diff --git a/.github/classifier.yml b/.github/classifier.yml index e0f0cec81..8acb00023 100644 --- a/.github/classifier.yml +++ b/.github/classifier.yml @@ -15,44 +15,131 @@ css-less-scss: [], debug-console: [], debug: { - assignees: [ isidorn ], + assignees: [ weinand ], + assignLabel: false + }, + diff-editor: : { + assignees: [], assignLabel: false }, - diff-editor: [], dropdown: [], - editor: { - assignees: [], - assignLabel: false - }, - editor-1000-limit: [], - editor-autoclosing: [], - editor-autoindent: [], - editor-brackets: [], - editor-clipboard: [], - editor-code-actions: [], - editor-code-lens: [], - editor-color-picker: [], - editor-colors: [], - editor-columnselect: [], - editor-commands: [], - editor-contrib: [], - editor-drag-and-drop: [], - editor-find: [], - editor-folding: [], - editor-hover: [], - editor-ime: [], - editor-input: [], - editor-ligatures: [], - editor-links: [], - editor-minimap: [], - editor-multicursor: [], - editor-parameter-hints: [], - editor-rendering: [], - editor-smooth: [], - editor-symbols: [], - editor-textbuffer: [], - editor-wrapping: [], - emmet: [ octref, ramya-rao-a ], + editor: : { + assignees: [], + assignLabel: false + }, + editor-1000-limit: : { + assignees: [], + assignLabel: false + }, + editor-autoclosing: : { + assignees: [], + assignLabel: false + }, + editor-autoindent: : { + assignees: [], + assignLabel: false + }, + editor-brackets: : { + assignees: [], + assignLabel: false + }, + editor-clipboard: : { + assignees: [], + assignLabel: false + }, + editor-code-actions: : { + assignees: [], + assignLabel: false + }, + editor-code-lens: : { + assignees: [], + assignLabel: false + }, + editor-color-picker: : { + assignees: [], + assignLabel: false + }, + editor-colors: : { + assignees: [], + assignLabel: false + }, + editor-columnselect: : { + assignees: [], + assignLabel: false + }, + editor-commands: : { + assignees: [], + assignLabel: false + }, + editor-contrib: : { + assignees: [], + assignLabel: false + }, + editor-drag-and-drop: : { + assignees: [], + assignLabel: false + }, + editor-find: : { + assignees: [], + assignLabel: false + }, + editor-folding: : { + assignees: [], + assignLabel: false + }, + editor-hover: : { + assignees: [], + assignLabel: false + }, + editor-ime: : { + assignees: [], + assignLabel: false + }, + editor-input: : { + assignees: [], + assignLabel: false + }, + editor-ligatures: : { + assignees: [], + assignLabel: false + }, + editor-links: : { + assignees: [], + assignLabel: false + }, + editor-minimap: : { + assignees: [], + assignLabel: false + }, + editor-multicursor: : { + assignees: [], + assignLabel: false + }, + editor-parameter-hints: : { + assignees: [], + assignLabel: false + }, + editor-rendering: : { + assignees: [], + assignLabel: false + }, + editor-smooth: : { + assignees: [], + assignLabel: false + }, + editor-symbols: : { + assignees: [], + assignLabel: false + }, + editor-textbuffer: : { + assignees: [], + assignLabel: false + }, + editor-wrapping: : { + assignees: [], + assignLabel: false + }, + emmet: [ octref ], error-list: [], explorer-custom: [], extension-host: [], @@ -81,14 +168,20 @@ hot-exit: [], html: [], install-update: [], - integrated-terminal: [ Tyriar ], + integrated-terminal: [], integration-test: [], intellisense-config: [], issue-reporter: [ RMacfarlane ], javascript: [ mjbvz ], json: [], - keyboard-layout: [], - keybindings: [], + keyboard-layout: : { + assignees: [], + assignLabel: false + }, + keybindings: : { + assignees: [], + assignLabel: false + }, keybindings-editor: [], lang-diagnostics: [], languages basic: [], diff --git a/.github/commands.yml b/.github/commands.yml index f20079caa..c92792325 100644 --- a/.github/commands.yml +++ b/.github/commands.yml @@ -105,7 +105,7 @@ { type: 'comment', name: 'a11ymas', - allowUsers: ['AccessibilityTestingTeam-TCS'], + allowUsers: ['AccessibilityTestingTeam-TCS', 'dixitsonali95', 'Mohini78', 'ChitrarupaSharma', 'mspatil110', 'umasarath52', 'v-umnaik'], action: 'updateLabels', addLabel: 'a11ymas' }, diff --git a/.gitignore b/.gitignore index 6a9804cd2..160c42ed7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .DS_Store +.cache npm-debug.log Thumbs.db node_modules/ @@ -14,6 +15,16 @@ out-editor-min/ out-monaco-editor-core/ out-vscode/ out-vscode-min/ +out-vscode-reh/ +out-vscode-reh-min/ +out-vscode-reh-pkg/ +out-vscode-reh-web/ +out-vscode-reh-web-min/ +out-vscode-reh-web-pkg/ +out-vscode-web/ +out-vscode-web-min/ +src/vs/server +resources/server build/node_modules coverage/ test_data/ diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 55cfea092..b4336e7d1 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -4,6 +4,7 @@ "recommendations": [ "ms-vscode.vscode-typescript-tslint-plugin", "dbaeumer.vscode-eslint", + "EditorConfig.EditorConfig", "msjsdiag.debugger-for-chrome" ] } diff --git a/.vscode/launch.json b/.vscode/launch.json index bd9e290ab..1d8207865 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -148,6 +148,9 @@ "request": "launch", "name": "Launch VS Code (Main Process)", "runtimeExecutable": "${workspaceFolder}/scripts/code.sh", + "windows": { + "runtimeExecutable": "${workspaceFolder}/scripts/code.bat", + }, "runtimeArgs": [ "--no-cached-data" ], @@ -276,4 +279,4 @@ ] }, ] -} +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index af8b38037..1a760bdda 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -56,5 +56,9 @@ "url": "./.vscode/cglicenses.schema.json" } ], - "git.ignoreLimitWarning": true + "git.ignoreLimitWarning": true, + "remote.extensionKind": { + "msjsdiag.debugger-for-chrome": "workspace" + }, + "files.insertFinalNewline": true } \ No newline at end of file diff --git a/.yarnrc b/.yarnrc index beab9f70b..c45abdbac 100644 --- a/.yarnrc +++ b/.yarnrc @@ -1,3 +1,3 @@ disturl "https://atom.io/download/electron" -target "3.1.8" +target "4.2.7" runtime "electron" diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index 65c8a42b8..000000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1 +0,0 @@ -This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. diff --git a/README.md b/README.md index 29b3270f1..035ba940a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Visual Studio Code - Open Source +# Visual Studio Code - Open Source ("Code - OSS") [![Build Status](https://dev.azure.com/vscode/VSCode/_apis/build/status/VS%20Code?branchName=master)](https://dev.azure.com/vscode/VSCode/_build/latest?definitionId=12) @@ -6,55 +6,63 @@ [![Bugs](https://img.shields.io/github/issues/Microsoft/vscode/bug.svg)](https://github.com/Microsoft/vscode/issues?utf8=✓&q=is%3Aissue+is%3Aopen+label%3Abug) [![Gitter](https://img.shields.io/badge/chat-on%20gitter-yellow.svg)](https://gitter.im/Microsoft/vscode) -[VS Code](https://code.visualstudio.com) is a type of tool that combines the simplicity of -a code editor with what developers need for their core edit-build-debug cycle. It provides comprehensive editing and debugging support, an extensibility model, and lightweight integration with existing tools. +## The Repository -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 daily at the very least. +This repository ("`Code - OSS`") is where we (Microsoft) develop the [Visual Studio Code](https://code.visualstudio.com) product. Not only do we work on code and issues here, we also publish our roadmap, monthly iteration plans, and our endgame plans. The source code here is available to everyone under the standard [MIT license](https://github.com/microsoft/vscode/blob/master/LICENSE.txt). + +## Visual Studio Code

- VS Code in action + VS Code in action

-The [`vscode`](https://github.com/microsoft/vscode) repository is where VS Code is developed and there are many ways in which you can participate in the project, for example: +[Visual Studio Code](https://code.visualstudio.com) is a distribution of the `Code - OSS` repository with Microsoft specific customizations released under a traditional [Microsoft product license](https://code.visualstudio.com/License/). + +[Visual Studio Code](https://code.visualstudio.com) combines the simplicity of a code editor with what developers need for their core edit-build-debug cycle. It provides comprehensive code editing, navigation, and understanding support along with lightweight debugging, a rich extensibility model, and lightweight integration with existing tools. + +Visual Studio Code is updated monthly with new features and bug fixes. You can download it for Windows, macOS, and Linux on [Visual Studio Code's website](https://code.visualstudio.com/Download). To get the latest releases every day, install the [Insiders build](https://code.visualstudio.com/insiders). + -* [Submit bugs and feature requests](https://github.com/microsoft/vscode/issues) and help us verify as they are checked in. -* Review [source code changes](https://github.com/microsoft/vscode/pulls). -* Review the [documentation](https://github.com/microsoft/vscode-docs) and make pull requests for anything from typos to new content. ## Contributing +There are many ways in which you can participate in the project, for example: + +* [Submit bugs and feature requests](https://github.com/microsoft/vscode/issues), and help us verify as they are checked in +* Review [source code changes](https://github.com/microsoft/vscode/pulls) +* Review the [documentation](https://github.com/microsoft/vscode-docs) and make pull requests for anything from typos to new content + If you are interested in fixing issues and contributing directly to the code base, please see the document [How to Contribute](https://github.com/Microsoft/vscode/wiki/How-to-Contribute), which covers the following: * [How to build and run from source](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#build-and-run) * [The development workflow, including debugging and running tests](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#debugging) -* [Coding Guidelines](https://github.com/Microsoft/vscode/wiki/Coding-Guidelines) +* [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 also see our [Code of Conduct](CODE_OF_CONDUCT.md). - ## Feedback -* Ask a question on [Stack Overflow](https://stackoverflow.com/questions/tagged/vscode). -* Request a new feature on [GitHub](CONTRIBUTING.md). -* Vote for [Popular Feature Requests](https://github.com/Microsoft/vscode/issues?q=is%3Aopen+is%3Aissue+label%3Afeature-request+sort%3Areactions-%2B1-desc). -* File a bug in [GitHub Issues](https://github.com/Microsoft/vscode/issues). -* [Tweet](https://twitter.com/code) us with any other feedback. +* Ask a question on [Stack Overflow](https://stackoverflow.com/questions/tagged/vscode) +* [Request a new feature](CONTRIBUTING.md) +* Up vote [popular feature requests](https://github.com/Microsoft/vscode/issues?q=is%3Aopen+is%3Aissue+label%3Afeature-request+sort%3Areactions-%2B1-desc) +* [File an issue](https://github.com/Microsoft/vscode/issues) +* Follow [@code](https://twitter.com/code) and let us know what you think! ## Related Projects -Many of the core components and extensions to Code live in their own repositories on GitHub. For example, the [node debug adapter](https://github.com/microsoft/vscode-node-debug) and the [mono debug adapter](https://github.com/microsoft/vscode-mono-debug) have their own repositories. - -For a complete list, please visit the [Related Projects](https://github.com/Microsoft/vscode/wiki/Related-Projects) page on our [wiki](https://github.com/Microsoft/vscode/wiki). +Many of the core components and extensions to Code live in their own repositories on GitHub. For example, the [node debug adapter](https://github.com/microsoft/vscode-node-debug) and the [mono debug adapter](https://github.com/microsoft/vscode-mono-debug) have their own repositories. For a complete list, please visit the [Related Projects](https://github.com/Microsoft/vscode/wiki/Related-Projects) page on our [wiki](https://github.com/Microsoft/vscode/wiki). ## Bundled Extensions -Code ships with a set of extensions. These extensions are located in the [extensions](extensions) folder. -These extensions include grammars and snippets for several languages. Extensions that provide rich language support (code completion, go to definition) for a language have the suffix 'language-features'. For example, the 'json' extension provides coloring for JSON and the 'json-language-features' provides rich language support for JSON. +Code includes a set of built-in extensions located in the [extensions](extensions) folder, including grammars and snippets for many languages. Extensions that provide rich language support (code completion, Go to Definition) for a language have the suffix `language-features`. For example, the `json` extension provides coloring for `JSON` and the `json-language-features` provides rich language support for `JSON`. + +## Code of Conduct + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. ## License Copyright (c) Microsoft Corporation. All rights reserved. -Licensed under the [MIT](LICENSE.txt) License. +Licensed under the [MIT](LICENSE.txt) license. diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt index 2df05cca0..64f72e53b 100644 --- a/ThirdPartyNotices.txt +++ b/ThirdPartyNotices.txt @@ -5,28 +5,28 @@ Do Not Translate or Localize This project incorporates components from the projects listed below. The original copyright notices and the licenses under which Microsoft received such components are set forth below. Microsoft reserves all rights not expressly granted herein, whether by implication, estoppel or otherwise. -1. atom/language-clojure version 0.22.6 (https://github.com/atom/language-clojure) +1. atom/language-clojure version 0.22.7 (https://github.com/atom/language-clojure) 2. atom/language-coffee-script version 0.49.3 (https://github.com/atom/language-coffee-script) -3. atom/language-java version 0.31.1 (https://github.com/atom/language-java) -4. atom/language-objective-c version 0.15.0 (https://github.com/atom/language-objective-c) -5. atom/language-sass version 0.61.4 (https://github.com/atom/language-sass) -6. atom/language-shellscript version 0.26.0 (https://github.com/atom/language-shellscript) -7. atom/language-xml version 0.35.2 (https://github.com/atom/language-xml) -8. Colorsublime-Themes version 0.1.0 (https://github.com/Colorsublime/Colorsublime-Themes) -9. daaain/Handlebars version 1.7.1 (https://github.com/daaain/Handlebars) -10. davidrios/pug-tmbundle (https://github.com/davidrios/pug-tmbundle) -11. definitelytyped (https://github.com/DefinitelyTyped/DefinitelyTyped) -12. demyte/language-cshtml version 0.3.0 (https://github.com/demyte/language-cshtml) -13. Document Object Model version 4.0.0 (https://www.w3.org/DOM/) -14. dotnet/csharp-tmLanguage version 0.1.0 (https://github.com/dotnet/csharp-tmLanguage) -15. expand-abbreviation version 0.5.8 (https://github.com/emmetio/expand-abbreviation) -16. fadeevab/make.tmbundle (https://github.com/fadeevab/make.tmbundle) -17. freebroccolo/atom-language-swift (https://github.com/freebroccolo/atom-language-swift) -18. HTML 5.1 W3C Working Draft version 08 October 2015 (http://www.w3.org/TR/2015/WD-html51-20151008/) -19. Ikuyadeu/vscode-R version 0.5.5 (https://github.com/Ikuyadeu/vscode-R) -20. Ionic documentation version 1.2.4 (https://github.com/ionic-team/ionic-site) -21. ionide/ionide-fsgrammar (https://github.com/ionide/ionide-fsgrammar) -22. jeff-hykin/cpp-textmate-grammar version 1.4.5 (https://github.com/jeff-hykin/cpp-textmate-grammar) +3. atom/language-java version 0.31.3 (https://github.com/atom/language-java) +4. atom/language-sass version 0.61.4 (https://github.com/atom/language-sass) +5. atom/language-shellscript version 0.26.0 (https://github.com/atom/language-shellscript) +6. atom/language-xml version 0.35.2 (https://github.com/atom/language-xml) +7. Colorsublime-Themes version 0.1.0 (https://github.com/Colorsublime/Colorsublime-Themes) +8. daaain/Handlebars version 1.8.0 (https://github.com/daaain/Handlebars) +9. davidrios/pug-tmbundle (https://github.com/davidrios/pug-tmbundle) +10. definitelytyped (https://github.com/DefinitelyTyped/DefinitelyTyped) +11. demyte/language-cshtml version 0.3.0 (https://github.com/demyte/language-cshtml) +12. Document Object Model version 4.0.0 (https://www.w3.org/DOM/) +13. dotnet/csharp-tmLanguage version 0.1.0 (https://github.com/dotnet/csharp-tmLanguage) +14. expand-abbreviation version 0.5.8 (https://github.com/emmetio/expand-abbreviation) +15. fadeevab/make.tmbundle (https://github.com/fadeevab/make.tmbundle) +16. freebroccolo/atom-language-swift (https://github.com/freebroccolo/atom-language-swift) +17. HTML 5.1 W3C Working Draft version 08 October 2015 (http://www.w3.org/TR/2015/WD-html51-20151008/) +18. Ikuyadeu/vscode-R version 0.5.5 (https://github.com/Ikuyadeu/vscode-R) +19. Ionic documentation version 1.2.4 (https://github.com/ionic-team/ionic-site) +20. ionide/ionide-fsgrammar (https://github.com/ionide/ionide-fsgrammar) +21. jeff-hykin/cpp-textmate-grammar version 1.12.11 (https://github.com/jeff-hykin/cpp-textmate-grammar) +22. jeff-hykin/cpp-textmate-grammar version 1.12.18 (https://github.com/jeff-hykin/cpp-textmate-grammar) 23. js-beautify version 1.6.8 (https://github.com/beautify-web/js-beautify) 24. Jxck/assert version 1.0.0 (https://github.com/Jxck/assert) 25. language-docker (https://github.com/moby/moby) @@ -35,14 +35,14 @@ This project incorporates components from the projects listed below. The origina 28. language-php version 0.44.1 (https://github.com/atom/language-php) 29. language-rust version 0.4.12 (https://github.com/zargony/atom-language-rust) 30. MagicStack/MagicPython version 1.1.1 (https://github.com/MagicStack/MagicPython) -31. marked version 0.5.0 (https://github.com/markedjs/marked) +31. marked version 0.6.2 (https://github.com/markedjs/marked) 32. mdn-data version 1.1.12 (https://github.com/mdn/data) 33. Microsoft/TypeScript-TmLanguage version 0.0.1 (https://github.com/Microsoft/TypeScript-TmLanguage) 34. Microsoft/vscode-JSON.tmLanguage (https://github.com/Microsoft/vscode-JSON.tmLanguage) -35. Microsoft/vscode-mssql version 1.4.0 (https://github.com/Microsoft/vscode-mssql) +35. Microsoft/vscode-mssql version 1.6.0 (https://github.com/Microsoft/vscode-mssql) 36. mmims/language-batchfile version 0.7.5 (https://github.com/mmims/language-batchfile) 37. octicons version 8.3.0 (https://github.com/primer/octicons) -38. octref/language-css (https://github.com/octref/language-css) +38. octref/language-css version 0.42.11 (https://github.com/octref/language-css) 39. PowerShell/EditorSyntax (https://github.com/powershell/editorsyntax) 40. promise-polyfill version 8.0.0 (https://github.com/taylorhakes/promise-polyfill) 41. seti-ui version 0.1.0 (https://github.com/jesseweed/seti-ui) @@ -64,7 +64,7 @@ This project incorporates components from the projects listed below. The origina 57. TypeScript-TmLanguage version 1.0.0 (https://github.com/Microsoft/TypeScript-TmLanguage) 58. Unicode version 12.0.0 (http://www.unicode.org/) 59. vscode-logfile-highlighter version 2.4.1 (https://github.com/emilast/vscode-logfile-highlighter) -60. vscode-octicons-font version 1.0.0 (https://github.com/Microsoft/vscode-octicons-font) +60. vscode-octicons-font version 1.3.1 (https://github.com/Microsoft/vscode-octicons-font) 61. vscode-swift version 0.0.1 (https://github.com/owensd/vscode-swift) 62. Web Background Synchronization (https://github.com/WICG/BackgroundSync) @@ -213,43 +213,6 @@ suitability for any purpose. ========================================= END OF atom/language-java NOTICES AND INFORMATION -%% atom/language-objective-c NOTICES AND INFORMATION BEGIN HERE -========================================= -The MIT License (MIT) - -Copyright (c) 2014 GitHub Inc. - -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. - - -This package was derived from a TextMate bundle located at -https://github.com/textmate/objective-c.tmbundle and distributed under the following -license, located in `README.mdown`: - -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 atom/language-objective-c NOTICES AND INFORMATION - %% atom/language-sass NOTICES AND INFORMATION BEGIN HERE ========================================= The MIT License (MIT) diff --git a/build/.cachesalt b/build/.cachesalt new file mode 100644 index 000000000..105ce86ae --- /dev/null +++ b/build/.cachesalt @@ -0,0 +1 @@ +2019-07-11T05:47:05.444Z diff --git a/build/.nativeignore b/build/.nativeignore new file mode 100644 index 000000000..a4823bf71 --- /dev/null +++ b/build/.nativeignore @@ -0,0 +1,107 @@ +# cleanup rules for native node modules, .gitignore style + +nan/** +*/node_modules/nan/** + +fsevents/binding.gyp +fsevents/fsevents.cc +fsevents/build/** +fsevents/src/** +fsevents/test/** +!fsevents/**/*.node + +vscode-sqlite3/binding.gyp +vscode-sqlite3/benchmark/** +vscode-sqlite3/cloudformation/** +vscode-sqlite3/deps/** +vscode-sqlite3/test/** +vscode-sqlite3/build/** +vscode-sqlite3/src/** +!vscode-sqlite3/build/Release/*.node + +oniguruma/binding.gyp +oniguruma/build/** +oniguruma/src/** +oniguruma/deps/** +!oniguruma/build/Release/*.node +!oniguruma/src/*.js + +windows-mutex/binding.gyp +windows-mutex/build/** +windows-mutex/src/** +!windows-mutex/**/*.node + +native-keymap/binding.gyp +native-keymap/build/** +native-keymap/src/** +native-keymap/deps/** +!native-keymap/build/Release/*.node + +native-is-elevated/binding.gyp +native-is-elevated/build/** +native-is-elevated/src/** +native-is-elevated/deps/** +!native-is-elevated/build/Release/*.node + +native-watchdog/binding.gyp +native-watchdog/build/** +native-watchdog/src/** +!native-watchdog/build/Release/*.node + +spdlog/binding.gyp +spdlog/build/** +spdlog/deps/** +spdlog/src/** +spdlog/test/** +!spdlog/build/Release/*.node + +jschardet/dist/** + +windows-foreground-love/binding.gyp +windows-foreground-love/build/** +windows-foreground-love/src/** +!windows-foreground-love/**/*.node + +windows-process-tree/binding.gyp +windows-process-tree/build/** +windows-process-tree/src/** +!windows-process-tree/**/*.node + +keytar/binding.gyp +keytar/build/** +keytar/src/** +keytar/script/** +keytar/node_modules/** +!keytar/**/*.node + +node-pty/binding.gyp +node-pty/build/** +node-pty/src/** +node-pty/tools/** +node-pty/deps/** +!node-pty/build/Release/*.exe +!node-pty/build/Release/*.dll +!node-pty/build/Release/*.node + +nsfw/binding.gyp +nsfw/build/** +nsfw/src/** +nsfw/openpa/** +nsfw/includes/** +!nsfw/build/Release/*.node +!nsfw/**/*.a + +vsda/build/** +vsda/ci/** +vsda/src/** +vsda/.gitignore +vsda/binding.gyp +vsda/README.md +vsda/targets +!vsda/build/Release/vsda.node + +vscode-windows-ca-certs/**/* +!vscode-windows-ca-certs/package.json +!vscode-windows-ca-certs/**/*.node + +node-addon-api/**/* diff --git a/build/azure-pipelines/common/extract-telemetry.sh b/build/azure-pipelines/common/extract-telemetry.sh new file mode 100755 index 000000000..84bbd9c53 --- /dev/null +++ b/build/azure-pipelines/common/extract-telemetry.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -e + +cd $BUILD_STAGINGDIRECTORY +mkdir extraction +cd extraction +git clone --depth 1 https://github.com/Microsoft/vscode-extension-telemetry.git +git clone --depth 1 https://github.com/Microsoft/vscode-chrome-debug-core.git +git clone --depth 1 https://github.com/Microsoft/vscode-node-debug2.git +git clone --depth 1 https://github.com/Microsoft/vscode-node-debug.git +git clone --depth 1 https://github.com/Microsoft/vscode-html-languageservice.git +git clone --depth 1 https://github.com/Microsoft/vscode-json-languageservice.git +$BUILD_SOURCESDIRECTORY/build/node_modules/.bin/vscode-telemetry-extractor --sourceDir $BUILD_SOURCESDIRECTORY --excludedDir $BUILD_SOURCESDIRECTORY/extensions --outputDir . --applyEndpoints +$BUILD_SOURCESDIRECTORY/build/node_modules/.bin/vscode-telemetry-extractor --config $BUILD_SOURCESDIRECTORY/build/azure-pipelines/common/telemetry-config.json -o . +mkdir -p $BUILD_SOURCESDIRECTORY/.build/telemetry +mv declarations-resolved.json $BUILD_SOURCESDIRECTORY/.build/telemetry/telemetry-core.json +mv config-resolved.json $BUILD_SOURCESDIRECTORY/.build/telemetry/telemetry-extensions.json +cd .. +rm -rf extraction \ No newline at end of file diff --git a/build/azure-pipelines/common/installDistro.ts b/build/azure-pipelines/common/installDistro.ts deleted file mode 100644 index 3cb97afd2..000000000 --- a/build/azure-pipelines/common/installDistro.ts +++ /dev/null @@ -1,18 +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 cp from 'child_process'; - -function yarnInstall(packageName: string): void { - cp.execSync(`yarn add --no-lockfile ${packageName}`); -} - -const product = require('../../../product.json'); -const dependencies = product.dependencies || {} as { [name: string]: string; }; - -Object.keys(dependencies).forEach(name => { - const url = dependencies[name]; - yarnInstall(url); -}); \ No newline at end of file diff --git a/build/azure-pipelines/common/publish.ts b/build/azure-pipelines/common/publish.ts index 724939da3..62113c8f3 100644 --- a/build/azure-pipelines/common/publish.ts +++ b/build/azure-pipelines/common/publish.ts @@ -151,13 +151,6 @@ async function publish(commit: string, quality: string, platform: string, type: const queuedBy = process.env['BUILD_QUEUEDBY']!; const sourceBranch = process.env['BUILD_SOURCEBRANCH']!; - const isReleased = ( - // Insiders: nightly build from master - (quality === 'insider' && /^master$|^refs\/heads\/master$/.test(sourceBranch) && /Project Collection Service Accounts|Microsoft.VisualStudio.Services.TFS/.test(queuedBy)) || - - // Exploration: any build from electron-4.0.x branch - (quality === 'exploration' && /^electron-4.0.x$|^refs\/heads\/electron-4.0.x$/.test(sourceBranch)) - ); console.log('Publishing...'); console.log('Quality:', quality); @@ -167,7 +160,6 @@ async function publish(commit: string, quality: string, platform: string, type: console.log('Version:', version); console.log('Commit:', commit); console.log('Is Update:', isUpdate); - 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))); @@ -226,7 +218,7 @@ async function publish(commit: string, quality: string, platform: string, type: id: commit, timestamp: (new Date()).getTime(), version, - isReleased: config.frozen ? false : isReleased, + isReleased: false, sourceBranch, queuedBy, assets: [] as Array, @@ -245,11 +237,6 @@ async function publish(commit: string, quality: string, platform: string, type: } function main(): void { - if (process.env['VSCODE_BUILD_SKIP_PUBLISH']) { - console.warn('Skipping publish due to VSCODE_BUILD_SKIP_PUBLISH'); - return; - } - const commit = process.env['BUILD_SOURCEVERSION']; if (!commit) { diff --git a/build/azure-pipelines/common/release.ts b/build/azure-pipelines/common/release.ts new file mode 100644 index 000000000..1220bd62e --- /dev/null +++ b/build/azure-pipelines/common/release.ts @@ -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. + *--------------------------------------------------------------------------------------------*/ + +'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); + }); + }); +} + +function doRelease(commit: string, quality: string): Promise { + const client = new DocumentClient(process.env['AZURE_DOCUMENTDB_ENDPOINT']!, { masterKey: process.env['AZURE_DOCUMENTDB_MASTERKEY'] }); + const collection = 'dbs/builds/colls/' + quality; + const query = { + query: 'SELECT TOP 1 * FROM c WHERE c.id = @id', + parameters: [{ name: '@id', value: commit }] + }; + + let updateTries = 0; + + function update(): Promise { + updateTries++; + + return new Promise((c, e) => { + client.queryDocuments(collection, query).toArray((err, results) => { + if (err) { return e(err); } + if (results.length !== 1) { return e(new Error('No documents')); } + + const release = results[0]; + release.isReleased = true; + + client.replaceDocument(release._self, release, err => { + if (err && err.code === 409 && updateTries < 5) { return c(update()); } + if (err) { return e(err); } + + console.log('Build successfully updated.'); + c(); + }); + }); + }); + } + + return update(); +} + +async function release(commit: string, quality: string): Promise { + const config = await getConfig(quality); + + console.log('Quality config:', config); + + if (config.frozen) { + console.log(`Skipping release because quality ${quality} is frozen.`); + return; + } + + await doRelease(commit, quality); +} + +function env(name: string): string { + const result = process.env[name]; + + if (!result) { + throw new Error(`Skipping release due to missing env: ${name}`); + } + + return result; +} + +async function main(): Promise { + const commit = env('BUILD_SOURCEVERSION'); + const quality = env('VSCODE_QUALITY'); + + await release(commit, quality); +} + +main().catch(err => { + console.error(err); + process.exit(1); +}); diff --git a/build/azure-pipelines/common/symbols.ts b/build/azure-pipelines/common/symbols.ts index 1a5125295..153be4f25 100644 --- a/build/azure-pipelines/common/symbols.ts +++ b/build/azure-pipelines/common/symbols.ts @@ -36,7 +36,6 @@ export interface IVersionAccessor extends IApplicationAccessor { enum Platform { WIN_32 = 'win32-ia32', WIN_64 = 'win32-x64', - LINUX_32 = 'linux-ia32', LINUX_64 = 'linux-x64', MAC_OS = 'darwin-x64' } @@ -147,6 +146,10 @@ async function ensureVersionAndSymbols(options: IOptions) { // Check version does not exist console.log(`HockeyApp: checking for existing version ${options.versions.code} (${options.platform})`); const versions = await getVersions({ accessToken: options.access.hockeyAppToken, appId: options.access.hockeyAppId }); + if (!Array.isArray(versions.app_versions)) { + throw new Error(`Unexpected response: ${JSON.stringify(versions)}`); + } + if (versions.app_versions.some(v => v.version === options.versions.code)) { console.log(`HockeyApp: Returning without uploading symbols because version ${options.versions.code} (${options.platform}) was already found`); return; @@ -185,13 +188,17 @@ const hockeyAppToken = process.argv[3]; const is64 = process.argv[4] === 'x64'; const hockeyAppId = process.argv[5]; +if (process.argv.length !== 6) { + throw new Error(`HockeyApp: Unexpected number of arguments. Got ${process.argv}`); +} + let platform: Platform; if (process.platform === 'darwin') { platform = Platform.MAC_OS; } else if (process.platform === 'win32') { platform = is64 ? Platform.WIN_64 : Platform.WIN_32; } else { - platform = is64 ? Platform.LINUX_64 : Platform.LINUX_32; + platform = Platform.LINUX_64; } // Create version and upload symbols in HockeyApp @@ -212,7 +219,9 @@ if (repository && codeVersion && electronVersion && (product.quality === 'stable }).then(() => { console.log('HockeyApp: done'); }).catch(error => { - console.error(`HockeyApp: error (${error})`); + console.error(`HockeyApp: error ${error} (AppID: ${hockeyAppId})`); + + return process.exit(1); }); } else { console.log(`HockeyApp: skipping due to unexpected context (repository: ${repository}, codeVersion: ${codeVersion}, electronVersion: ${electronVersion}, quality: ${product.quality})`); diff --git a/build/azure-pipelines/common/sync-mooncake.ts b/build/azure-pipelines/common/sync-mooncake.ts index af0db5306..1eac8f34e 100644 --- a/build/azure-pipelines/common/sync-mooncake.ts +++ b/build/azure-pipelines/common/sync-mooncake.ts @@ -153,11 +153,6 @@ async function sync(commit: string, quality: string): Promise { } function main(): void { - if (process.env['VSCODE_BUILD_SKIP_PUBLISH']) { - error('Skipping publish due to VSCODE_BUILD_SKIP_PUBLISH'); - return; - } - const commit = process.env['BUILD_SOURCEVERSION']; if (!commit) { diff --git a/build/azure-pipelines/common/telemetry-config.json b/build/azure-pipelines/common/telemetry-config.json new file mode 100644 index 000000000..fcba1e042 --- /dev/null +++ b/build/azure-pipelines/common/telemetry-config.json @@ -0,0 +1,72 @@ +[ + { + "eventPrefix": "typescript-language-features/", + "sourceDirs": [ + "../../s/extensions/typescript-language-features" + ], + "excludedDirs": [], + "applyEndpoints": true + }, + { + "eventPrefix": "git/", + "sourceDirs": [ + "../../s/extensions/git" + ], + "excludedDirs": [], + "applyEndpoints": true + }, + { + "eventPrefix": "extension-telemetry/", + "sourceDirs": [ + "vscode-extension-telemetry" + ], + "excludedDirs": [], + "applyEndpoints": true + }, + { + "eventPrefix": "vscode-markdown/", + "sourceDirs": [ + "../../s/extensions/markdown-language-features" + ], + "excludedDirs": [], + "applyEndpoints": true + }, + { + "eventPrefix": "html-language-features/", + "sourceDirs": [ + "../../s/extensions/html-language-features", + "vscode-html-languageservice" + ], + "excludedDirs": [], + "applyEndpoints": true + }, + { + "eventPrefix": "json-language-features/", + "sourceDirs": [ + "../../s/extensions/json-language-features", + "vscode-json-languageservice" + ], + "excludedDirs": [], + "applyEndpoints": true + }, + { + "eventPrefix": "ms-vscode.node2/", + "sourceDirs": [ + "vscode-chrome-debug-core", + "vscode-node-debug2" + ], + "excludedDirs": [], + "applyEndpoints": true, + "patchDebugEvents": true + }, + { + "eventPrefix": "ms-vscode.node/", + "sourceDirs": [ + "vscode-chrome-debug-core", + "vscode-node-debug" + ], + "excludedDirs": [], + "applyEndpoints": true, + "patchDebugEvents": true + } +] \ No newline at end of file diff --git a/build/azure-pipelines/darwin/build.sh b/build/azure-pipelines/darwin/build.sh deleted file mode 100755 index af558b8c1..000000000 --- a/build/azure-pipelines/darwin/build.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash -set -e -yarn gulp vscode-darwin-min -yarn gulp upload-vscode-sourcemaps \ No newline at end of file diff --git a/build/azure-pipelines/darwin/continuous-build-darwin.yml b/build/azure-pipelines/darwin/continuous-build-darwin.yml index 776c1172b..018719423 100644 --- a/build/azure-pipelines/darwin/continuous-build-darwin.yml +++ b/build/azure-pipelines/darwin/continuous-build-darwin.yml @@ -4,19 +4,19 @@ steps: versionSpec: "10.15.1" - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 inputs: - keyfile: '**/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' + keyfile: '.yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' targetfolder: '**/node_modules, !**/node_modules/**/node_modules' vstsFeed: '$(ArtifactFeed)' - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 inputs: versionSpec: "1.10.1" - script: | - yarn + yarn --frozen-lockfile displayName: Install Dependencies - condition: ne(variables['CacheRestored'], 'true') + condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) - task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 inputs: - keyfile: '**/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' + keyfile: '.yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' targetfolder: '**/node_modules, !**/node_modules/**/node_modules' vstsFeed: '$(ArtifactFeed)' condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) diff --git a/build/azure-pipelines/darwin/product-build-darwin.yml b/build/azure-pipelines/darwin/product-build-darwin.yml index f5d5ef626..b712e0728 100644 --- a/build/azure-pipelines/darwin/product-build-darwin.yml +++ b/build/azure-pipelines/darwin/product-build-darwin.yml @@ -1,4 +1,23 @@ steps: +- script: | + mkdir -p .build + echo -n $BUILD_SOURCEVERSION > .build/commit + displayName: Prepare cache flag + +- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 + inputs: + keyfile: 'build/.cachesalt, .build/commit' + targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min' + vstsFeed: 'npm-vscode' + platformIndependent: true + alias: 'Compilation' + +- script: | + set -e + exit 1 + displayName: Check RestoreCache + condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) + - task: NodeTool@0 inputs: versionSpec: "10.15.1" @@ -7,36 +26,70 @@ steps: inputs: versionSpec: "1.10.1" +- task: AzureKeyVault@1 + displayName: 'Azure Key Vault: Get Secrets' + inputs: + azureSubscription: 'vscode-builds-subscription' + KeyVaultName: vscode + - script: | set -e cat << EOF > ~/.netrc - machine monacotools.visualstudio.com - password $(VSO_PAT) machine github.com login vscode - password $(VSCODE_MIXIN_PASSWORD) + password $(github-distro-mixin-password) EOF git config user.email "vscode@microsoft.com" git config user.name "VSCode" + displayName: Prepare tooling + +- script: | + set -e git remote add distro "https://github.com/$(VSCODE_MIXIN_REPO).git" git fetch distro git merge $(node -p "require('./package.json').distro") + displayName: Merge distro - yarn - yarn gulp mixin - yarn gulp hygiene - yarn monaco-compile-check - node build/azure-pipelines/common/installDistro.js - node build/lib/builtInExtensions.js - displayName: Prepare build +- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 + inputs: + keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' + targetfolder: '**/node_modules, !**/node_modules/**/node_modules' + vstsFeed: 'npm-vscode' + +- script: | + set -e + CHILD_CONCURRENCY=1 yarn --frozen-lockfile + displayName: Install dependencies + condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) + +- task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 + inputs: + keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' + targetfolder: '**/node_modules, !**/node_modules/**/node_modules' + vstsFeed: 'npm-vscode' + condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) + +- script: | + set -e + yarn postinstall + displayName: Run postinstall scripts + condition: and(succeeded(), eq(variables['CacheRestored'], 'true')) + +- script: | + set -e + node build/azure-pipelines/mixin + displayName: Mix in quality - script: | set -e - VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" \ - AZURE_STORAGE_ACCESS_KEY="$(AZURE_STORAGE_ACCESS_KEY)" \ - ./build/azure-pipelines/darwin/build.sh + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn gulp vscode-darwin-min-ci + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn gulp vscode-reh-darwin-min-ci + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn gulp vscode-reh-web-darwin-min-ci displayName: Build - script: | @@ -45,11 +98,13 @@ steps: # APP_NAME="`ls $(agent.builddirectory)/VSCode-darwin | head -n 1`" # yarn smoketest -- --build "$(agent.builddirectory)/VSCode-darwin/$APP_NAME" displayName: Run unit tests + condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - script: | set -e ./scripts/test-integration.sh --build --tfs "Integration Tests" displayName: Run integration tests + condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - script: | set -e @@ -77,11 +132,11 @@ steps: - script: | set -e - VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" \ - AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \ - AZURE_STORAGE_ACCESS_KEY="$(AZURE_STORAGE_ACCESS_KEY)" \ - AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \ - VSCODE_HOCKEYAPP_TOKEN="$(VSCODE_HOCKEYAPP_TOKEN)" \ + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ + AZURE_STORAGE_ACCESS_KEY="$(ticino-storage-key)" \ + AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \ + VSCODE_HOCKEYAPP_TOKEN="$(vscode-hockeyapp-token)" \ ./build/azure-pipelines/darwin/publish.sh displayName: Publish diff --git a/build/azure-pipelines/darwin/publish.sh b/build/azure-pipelines/darwin/publish.sh index 96d5967ea..fa453bcaf 100755 --- a/build/azure-pipelines/darwin/publish.sh +++ b/build/azure-pipelines/darwin/publish.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +set -e # remove pkg from archive zip -d ../VSCode-darwin.zip "*.pkg" @@ -15,8 +16,21 @@ node build/azure-pipelines/common/publish.js \ true \ ../VSCode-darwin.zip +# package Remote Extension Host +pushd .. && mv vscode-reh-darwin vscode-server-darwin && zip -Xry vscode-server-darwin.zip vscode-server-darwin && popd + +# publish Remote Extension Host +node build/azure-pipelines/common/publish.js \ + "$VSCODE_QUALITY" \ + server-darwin \ + archive-unsigned \ + "vscode-server-darwin.zip" \ + $VERSION \ + true \ + ../vscode-server-darwin.zip + # publish hockeyapp symbols -node build/azure-pipelines/common/symbols.js "$VSCODE_MIXIN_PASSWORD" "$VSCODE_HOCKEYAPP_TOKEN" "$VSCODE_ARCH" "$VSCODE_HOCKEYAPP_ID_MACOS" +node build/azure-pipelines/common/symbols.js "$VSCODE_MIXIN_PASSWORD" "$VSCODE_HOCKEYAPP_TOKEN" x64 "$VSCODE_HOCKEYAPP_ID_MACOS" # upload configuration yarn gulp upload-vscode-configuration diff --git a/build/azure-pipelines/distro-build.yml b/build/azure-pipelines/distro-build.yml index dc55bce80..62ee67ad1 100644 --- a/build/azure-pipelines/distro-build.yml +++ b/build/azure-pipelines/distro-build.yml @@ -10,13 +10,19 @@ steps: inputs: versionSpec: "10.15.1" +- task: AzureKeyVault@1 + displayName: 'Azure Key Vault: Get Secrets' + inputs: + azureSubscription: 'vscode-builds-subscription' + KeyVaultName: vscode + - script: | set -e cat << EOF > ~/.netrc machine github.com login vscode - password $(VSCODE_MIXIN_PASSWORD) + password $(github-distro-mixin-password) EOF git config user.email "vscode@microsoft.com" @@ -24,7 +30,13 @@ steps: git remote add distro "https://github.com/$VSCODE_MIXIN_REPO.git" git fetch distro - git push distro origin/master:refs/heads/master + + # Push master branch into oss/master + git push distro origin/master:refs/heads/oss/master + + # Push every release branch into oss/release + git for-each-ref --format="%(refname:short)" refs/remotes/origin/release/* | sed 's/^origin\/\(.*\)$/\0:refs\/heads\/oss\/\1/' | xargs git push distro + git merge $(node -p "require('./package.json').distro") - displayName: Sync & Merge Distro \ No newline at end of file + displayName: Sync & Merge Distro diff --git a/build/azure-pipelines/linux/build.sh b/build/azure-pipelines/linux/build.sh deleted file mode 100755 index bd251ebc7..000000000 --- a/build/azure-pipelines/linux/build.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash -set -e -yarn gulp "vscode-linux-$VSCODE_ARCH-min" \ No newline at end of file diff --git a/build/azure-pipelines/linux/continuous-build-linux.yml b/build/azure-pipelines/linux/continuous-build-linux.yml index ee47a8d43..8b0aaca2a 100644 --- a/build/azure-pipelines/linux/continuous-build-linux.yml +++ b/build/azure-pipelines/linux/continuous-build-linux.yml @@ -12,19 +12,19 @@ steps: versionSpec: "10.15.1" - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 inputs: - keyfile: '**/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' + keyfile: '.yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' targetfolder: '**/node_modules, !**/node_modules/**/node_modules' vstsFeed: '$(ArtifactFeed)' - task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 inputs: versionSpec: "1.10.1" - script: | - yarn + yarn --frozen-lockfile displayName: Install Dependencies - condition: ne(variables['CacheRestored'], 'true') + condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) - task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 inputs: - keyfile: '**/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' + keyfile: '.yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' targetfolder: '**/node_modules, !**/node_modules/**/node_modules' vstsFeed: '$(ArtifactFeed)' condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) @@ -46,9 +46,12 @@ steps: - script: | DISPLAY=:10 ./scripts/test.sh --tfs "Unit Tests" displayName: Run Unit Tests +- script: | + DISPLAY=:10 ./scripts/test-integration.sh --tfs "Integration Tests" + displayName: Run Integration Tests - task: PublishTestResults@2 displayName: Publish Tests Results inputs: testResultsFiles: '*-results.xml' searchFolder: '$(Build.ArtifactStagingDirectory)/test-results' - condition: succeededOrFailed() \ No newline at end of file + condition: succeededOrFailed() diff --git a/build/azure-pipelines/linux/multiarch/alpine/build.sh b/build/azure-pipelines/linux/multiarch/alpine/build.sh new file mode 100755 index 000000000..4f01bc9a7 --- /dev/null +++ b/build/azure-pipelines/linux/multiarch/alpine/build.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -e +echo 'noop' \ No newline at end of file diff --git a/build/azure-pipelines/linux/multiarch/alpine/prebuild.sh b/build/azure-pipelines/linux/multiarch/alpine/prebuild.sh new file mode 100755 index 000000000..4f01bc9a7 --- /dev/null +++ b/build/azure-pipelines/linux/multiarch/alpine/prebuild.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -e +echo 'noop' \ No newline at end of file diff --git a/build/azure-pipelines/linux/multiarch/alpine/publish.sh b/build/azure-pipelines/linux/multiarch/alpine/publish.sh new file mode 100755 index 000000000..4f01bc9a7 --- /dev/null +++ b/build/azure-pipelines/linux/multiarch/alpine/publish.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -e +echo 'noop' \ No newline at end of file diff --git a/build/azure-pipelines/linux/multiarch/armhf/build.sh b/build/azure-pipelines/linux/multiarch/armhf/build.sh new file mode 100755 index 000000000..4f01bc9a7 --- /dev/null +++ b/build/azure-pipelines/linux/multiarch/armhf/build.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -e +echo 'noop' \ No newline at end of file diff --git a/build/azure-pipelines/linux/multiarch/armhf/prebuild.sh b/build/azure-pipelines/linux/multiarch/armhf/prebuild.sh new file mode 100755 index 000000000..4f01bc9a7 --- /dev/null +++ b/build/azure-pipelines/linux/multiarch/armhf/prebuild.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -e +echo 'noop' \ No newline at end of file diff --git a/build/azure-pipelines/linux/multiarch/armhf/publish.sh b/build/azure-pipelines/linux/multiarch/armhf/publish.sh new file mode 100755 index 000000000..4f01bc9a7 --- /dev/null +++ b/build/azure-pipelines/linux/multiarch/armhf/publish.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +set -e +echo 'noop' \ No newline at end of file diff --git a/build/azure-pipelines/linux/product-build-linux-multiarch.yml b/build/azure-pipelines/linux/product-build-linux-multiarch.yml new file mode 100644 index 000000000..dff5ae2ce --- /dev/null +++ b/build/azure-pipelines/linux/product-build-linux-multiarch.yml @@ -0,0 +1,115 @@ +steps: +- script: | + mkdir -p .build + echo -n $BUILD_SOURCEVERSION > .build/commit + displayName: Prepare cache flag + +- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 + inputs: + keyfile: 'build/.cachesalt, .build/commit' + targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min' + vstsFeed: 'npm-vscode' + platformIndependent: true + alias: 'Compilation' + +- script: | + set -e + exit 1 + displayName: Check RestoreCache + condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) + +- task: NodeTool@0 + inputs: + versionSpec: "10.15.1" + +- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 + inputs: + versionSpec: "1.10.1" + +- task: AzureKeyVault@1 + displayName: 'Azure Key Vault: Get Secrets' + inputs: + azureSubscription: 'vscode-builds-subscription' + KeyVaultName: vscode + +- task: Docker@1 + displayName: 'Pull image' + inputs: + azureSubscriptionEndpoint: 'vscode-builds-subscription' + azureContainerRegistry: vscodehub.azurecr.io + command: 'Run an image' + imageName: 'vscode-linux-build-agent:$(VSCODE_ARCH)' + containerCommand: uname + +- script: | + set -e + + cat << EOF > ~/.netrc + machine github.com + login vscode + password $(github-distro-mixin-password) + EOF + + git config user.email "vscode@microsoft.com" + git config user.name "VSCode" + displayName: Prepare tooling + +- script: | + set -e + git remote add distro "https://github.com/$(VSCODE_MIXIN_REPO).git" + git fetch distro + git merge $(node -p "require('./package.json').distro") + displayName: Merge distro + +- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 + inputs: + keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' + targetfolder: '**/node_modules, !**/node_modules/**/node_modules' + vstsFeed: 'npm-vscode' + +- script: | + set -e + CHILD_CONCURRENCY=1 yarn --frozen-lockfile + displayName: Install dependencies + condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) + +- task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 + inputs: + keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' + targetfolder: '**/node_modules, !**/node_modules/**/node_modules' + vstsFeed: 'npm-vscode' + condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) + +- script: | + set -e + yarn postinstall + displayName: Run postinstall scripts + condition: and(succeeded(), eq(variables['CacheRestored'], 'true')) + +- script: | + set -e + node build/azure-pipelines/mixin + displayName: Mix in quality + +- script: | + set -e + CHILD_CONCURRENCY=1 ./build/azure-pipelines/linux/multiarch/$(VSCODE_ARCH)/prebuild.sh + displayName: Prebuild + +- script: | + set -e + ./build/azure-pipelines/linux/multiarch/$(VSCODE_ARCH)/build.sh + displayName: Build + +- script: | + set -e + AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ + AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \ + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + VSCODE_HOCKEYAPP_TOKEN="$(vscode-hockeyapp-token)" \ + ./build/azure-pipelines/linux/multiarch/$(VSCODE_ARCH)/publish.sh + displayName: Publish + +- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 + displayName: 'Component Detection' + continueOnError: true \ No newline at end of file diff --git a/build/azure-pipelines/linux/product-build-linux.yml b/build/azure-pipelines/linux/product-build-linux.yml index 342d72e49..dee07a95d 100644 --- a/build/azure-pipelines/linux/product-build-linux.yml +++ b/build/azure-pipelines/linux/product-build-linux.yml @@ -1,4 +1,23 @@ steps: +- script: | + mkdir -p .build + echo -n $BUILD_SOURCEVERSION > .build/commit + displayName: Prepare cache flag + +- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 + inputs: + keyfile: 'build/.cachesalt, .build/commit' + targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min' + vstsFeed: 'npm-vscode' + platformIndependent: true + alias: 'Compilation' + +- script: | + set -e + exit 1 + displayName: Check RestoreCache + condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) + - task: NodeTool@0 inputs: versionSpec: "10.15.1" @@ -7,67 +26,105 @@ steps: inputs: versionSpec: "1.10.1" +- task: AzureKeyVault@1 + displayName: 'Azure Key Vault: Get Secrets' + inputs: + azureSubscription: 'vscode-builds-subscription' + KeyVaultName: vscode + - script: | set -e - export npm_config_arch="$(VSCODE_ARCH)" - if [[ "$(VSCODE_ARCH)" == "ia32" ]]; then - export PKG_CONFIG_PATH="/usr/lib/i386-linux-gnu/pkgconfig" - fi - cat << EOF > ~/.netrc - machine monacotools.visualstudio.com - password $(VSO_PAT) machine github.com login vscode - password $(VSCODE_MIXIN_PASSWORD) + password $(github-distro-mixin-password) EOF git config user.email "vscode@microsoft.com" git config user.name "VSCode" + displayName: Prepare tooling + +- script: | + set -e git remote add distro "https://github.com/$(VSCODE_MIXIN_REPO).git" git fetch distro git merge $(node -p "require('./package.json').distro") + displayName: Merge distro - CHILD_CONCURRENCY=1 yarn - yarn gulp mixin - yarn gulp hygiene - yarn monaco-compile-check - node build/azure-pipelines/common/installDistro.js - node build/lib/builtInExtensions.js - displayName: Prepare build +- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 + inputs: + keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' + targetfolder: '**/node_modules, !**/node_modules/**/node_modules' + vstsFeed: 'npm-vscode' - script: | set -e - VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" \ - ./build/azure-pipelines/linux/build.sh - displayName: Build + CHILD_CONCURRENCY=1 yarn --frozen-lockfile + displayName: Install dependencies + condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) + +- task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 + inputs: + keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' + targetfolder: '**/node_modules, !**/node_modules/**/node_modules' + vstsFeed: 'npm-vscode' + condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) + +- script: | + set -e + yarn postinstall + displayName: Run postinstall scripts + condition: and(succeeded(), eq(variables['CacheRestored'], 'true')) - script: | set -e - yarn gulp "electron-$(VSCODE_ARCH)" + node build/azure-pipelines/mixin + displayName: Mix in quality - # xvfb seems to be crashing often, let's make sure it's always up +- script: | + set -e + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn gulp vscode-linux-x64-min-ci + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn gulp vscode-reh-linux-x64-min-ci + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn gulp vscode-reh-web-linux-x64-min-ci + displayName: Build + +- script: | + set -e service xvfb start + displayName: Start xvfb + condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) +- script: | + set -e DISPLAY=:10 ./scripts/test.sh --build --tfs "Unit Tests" - # yarn smoketest -- --build "$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)" displayName: Run unit tests + condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - script: | set -e - AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \ - AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \ - VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" \ - VSCODE_HOCKEYAPP_TOKEN="$(VSCODE_HOCKEYAPP_TOKEN)" \ + DISPLAY=:10 ./scripts/test-integration.sh --build --tfs "Integration Tests" + # yarn smoketest -- --build "$(agent.builddirectory)/VSCode-linux-x64" + displayName: Run integration tests + condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) + +- script: | + set -e + AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ + AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \ + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + VSCODE_HOCKEYAPP_TOKEN="$(vscode-hockeyapp-token)" \ ./build/azure-pipelines/linux/publish.sh displayName: Publish -- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - continueOnError: true - - task: PublishPipelineArtifact@0 displayName: 'Publish Pipeline Artifact' inputs: - artifactName: snap-$(VSCODE_ARCH) + artifactName: snap-x64 targetPath: .build/linux/snap-tarball + +- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 + displayName: 'Component Detection' + continueOnError: true diff --git a/build/azure-pipelines/linux/publish.sh b/build/azure-pipelines/linux/publish.sh index ca338a6fc..5fc86d02d 100755 --- a/build/azure-pipelines/linux/publish.sh +++ b/build/azure-pipelines/linux/publish.sh @@ -4,9 +4,7 @@ REPO="$(pwd)" ROOT="$REPO/.." # Publish tarball -PLATFORM_LINUX="linux-$VSCODE_ARCH" -[[ "$VSCODE_ARCH" == "ia32" ]] && DEB_ARCH="i386" || DEB_ARCH="amd64" -[[ "$VSCODE_ARCH" == "ia32" ]] && RPM_ARCH="i386" || RPM_ARCH="x86_64" +PLATFORM_LINUX="linux-x64" BUILDNAME="VSCode-$PLATFORM_LINUX" BUILD="$ROOT/$BUILDNAME" BUILD_VERSION="$(date +%s)" @@ -20,32 +18,43 @@ rm -rf $ROOT/code-*.tar.* node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "$PLATFORM_LINUX" archive-unsigned "$TARBALL_FILENAME" "$VERSION" true "$TARBALL_PATH" +# Publish Remote Extension Host +LEGACY_SERVER_BUILD_NAME="vscode-reh-$PLATFORM_LINUX" +SERVER_BUILD_NAME="vscode-server-$PLATFORM_LINUX" +SERVER_TARBALL_FILENAME="vscode-server-$PLATFORM_LINUX.tar.gz" +SERVER_TARBALL_PATH="$ROOT/$SERVER_TARBALL_FILENAME" + +rm -rf $ROOT/vscode-server-*.tar.* +(cd $ROOT && mv $LEGACY_SERVER_BUILD_NAME $SERVER_BUILD_NAME && tar --owner=0 --group=0 -czf $SERVER_TARBALL_PATH $SERVER_BUILD_NAME) + +node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "server-$PLATFORM_LINUX" archive-unsigned "$SERVER_TARBALL_FILENAME" "$VERSION" true "$SERVER_TARBALL_PATH" + # Publish hockeyapp symbols -node build/azure-pipelines/common/symbols.js "$VSCODE_MIXIN_PASSWORD" "$VSCODE_HOCKEYAPP_TOKEN" "$VSCODE_ARCH" "$VSCODE_HOCKEYAPP_ID_LINUX64" +node build/azure-pipelines/common/symbols.js "$VSCODE_MIXIN_PASSWORD" "$VSCODE_HOCKEYAPP_TOKEN" "x64" "$VSCODE_HOCKEYAPP_ID_LINUX64" # Publish DEB -yarn gulp "vscode-linux-$VSCODE_ARCH-build-deb" -PLATFORM_DEB="linux-deb-$VSCODE_ARCH" -[[ "$VSCODE_ARCH" == "ia32" ]] && DEB_ARCH="i386" || DEB_ARCH="amd64" +yarn gulp "vscode-linux-x64-build-deb" +PLATFORM_DEB="linux-deb-x64" +DEB_ARCH="amd64" DEB_FILENAME="$(ls $REPO/.build/linux/deb/$DEB_ARCH/deb/)" DEB_PATH="$REPO/.build/linux/deb/$DEB_ARCH/deb/$DEB_FILENAME" node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "$PLATFORM_DEB" package "$DEB_FILENAME" "$VERSION" true "$DEB_PATH" # Publish RPM -yarn gulp "vscode-linux-$VSCODE_ARCH-build-rpm" -PLATFORM_RPM="linux-rpm-$VSCODE_ARCH" -[[ "$VSCODE_ARCH" == "ia32" ]] && RPM_ARCH="i386" || RPM_ARCH="x86_64" +yarn gulp "vscode-linux-x64-build-rpm" +PLATFORM_RPM="linux-rpm-x64" +RPM_ARCH="x86_64" RPM_FILENAME="$(ls $REPO/.build/linux/rpm/$RPM_ARCH/ | grep .rpm)" RPM_PATH="$REPO/.build/linux/rpm/$RPM_ARCH/$RPM_FILENAME" node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "$PLATFORM_RPM" package "$RPM_FILENAME" "$VERSION" true "$RPM_PATH" # Publish Snap -yarn gulp "vscode-linux-$VSCODE_ARCH-prepare-snap" +yarn gulp "vscode-linux-x64-prepare-snap" # Pack snap tarball artifact, in order to preserve file perms mkdir -p $REPO/.build/linux/snap-tarball -SNAP_TARBALL_PATH="$REPO/.build/linux/snap-tarball/snap-$VSCODE_ARCH.tar.gz" +SNAP_TARBALL_PATH="$REPO/.build/linux/snap-tarball/snap-x64.tar.gz" rm -rf $SNAP_TARBALL_PATH (cd .build/linux && tar -czf $SNAP_TARBALL_PATH snap) diff --git a/build/azure-pipelines/linux/snap-build-linux.yml b/build/azure-pipelines/linux/snap-build-linux.yml index 9588ebcb3..4c3f602e8 100644 --- a/build/azure-pipelines/linux/snap-build-linux.yml +++ b/build/azure-pipelines/linux/snap-build-linux.yml @@ -7,10 +7,16 @@ steps: inputs: versionSpec: "1.10.1" +- task: AzureKeyVault@1 + displayName: 'Azure Key Vault: Get Secrets' + inputs: + azureSubscription: 'vscode-builds-subscription' + KeyVaultName: vscode + - task: DownloadPipelineArtifact@0 displayName: 'Download Pipeline Artifact' inputs: - artifactName: snap-$(VSCODE_ARCH) + artifactName: snap-x64 targetPath: .build/linux/snap-tarball - script: | @@ -25,14 +31,13 @@ steps: # Define variables REPO="$(pwd)" - ARCH="$(VSCODE_ARCH)" - SNAP_ROOT="$REPO/.build/linux/snap/$ARCH" + SNAP_ROOT="$REPO/.build/linux/snap/x64" # Install build dependencies (cd build && yarn) # Unpack snap tarball artifact, in order to preserve file perms - SNAP_TARBALL_PATH="$REPO/.build/linux/snap-tarball/snap-$ARCH.tar.gz" + SNAP_TARBALL_PATH="$REPO/.build/linux/snap-tarball/snap-x64.tar.gz" (cd .build/linux && tar -xzf $SNAP_TARBALL_PATH) # Create snap package @@ -41,9 +46,9 @@ steps: PACKAGEJSON="$(ls $SNAP_ROOT/code*/usr/share/code*/resources/app/package.json)" VERSION=$(node -p "require(\"$PACKAGEJSON\").version") SNAP_PATH="$SNAP_ROOT/$SNAP_FILENAME" - (cd $SNAP_ROOT/code-* && sudo snapcraft snap --output "$SNAP_PATH") + (cd $SNAP_ROOT/code-* && sudo --preserve-env snapcraft snap --output "$SNAP_PATH") # Publish snap package - AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \ - AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \ - node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "linux-snap-$ARCH" package "$SNAP_FILENAME" "$VERSION" true "$SNAP_PATH" \ No newline at end of file + AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ + AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \ + node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "linux-snap-x64" package "$SNAP_FILENAME" "$VERSION" true "$SNAP_PATH" \ No newline at end of file diff --git a/build/azure-pipelines/mixin.js b/build/azure-pipelines/mixin.js new file mode 100644 index 000000000..efb7d4d1c --- /dev/null +++ b/build/azure-pipelines/mixin.js @@ -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. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +const json = require('gulp-json-editor'); +const buffer = require('gulp-buffer'); +const filter = require('gulp-filter'); +const es = require('event-stream'); +const vfs = require('vinyl-fs'); +const fancyLog = require('fancy-log'); +const ansiColors = require('ansi-colors'); + +function main() { + const quality = process.env['VSCODE_QUALITY']; + + if (!quality) { + console.log('Missing VSCODE_QUALITY, skipping mixin'); + return; + } + + const productJsonFilter = filter('product.json', { restore: true }); + + fancyLog(ansiColors.blue('[mixin]'), `Mixing in sources:`); + return vfs + .src(`quality/${quality}/**`, { base: `quality/${quality}` }) + .pipe(filter(f => !f.isDirectory())) + .pipe(productJsonFilter) + .pipe(buffer()) + .pipe(json(o => Object.assign({}, require('../product.json'), o))) + .pipe(productJsonFilter.restore) + .pipe(es.mapSync(function (f) { + fancyLog(ansiColors.blue('[mixin]'), f.relative, ansiColors.green('✔︎')); + return f; + })) + .pipe(vfs.dest('.')); +} + +main(); \ No newline at end of file diff --git a/build/azure-pipelines/product-build.yml b/build/azure-pipelines/product-build.yml index 86868f6a2..469494c7d 100644 --- a/build/azure-pipelines/product-build.yml +++ b/build/azure-pipelines/product-build.yml @@ -1,79 +1,135 @@ resources: containers: - container: vscode-x64 - image: joaomoreno/vscode-linux-build-agent:x64 - - container: vscode-ia32 - image: joaomoreno/vscode-linux-build-agent:ia32 + image: vscodehub.azurecr.io/vscode-linux-build-agent:x64 + endpoint: VSCodeHub - container: snapcraft - image: snapcore/snapcraft + image: snapcore/snapcraft:stable jobs: +- job: Compile + pool: + vmImage: 'Ubuntu-16.04' + container: vscode-x64 + steps: + - template: product-compile.yml + - job: Windows - condition: eq(variables['VSCODE_BUILD_WIN32'], 'true') + condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_WIN32'], 'true')) pool: vmImage: VS2017-Win2016 variables: VSCODE_ARCH: x64 + dependsOn: + - Compile steps: - template: win32/product-build-win32.yml - job: Windows32 - condition: eq(variables['VSCODE_BUILD_WIN32_32BIT'], 'true') + condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_WIN32_32BIT'], 'true')) pool: vmImage: VS2017-Win2016 variables: VSCODE_ARCH: ia32 + dependsOn: + - Compile steps: - template: win32/product-build-win32.yml - job: Linux - condition: eq(variables['VSCODE_BUILD_LINUX'], 'true') + condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX'], 'true')) pool: vmImage: 'Ubuntu-16.04' - variables: - VSCODE_ARCH: x64 container: vscode-x64 + dependsOn: + - Compile steps: - template: linux/product-build-linux.yml - job: LinuxSnap - condition: eq(variables['VSCODE_BUILD_LINUX'], 'true') + condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX'], 'true')) pool: vmImage: 'Ubuntu-16.04' - variables: - VSCODE_ARCH: x64 container: snapcraft dependsOn: Linux steps: - template: linux/snap-build-linux.yml -- job: Linux32 - condition: eq(variables['VSCODE_BUILD_LINUX_32BIT'], 'true') +- job: LinuxArmhf + condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX_ARMHF'], 'true'), ne(variables['VSCODE_QUALITY'], 'stable')) pool: vmImage: 'Ubuntu-16.04' variables: - VSCODE_ARCH: ia32 - container: vscode-ia32 + VSCODE_ARCH: armhf + dependsOn: + - Compile steps: - - template: linux/product-build-linux.yml + - template: linux/product-build-linux-multiarch.yml + +- job: LinuxAlpine + condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX_ALPINE'], 'true'), ne(variables['VSCODE_QUALITY'], 'stable')) + pool: + vmImage: 'Ubuntu-16.04' + variables: + VSCODE_ARCH: alpine + dependsOn: + - Compile + steps: + - template: linux/product-build-linux-multiarch.yml + +- job: LinuxWeb + condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_WEB'], 'true')) + pool: + vmImage: 'Ubuntu-16.04' + variables: + VSCODE_ARCH: x64 + dependsOn: + - Compile + steps: + - template: web/product-build-web.yml - job: macOS - condition: eq(variables['VSCODE_BUILD_MACOS'], 'true') + condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_MACOS'], 'true')) pool: vmImage: macOS 10.13 + dependsOn: + - Compile steps: - template: darwin/product-build-darwin.yml +- job: Release + condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), or(eq(variables['VSCODE_RELEASE'], 'true'), and(or(eq(variables['VSCODE_QUALITY'], 'insider'), eq(variables['VSCODE_QUALITY'], 'exploration')), eq(variables['Build.Reason'], 'Schedule')))) + pool: + vmImage: 'Ubuntu-16.04' + dependsOn: + - Windows + - Windows32 + - Linux + - LinuxSnap + - LinuxArmhf + - LinuxAlpine + - macOS + steps: + - template: release.yml + - job: Mooncake pool: vmImage: 'Ubuntu-16.04' - condition: true + condition: and(succeededOrFailed(), eq(variables['VSCODE_COMPILE_ONLY'], 'false')) dependsOn: - Windows - Windows32 - Linux - LinuxSnap - - Linux32 + - LinuxArmhf + - LinuxAlpine - macOS steps: - - template: sync-mooncake.yml \ No newline at end of file + - template: sync-mooncake.yml + +schedules: +- cron: "0 5 * * Mon-Fri" + displayName: Mon-Fri at 7:00 + branches: + include: + - master \ No newline at end of file diff --git a/build/azure-pipelines/product-compile.yml b/build/azure-pipelines/product-compile.yml new file mode 100644 index 000000000..e5105326e --- /dev/null +++ b/build/azure-pipelines/product-compile.yml @@ -0,0 +1,124 @@ +steps: +- script: | + mkdir -p .build + echo -n $BUILD_SOURCEVERSION > .build/commit + displayName: Prepare cache flag + +- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 + inputs: + keyfile: 'build/.cachesalt, .build/commit' + targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min' + vstsFeed: 'npm-vscode' + platformIndependent: true + alias: 'Compilation' + +- task: NodeTool@0 + inputs: + versionSpec: "10.15.1" + condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) + +- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 + inputs: + versionSpec: "1.10.1" + condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) + +- task: AzureKeyVault@1 + displayName: 'Azure Key Vault: Get Secrets' + inputs: + azureSubscription: 'vscode-builds-subscription' + KeyVaultName: vscode + condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) + +- script: | + set -e + cat << EOF > ~/.netrc + machine github.com + login vscode + password $(github-distro-mixin-password) + EOF + + git config user.email "vscode@microsoft.com" + git config user.name "VSCode" + displayName: Prepare tooling + condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) + +- script: | + set -e + git remote add distro "https://github.com/$(VSCODE_MIXIN_REPO).git" + git fetch distro + git merge $(node -p "require('./package.json').distro") + displayName: Merge distro + condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) + +- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 + inputs: + keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' + targetfolder: '**/node_modules, !**/node_modules/**/node_modules' + vstsFeed: 'npm-vscode' + condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) + +- script: | + set -e + CHILD_CONCURRENCY=1 yarn --frozen-lockfile + displayName: Install dependencies + condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'), ne(variables['CacheRestored'], 'true')) + +- task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 + inputs: + keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' + targetfolder: '**/node_modules, !**/node_modules/**/node_modules' + vstsFeed: 'npm-vscode' + condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'), ne(variables['CacheRestored'], 'true')) + +- script: | + set -e + yarn postinstall + displayName: Run postinstall scripts + condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'), eq(variables['CacheRestored'], 'true')) + +# Mixin must run before optimize, because the CSS loader will +# inline small SVGs +- script: | + set -e + node build/azure-pipelines/mixin + displayName: Mix in quality + condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) + +- script: | + set -e + yarn gulp hygiene + yarn monaco-compile-check + displayName: Run hygiene checks + condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'), eq(variables['VSCODE_STEP_ON_IT'], 'false')) + +- script: | + set - + ./build/azure-pipelines/common/extract-telemetry.sh + displayName: Extract Telemetry + condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) + +- script: | + set -e + yarn gulp compile-build + yarn gulp compile-extensions-build + yarn gulp minify-vscode + yarn gulp minify-vscode-reh + yarn gulp minify-vscode-reh-web + displayName: Compile + condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) + +- script: | + set -e + AZURE_STORAGE_ACCESS_KEY="$(ticino-storage-key)" \ + node build/azure-pipelines/upload-sourcemaps + displayName: Upload sourcemaps + condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) + +- task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 + inputs: + keyfile: 'build/.cachesalt, .build/commit' + targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min' + vstsFeed: 'npm-vscode' + platformIndependent: true + alias: 'Compilation' + condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) \ No newline at end of file diff --git a/build/azure-pipelines/publish-types/.gitignore b/build/azure-pipelines/publish-types/.gitignore new file mode 100644 index 000000000..e94ecda76 --- /dev/null +++ b/build/azure-pipelines/publish-types/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +*.js \ No newline at end of file diff --git a/build/azure-pipelines/publish-types/check-version.ts b/build/azure-pipelines/publish-types/check-version.ts new file mode 100644 index 000000000..2c7308891 --- /dev/null +++ b/build/azure-pipelines/publish-types/check-version.ts @@ -0,0 +1,43 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import * as cp from 'child_process'; + +let tag = ''; +try { + tag = cp + .execSync('git describe --tags `git rev-list --tags --max-count=1`') + .toString() + .trim(); + + if (!isValidTag(tag)) { + throw Error(`Invalid tag ${tag}`); + } +} catch (err) { + console.error(err); + console.error('Failed to update types'); + process.exit(1); +} + +function isValidTag(t: string) { + if (t.split('.').length !== 3) { + return false; + } + + const [major, minor, bug] = t.split('.'); + + // Only release for tags like 1.34.0 + if (bug !== '0') { + return false; + } + + if (parseInt(major, 10) === NaN || parseInt(minor, 10) === NaN) { + return false; + } + + return true; +} \ No newline at end of file diff --git a/build/azure-pipelines/publish-types/publish-types.yml b/build/azure-pipelines/publish-types/publish-types.yml new file mode 100644 index 000000000..ff03ceced --- /dev/null +++ b/build/azure-pipelines/publish-types/publish-types.yml @@ -0,0 +1,67 @@ +# Publish @types/vscode for each release + +trigger: + branches: + include: ['refs/tags/*'] + +pr: none + +steps: +- task: NodeTool@0 + inputs: + versionSpec: "10.15.1" + +- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 + inputs: + versionSpec: "1.10.1" + +- bash: | + # Install build dependencies + (cd build && yarn) + node build/azure-pipelines/publish-types/check-version.js + displayName: Check version + +- bash: | + git config --global user.email "vscode@microsoft.com" + git config --global user.name "VSCode" + + git clone https://$(GITHUB_TOKEN)@github.com/DefinitelyTyped/DefinitelyTyped.git --depth=1 + node build/azure-pipelines/publish-types/update-types.js + + TAG_VERSION=$(git describe --tags `git rev-list --tags --max-count=1`) + + cd DefinitelyTyped + + git diff --color | cat + git add -A + git status + git checkout -b "vscode-types-$TAG_VERSION" + git commit -m "VS Code $TAG_VERSION Extension API" + git push origin "vscode-types-$TAG_VERSION" + + displayName: Push update to DefinitelyTyped + +- bash: | + TAG_VERSION=$(git describe --tags `git rev-list --tags --max-count=1`) + CHANNEL="G1C14HJ2F" + + MESSAGE="DefinitelyTyped/DefinitelyTyped#vscode-types-$TAG_VERSION created. Endgame master, please open this link, examine changes and create a PR:" + LINK="https://github.com/DefinitelyTyped/DefinitelyTyped/compare/vscode-types-$TAG_VERSION?quick_pull=1&body=Updating%20VS%20Code%20Extension%20API.%20See%20https%3A%2F%2Fgithub.com%2Fmicrosoft%2Fvscode%2Fissues%2F70175%20for%20details." + MESSAGE2="[@octref, @jrieken, @kmaetzel, @egamma]. Please review and merge PR to publish @types/vscode." + + curl -X POST -H "Authorization: Bearer $(SLACK_TOKEN)" \ + -H 'Content-type: application/json; charset=utf-8' \ + --data '{"channel":"'"$CHANNEL"'", "link_names": true, "text":"'"$MESSAGE"'"}' \ + https://slack.com/api/chat.postMessage + + curl -X POST -H "Authorization: Bearer $(SLACK_TOKEN)" \ + -H 'Content-type: application/json; charset=utf-8' \ + --data '{"channel":"'"$CHANNEL"'", "link_names": true, "text":"'"$LINK"'"}' \ + https://slack.com/api/chat.postMessage + + curl -X POST -H "Authorization: Bearer $(SLACK_TOKEN)" \ + -H 'Content-type: application/json; charset=utf-8' \ + --data '{"channel":"'"$CHANNEL"'", "link_names": true, "text":"'"$MESSAGE2"'"}' \ + https://slack.com/api/chat.postMessage + + displayName: Send message on Slack diff --git a/build/azure-pipelines/publish-types/update-types.ts b/build/azure-pipelines/publish-types/update-types.ts new file mode 100644 index 000000000..a5ef449b7 --- /dev/null +++ b/build/azure-pipelines/publish-types/update-types.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. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import * as fs from 'fs'; +import * as cp from 'child_process'; +import * as path from 'path'; + +let tag = ''; +try { + tag = cp + .execSync('git describe --tags `git rev-list --tags --max-count=1`') + .toString() + .trim(); + + const dtsUri = `https://raw.githubusercontent.com/microsoft/vscode/${tag}/src/vs/vscode.d.ts`; + const outPath = path.resolve(process.cwd(), 'DefinitelyTyped/types/vscode/index.d.ts'); + cp.execSync(`curl ${dtsUri} --output ${outPath}`); + + updateDTSFile(outPath, tag); + + console.log(`Done updating vscode.d.ts at ${outPath}`); +} catch (err) { + console.error(err); + console.error('Failed to update types'); + process.exit(1); +} + +function updateDTSFile(outPath: string, tag: string) { + const oldContent = fs.readFileSync(outPath, 'utf-8'); + const newContent = getNewFileContent(oldContent, tag); + + fs.writeFileSync(outPath, newContent); +} + +function getNewFileContent(content: string, tag: string) { + const oldheader = [ + `/*---------------------------------------------------------------------------------------------`, + ` * Copyright (c) Microsoft Corporation. All rights reserved.`, + ` * Licensed under the MIT License. See License.txt in the project root for license information.`, + ` *--------------------------------------------------------------------------------------------*/` + ].join('\n'); + + return getNewFileHeader(tag) + content.slice(oldheader.length); +} + +function getNewFileHeader(tag: string) { + const [major, minor] = tag.split('.'); + const shorttag = `${major}.${minor}`; + + const header = [ + `// Type definitions for Visual Studio Code ${shorttag}`, + `// Project: https://github.com/microsoft/vscode`, + `// Definitions by: Visual Studio Code Team, Microsoft `, + `// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped`, + ``, + `/*---------------------------------------------------------------------------------------------`, + ` * Copyright (c) Microsoft Corporation. All rights reserved.`, + ` * Licensed under the MIT License.`, + ` * See https://github.com/Microsoft/vscode/blob/master/LICENSE.txt for license information.`, + ` *--------------------------------------------------------------------------------------------*/`, + ``, + `/**`, + ` * Type Definition for Visual Studio Code ${shorttag} Extension API`, + ` * See https://code.visualstudio.com/api for more information`, + ` */` + ].join('\n'); + + return header; +} diff --git a/build/azure-pipelines/release.yml b/build/azure-pipelines/release.yml new file mode 100644 index 000000000..eee54a1d8 --- /dev/null +++ b/build/azure-pipelines/release.yml @@ -0,0 +1,22 @@ +steps: +- task: NodeTool@0 + inputs: + versionSpec: "10.x" + +- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 + inputs: + versionSpec: "1.x" + +- task: AzureKeyVault@1 + displayName: 'Azure Key Vault: Get Secrets' + inputs: + azureSubscription: 'vscode-builds-subscription' + KeyVaultName: vscode + +- script: | + set -e + + (cd build ; yarn) + + AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ + node build/azure-pipelines/common/release.js diff --git a/build/azure-pipelines/sync-mooncake.yml b/build/azure-pipelines/sync-mooncake.yml index c422839de..f3e8bc078 100644 --- a/build/azure-pipelines/sync-mooncake.yml +++ b/build/azure-pipelines/sync-mooncake.yml @@ -7,12 +7,18 @@ steps: inputs: versionSpec: "1.10.1" +- task: AzureKeyVault@1 + displayName: 'Azure Key Vault: Get Secrets' + inputs: + azureSubscription: 'vscode-builds-subscription' + KeyVaultName: vscode + - script: | set -e (cd build ; yarn) - AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \ - AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \ - MOONCAKE_STORAGE_ACCESS_KEY="$(MOONCAKE_STORAGE_ACCESS_KEY)" \ + AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ + AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \ + MOONCAKE_STORAGE_ACCESS_KEY="$(vscode-mooncake-storage-key)" \ node build/azure-pipelines/common/sync-mooncake.js "$VSCODE_QUALITY" diff --git a/build/azure-pipelines/upload-sourcemaps.js b/build/azure-pipelines/upload-sourcemaps.js new file mode 100644 index 000000000..ac3bd55a7 --- /dev/null +++ b/build/azure-pipelines/upload-sourcemaps.js @@ -0,0 +1,39 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +const path = require('path'); +const es = require('event-stream'); +const azure = require('gulp-azure-storage'); +const vfs = require('vinyl-fs'); +const util = require('../lib/util'); +const root = path.dirname(path.dirname(__dirname)); +const commit = util.getVersion(root); + +function main() { + const vs = vfs.src('out-vscode-min/**/*.map', { base: 'out-vscode-min' }) // client source-maps only + .pipe(es.mapSync(f => { + f.path = `${f.base}/core/${f.relative}`; + return f; + })); + + const extensionsOut = vfs.src(['.build/extensions/**/*.js.map', '!**/node_modules/**'], { base: '.build' }); + + return es.merge(vs, extensionsOut) + .pipe(es.through(function (data) { + // debug + console.log('Uploading Sourcemap', data.relative); + this.emit('data', data); + })) + .pipe(azure.upload({ + account: process.env.AZURE_STORAGE_ACCOUNT, + key: process.env.AZURE_STORAGE_ACCESS_KEY, + container: 'sourcemaps', + prefix: commit + '/' + })); +} + +main(); \ No newline at end of file diff --git a/build/azure-pipelines/web/product-build-web.yml b/build/azure-pipelines/web/product-build-web.yml new file mode 100644 index 000000000..7c65dc982 --- /dev/null +++ b/build/azure-pipelines/web/product-build-web.yml @@ -0,0 +1,96 @@ +steps: +- script: | + mkdir -p .build + echo -n $BUILD_SOURCEVERSION > .build/commit + displayName: Prepare cache flag + +- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 + inputs: + keyfile: 'build/.cachesalt, .build/commit' + targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min' + vstsFeed: 'npm-vscode' + platformIndependent: true + alias: 'Compilation' + +- script: | + set -e + exit 1 + displayName: Check RestoreCache + condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) + +- task: NodeTool@0 + inputs: + versionSpec: "10.15.1" + +- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 + inputs: + versionSpec: "1.10.1" + +- task: AzureKeyVault@1 + displayName: 'Azure Key Vault: Get Secrets' + inputs: + azureSubscription: 'vscode-builds-subscription' + KeyVaultName: vscode + +- script: | + set -e + cat << EOF > ~/.netrc + machine github.com + login vscode + password $(github-distro-mixin-password) + EOF + + git config user.email "vscode@microsoft.com" + git config user.name "VSCode" + displayName: Prepare tooling + +- script: | + set -e + git remote add distro "https://github.com/$(VSCODE_MIXIN_REPO).git" + git fetch distro + git merge $(node -p "require('./package.json').distro") + displayName: Merge distro + +# - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 +# inputs: +# keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' +# targetfolder: '**/node_modules, !**/node_modules/**/node_modules' +# vstsFeed: 'npm-vscode' + +- script: | + set -e + CHILD_CONCURRENCY=1 yarn --frozen-lockfile + displayName: Install dependencies + # condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) + +# - task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 +# inputs: +# keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' +# targetfolder: '**/node_modules, !**/node_modules/**/node_modules' +# vstsFeed: 'npm-vscode' +# condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) + +# - script: | +# set -e +# yarn postinstall +# displayName: Run postinstall scripts +# condition: and(succeeded(), eq(variables['CacheRestored'], 'true')) + +- script: | + set -e + node build/azure-pipelines/mixin + displayName: Mix in quality + +- script: | + set -e + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + yarn gulp vscode-web-min-ci + displayName: Build + +- script: | + set -e + AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ + AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \ + VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ + ./build/azure-pipelines/web/publish.sh + displayName: Publish diff --git a/build/azure-pipelines/web/publish.sh b/build/azure-pipelines/web/publish.sh new file mode 100755 index 000000000..9d662fcfe --- /dev/null +++ b/build/azure-pipelines/web/publish.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -e +REPO="$(pwd)" +ROOT="$REPO/.." + +# Publish Web Client +WEB_BUILD_NAME="vscode-web" +WEB_TARBALL_FILENAME="vscode-web.tar.gz" +WEB_TARBALL_PATH="$ROOT/$WEB_TARBALL_FILENAME" + +rm -rf $ROOT/vscode-web.tar.* + +(cd $ROOT && tar --owner=0 --group=0 -czf $WEB_TARBALL_PATH $WEB_BUILD_NAME) + +node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "web-standalone" archive-unsigned "$WEB_TARBALL_FILENAME" "$VERSION" true "$WEB_TARBALL_PATH" diff --git a/build/azure-pipelines/win32/build.ps1 b/build/azure-pipelines/win32/build.ps1 deleted file mode 100644 index 60325ba54..000000000 --- a/build/azure-pipelines/win32/build.ps1 +++ /dev/null @@ -1,4 +0,0 @@ -. build/azure-pipelines/win32/exec.ps1 -$ErrorActionPreference = "Stop" -exec { yarn gulp "vscode-win32-$env:VSCODE_ARCH-min" } -exec { yarn gulp "vscode-win32-$env:VSCODE_ARCH-inno-updater" } \ No newline at end of file diff --git a/build/azure-pipelines/win32/continuous-build-win32.yml b/build/azure-pipelines/win32/continuous-build-win32.yml index 363362768..9b6d61ee9 100644 --- a/build/azure-pipelines/win32/continuous-build-win32.yml +++ b/build/azure-pipelines/win32/continuous-build-win32.yml @@ -11,16 +11,16 @@ steps: addToPath: true - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 inputs: - keyfile: '**/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' + keyfile: '.yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' targetfolder: '**/node_modules, !**/node_modules/**/node_modules' vstsFeed: '$(ArtifactFeed)' - powershell: | - yarn + yarn --frozen-lockfile displayName: Install Dependencies - condition: ne(variables['CacheRestored'], 'true') + condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) - task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 inputs: - keyfile: '**/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' + keyfile: '.yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' targetfolder: '**/node_modules, !**/node_modules/**/node_modules' vstsFeed: '$(ArtifactFeed)' condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) diff --git a/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml index a49349150..66583616c 100644 --- a/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -1,4 +1,23 @@ steps: +- powershell: | + mkdir .build -ea 0 + "$env:BUILD_SOURCEVERSION" | Out-File -Encoding ascii -NoNewLine .build\commit + displayName: Prepare cache flag + +- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 + inputs: + keyfile: 'build/.cachesalt, .build/commit' + targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min' + vstsFeed: 'npm-vscode' + platformIndependent: true + alias: 'Compilation' + +- powershell: | + $ErrorActionPreference = "Stop" + exit 1 + displayName: Check RestoreCache + condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) + - task: NodeTool@0 inputs: versionSpec: "10.15.1" @@ -12,32 +31,75 @@ steps: versionSpec: '2.x' addToPath: true +- task: AzureKeyVault@1 + displayName: 'Azure Key Vault: Get Secrets' + inputs: + azureSubscription: 'vscode-builds-subscription' + KeyVaultName: vscode + - powershell: | . build/azure-pipelines/win32/exec.ps1 $ErrorActionPreference = "Stop" - "machine monacotools.visualstudio.com`npassword $(VSO_PAT)`nmachine github.com`nlogin vscode`npassword $(VSCODE_MIXIN_PASSWORD)" | Out-File "$env:USERPROFILE\_netrc" -Encoding ASCII - $env:npm_config_arch="$(VSCODE_ARCH)" - $env:CHILD_CONCURRENCY="1" + "machine github.com`nlogin vscode`npassword $(github-distro-mixin-password)" | Out-File "$env:USERPROFILE\_netrc" -Encoding ASCII exec { git config user.email "vscode@microsoft.com" } exec { git config user.name "VSCode" } + + mkdir .build -ea 0 + "$(VSCODE_ARCH)" | Out-File -Encoding ascii -NoNewLine .build\arch + displayName: Prepare tooling + +- powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" exec { git remote add distro "https://github.com/$(VSCODE_MIXIN_REPO).git" } exec { git fetch distro } exec { git merge $(node -p "require('./package.json').distro") } + displayName: Merge distro - exec { yarn } - exec { yarn gulp mixin } - exec { yarn gulp hygiene } - exec { yarn monaco-compile-check } - exec { node build/azure-pipelines/common/installDistro.js } - exec { node build/lib/builtInExtensions.js } - displayName: Prepare build +- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 + inputs: + keyfile: 'build/.cachesalt, .build/arch, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' + targetfolder: '**/node_modules, !**/node_modules/**/node_modules' + vstsFeed: 'npm-vscode' + +- powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + $env:npm_config_arch="$(VSCODE_ARCH)" + $env:CHILD_CONCURRENCY="1" + exec { yarn --frozen-lockfile } + displayName: Install dependencies + condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) + +- task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1 + inputs: + keyfile: 'build/.cachesalt, .build/arch, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock' + targetfolder: '**/node_modules, !**/node_modules/**/node_modules' + vstsFeed: 'npm-vscode' + condition: and(succeeded(), ne(variables['CacheRestored'], 'true')) + +- powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { yarn postinstall } + displayName: Run postinstall scripts + condition: and(succeeded(), eq(variables['CacheRestored'], 'true')) + +- powershell: | + . build/azure-pipelines/win32/exec.ps1 + $ErrorActionPreference = "Stop" + exec { node build/azure-pipelines/mixin } + displayName: Mix in quality - powershell: | . build/azure-pipelines/win32/exec.ps1 $ErrorActionPreference = "Stop" - $env:VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" - .\build\azure-pipelines\win32\build.ps1 + $env:VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" + exec { yarn gulp "vscode-win32-$env:VSCODE_ARCH-min-ci" } + exec { yarn gulp "vscode-reh-win32-$env:VSCODE_ARCH-min-ci" } + exec { yarn gulp "vscode-reh-web-win32-$env:VSCODE_ARCH-min-ci" } + exec { yarn gulp "vscode-win32-$env:VSCODE_ARCH-inno-updater" } displayName: Build - powershell: | @@ -45,8 +107,8 @@ steps: $ErrorActionPreference = "Stop" exec { yarn gulp "electron-$(VSCODE_ARCH)" } exec { .\scripts\test.bat --build --tfs "Unit Tests" } - # yarn smoketest -- --build "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)" displayName: Run unit tests + condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - powershell: | . build/azure-pipelines/win32/exec.ps1 @@ -54,6 +116,7 @@ steps: exec { yarn gulp "electron-$(VSCODE_ARCH)" } exec { .\scripts\test-integration.bat --build --tfs "Integration Tests" } displayName: Run integration tests + condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false')) - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1 inputs: @@ -126,15 +189,16 @@ steps: - powershell: | $ErrorActionPreference = "Stop" - .\build\azure-pipelines\win32\import-esrp-auth-cert.ps1 -AuthCertificateBase64 $(ESRP_AUTH_CERTIFICATE) -AuthCertificateKey $(ESRP_AUTH_CERTIFICATE_KEY) + .\build\azure-pipelines\win32\import-esrp-auth-cert.ps1 -AuthCertificateBase64 $(esrp-auth-certificate) -AuthCertificateKey $(esrp-auth-certificate-key) displayName: Import ESRP Auth Certificate - powershell: | . build/azure-pipelines/win32/exec.ps1 $ErrorActionPreference = "Stop" - $env:AZURE_STORAGE_ACCESS_KEY_2 = "$(AZURE_STORAGE_ACCESS_KEY_2)" - $env:AZURE_DOCUMENTDB_MASTERKEY = "$(AZURE_DOCUMENTDB_MASTERKEY)" - $env:VSCODE_HOCKEYAPP_TOKEN = "$(VSCODE_HOCKEYAPP_TOKEN)" + $env:AZURE_STORAGE_ACCESS_KEY_2 = "$(vscode-storage-key)" + $env:AZURE_DOCUMENTDB_MASTERKEY = "$(builds-docdb-key-readwrite)" + $env:VSCODE_HOCKEYAPP_TOKEN = "$(vscode-hockeyapp-token)" + $env:VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" .\build\azure-pipelines\win32\publish.ps1 displayName: Publish diff --git a/build/azure-pipelines/win32/publish.ps1 b/build/azure-pipelines/win32/publish.ps1 index 8e6fa988a..86da6df4e 100644 --- a/build/azure-pipelines/win32/publish.ps1 +++ b/build/azure-pipelines/win32/publish.ps1 @@ -10,8 +10,16 @@ $Root = "$Repo\.." $SystemExe = "$Repo\.build\win32-$Arch\system-setup\VSCodeSetup.exe" $UserExe = "$Repo\.build\win32-$Arch\user-setup\VSCodeSetup.exe" $Zip = "$Repo\.build\win32-$Arch\archive\VSCode-win32-$Arch.zip" +$LegacyServer = "$Root\vscode-reh-win32-$Arch" +$ServerName = "vscode-server-win32-$Arch" +$Server = "$Root\$ServerName" +$ServerZip = "$Repo\.build\vscode-server-win32-$Arch.zip" $Build = "$Root\VSCode-win32-$Arch" +# Create server archive +exec { Rename-Item -Path $LegacyServer -NewName $ServerName } +exec { .\node_modules\7zip\7zip-lite\7z.exe a -tzip $ServerZip $Server -r } + # get version $PackageJson = Get-Content -Raw -Path "$Build\resources\app\package.json" | ConvertFrom-Json $Version = $PackageJson.version @@ -22,6 +30,7 @@ $AssetPlatform = if ("$Arch" -eq "ia32") { "win32" } else { "win32-x64" } exec { node build/azure-pipelines/common/publish.js $Quality "$AssetPlatform-archive" archive "VSCode-win32-$Arch-$Version.zip" $Version true $Zip } exec { node build/azure-pipelines/common/publish.js $Quality "$AssetPlatform" setup "VSCodeSetup-$Arch-$Version.exe" $Version true $SystemExe } exec { node build/azure-pipelines/common/publish.js $Quality "$AssetPlatform-user" setup "VSCodeUserSetup-$Arch-$Version.exe" $Version true $UserExe } +exec { node build/azure-pipelines/common/publish.js $Quality "server-$AssetPlatform" archive "vscode-server-win32-$Arch.zip" $Version true $ServerZip } # publish hockeyapp symbols $hockeyAppId = if ("$Arch" -eq "ia32") { "$env:VSCODE_HOCKEYAPP_ID_WIN32" } else { "$env:VSCODE_HOCKEYAPP_ID_WIN64" } diff --git a/build/builtInExtensions.json b/build/builtInExtensions.json index f678b7bec..a3483f451 100644 --- a/build/builtInExtensions.json +++ b/build/builtInExtensions.json @@ -1,7 +1,7 @@ [ { "name": "ms-vscode.node-debug", - "version": "1.33.3", + "version": "1.35.3", "repo": "https://github.com/Microsoft/vscode-node-debug", "metadata": { "id": "b6ded8fb-a0a0-4c1c-acbd-ab2a3bc995a6", @@ -31,7 +31,7 @@ }, { "name": "ms-vscode.references-view", - "version": "0.0.26", + "version": "0.0.29", "repo": "https://github.com/Microsoft/vscode-reference-view", "metadata": { "id": "dc489f46-520d-4556-ae85-1f9eab3c412d", diff --git a/build/builtin/main.js b/build/builtin/main.js index 849027ad2..b094a67ca 100644 --- a/build/builtin/main.js +++ b/build/builtin/main.js @@ -10,7 +10,7 @@ const path = require('path'); let window = null; app.once('ready', () => { - window = new BrowserWindow({ width: 800, height: 600 }); + window = new BrowserWindow({ width: 800, height: 600, webPreferences: { nodeIntegration: true, webviewTag: true } }); window.setMenuBarVisibility(false); window.loadURL(url.format({ pathname: path.join(__dirname, 'index.html'), protocol: 'file:', slashes: true })); // window.webContents.openDevTools(); diff --git a/build/download/download.js b/build/download/download.js deleted file mode 100644 index c70bae336..000000000 --- a/build/download/download.js +++ /dev/null @@ -1,91 +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. - *--------------------------------------------------------------------------------------------*/ -Object.defineProperty(exports, "__esModule", { value: true }); -const https = require("https"); -const fs = require("fs"); -const path = require("path"); -const cp = require("child_process"); -function ensureDir(filepath) { - if (!fs.existsSync(filepath)) { - ensureDir(path.dirname(filepath)); - fs.mkdirSync(filepath); - } -} -function download(options, destination) { - ensureDir(path.dirname(destination)); - return new Promise((c, e) => { - const fd = fs.openSync(destination, 'w'); - const req = https.get(options, (res) => { - res.on('data', (chunk) => { - fs.writeSync(fd, chunk); - }); - res.on('end', () => { - fs.closeSync(fd); - c(); - }); - }); - req.on('error', (reqErr) => { - console.error(`request to ${options.host}${options.path} failed.`); - console.error(reqErr); - e(reqErr); - }); - }); -} -const MARKER_ARGUMENT = `_download_fork_`; -function base64encode(str) { - return Buffer.from(str, 'utf8').toString('base64'); -} -function base64decode(str) { - return Buffer.from(str, 'base64').toString('utf8'); -} -function downloadInExternalProcess(options) { - const url = `https://${options.requestOptions.host}${options.requestOptions.path}`; - console.log(`Downloading ${url}...`); - return new Promise((c, e) => { - const child = cp.fork(__filename, [MARKER_ARGUMENT, base64encode(JSON.stringify(options))], { - stdio: ['pipe', 'pipe', 'pipe', 'ipc'] - }); - let stderr = []; - child.stderr.on('data', (chunk) => { - stderr.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk); - }); - child.on('exit', (code) => { - if (code === 0) { - // normal termination - console.log(`Finished downloading ${url}.`); - c(); - } - else { - // abnormal termination - console.error(Buffer.concat(stderr).toString()); - e(new Error(`Download of ${url} failed.`)); - } - }); - }); -} -exports.downloadInExternalProcess = downloadInExternalProcess; -function _downloadInExternalProcess() { - let options; - try { - options = JSON.parse(base64decode(process.argv[3])); - } - catch (err) { - console.error(`Cannot read arguments`); - console.error(err); - process.exit(-1); - return; - } - download(options.requestOptions, options.destinationPath).then(() => { - process.exit(0); - }, (err) => { - console.error(err); - process.exit(-2); - }); -} -if (process.argv.length >= 4 && process.argv[2] === MARKER_ARGUMENT) { - // running as forked download script - _downloadInExternalProcess(); -} diff --git a/build/download/download.ts b/build/download/download.ts deleted file mode 100644 index 01ac8864d..000000000 --- a/build/download/download.ts +++ /dev/null @@ -1,111 +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 https from 'https'; -import * as fs from 'fs'; -import * as path from 'path'; -import * as cp from 'child_process'; - -function ensureDir(filepath: string) { - if (!fs.existsSync(filepath)) { - ensureDir(path.dirname(filepath)); - fs.mkdirSync(filepath); - } -} - -function download(options: https.RequestOptions, destination: string): Promise { - ensureDir(path.dirname(destination)); - - return new Promise((c, e) => { - const fd = fs.openSync(destination, 'w'); - const req = https.get(options, (res) => { - res.on('data', (chunk) => { - fs.writeSync(fd, chunk); - }); - res.on('end', () => { - fs.closeSync(fd); - c(); - }); - }); - req.on('error', (reqErr) => { - console.error(`request to ${options.host}${options.path} failed.`); - console.error(reqErr); - e(reqErr); - }); - }); -} - -const MARKER_ARGUMENT = `_download_fork_`; - -function base64encode(str: string): string { - return Buffer.from(str, 'utf8').toString('base64'); -} - -function base64decode(str: string): string { - return Buffer.from(str, 'base64').toString('utf8'); -} - -export interface IDownloadRequestOptions { - host: string; - path: string; -} - -export interface IDownloadOptions { - requestOptions: IDownloadRequestOptions; - destinationPath: string; -} - -export function downloadInExternalProcess(options: IDownloadOptions): Promise { - const url = `https://${options.requestOptions.host}${options.requestOptions.path}`; - console.log(`Downloading ${url}...`); - return new Promise((c, e) => { - const child = cp.fork( - __filename, - [MARKER_ARGUMENT, base64encode(JSON.stringify(options))], - { - stdio: ['pipe', 'pipe', 'pipe', 'ipc'] - } - ); - let stderr: Buffer[] = []; - child.stderr.on('data', (chunk) => { - stderr.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk); - }); - child.on('exit', (code) => { - if (code === 0) { - // normal termination - console.log(`Finished downloading ${url}.`); - c(); - } else { - // abnormal termination - console.error(Buffer.concat(stderr).toString()); - e(new Error(`Download of ${url} failed.`)); - } - }); - }); -} - -function _downloadInExternalProcess() { - let options: IDownloadOptions; - try { - options = JSON.parse(base64decode(process.argv[3])); - } catch (err) { - console.error(`Cannot read arguments`); - console.error(err); - process.exit(-1); - return; - } - - download(options.requestOptions, options.destinationPath).then(() => { - process.exit(0); - }, (err) => { - console.error(err); - process.exit(-2); - }); -} - -if (process.argv.length >= 4 && process.argv[2] === MARKER_ARGUMENT) { - // running as forked download script - _downloadInExternalProcess(); -} diff --git a/build/gulpfile.compile.js b/build/gulpfile.compile.js index 0dd2e5abf..21aa78965 100644 --- a/build/gulpfile.compile.js +++ b/build/gulpfile.compile.js @@ -5,14 +5,12 @@ 'use strict'; +const gulp = require('gulp'); const util = require('./lib/util'); const task = require('./lib/task'); const compilation = require('./lib/compilation'); -const { compileExtensionsBuildTask } = require('./gulpfile.extensions'); // Full compile, including nls and inline sources in sourcemaps, for build -const compileClientBuildTask = task.define('compile-client-build', task.series(util.rimraf('out-build'), compilation.compileTask('src', 'out-build', true))); - -// All Build -const compileBuildTask = task.define('compile-build', task.parallel(compileClientBuildTask, compileExtensionsBuildTask)); +const compileBuildTask = task.define('compile-build', task.series(util.rimraf('out-build'), compilation.compileTask('src', 'out-build', true))); +gulp.task(compileBuildTask); exports.compileBuildTask = compileBuildTask; \ No newline at end of file diff --git a/build/gulpfile.extensions.js b/build/gulpfile.extensions.js index c72b26caf..e4f7b58d5 100644 --- a/build/gulpfile.extensions.js +++ b/build/gulpfile.extensions.js @@ -22,6 +22,7 @@ const root = path.dirname(__dirname); const commit = util.getVersion(root); const plumber = require('gulp-plumber'); const _ = require('underscore'); +const ext = require('./lib/extensions'); const extensionsPath = path.join(path.dirname(__dirname), 'extensions'); @@ -135,11 +136,7 @@ const tasks = compilations.map(function (tsconfigFile) { gulp.task(compileTask); gulp.task(watchTask); - return { - compileTask: compileTask, - watchTask: watchTask, - compileBuildTask: compileBuildTask - }; + return { compileTask, watchTask, compileBuildTask }; }); const compileExtensionsTask = task.define('compile-extensions', task.parallel(...tasks.map(t => t.compileTask))); @@ -150,5 +147,17 @@ const watchExtensionsTask = task.define('watch-extensions', task.parallel(...tas gulp.task(watchExtensionsTask); exports.watchExtensionsTask = watchExtensionsTask; -const compileExtensionsBuildTask = task.define('compile-extensions-build', task.parallel(...tasks.map(t => t.compileBuildTask))); -exports.compileExtensionsBuildTask = compileExtensionsBuildTask; +const compileExtensionsBuildLegacyTask = task.define('compile-extensions-build-legacy', task.parallel(...tasks.map(t => t.compileBuildTask))); +gulp.task(compileExtensionsBuildLegacyTask); + +// Azure Pipelines + +const cleanExtensionsBuildTask = task.define('clean-extensions-build', util.rimraf('.build/extensions')); +const compileExtensionsBuildTask = task.define('compile-extensions-build', task.series( + cleanExtensionsBuildTask, + task.define('bundle-extensions-build', () => ext.packageLocalExtensionsStream().pipe(gulp.dest('.build'))), + task.define('bundle-marketplace-extensions-build', () => ext.packageMarketplaceExtensionsStream().pipe(gulp.dest('.build'))), +)); + +gulp.task(compileExtensionsBuildTask); +exports.compileExtensionsBuildTask = compileExtensionsBuildTask; \ No newline at end of file diff --git a/build/gulpfile.hygiene.js b/build/gulpfile.hygiene.js index 500826933..f65948043 100644 --- a/build/gulpfile.hygiene.js +++ b/build/gulpfile.hygiene.js @@ -119,7 +119,8 @@ const copyrightFilter = [ '!resources/completions/**', '!extensions/markdown-language-features/media/highlight.css', '!extensions/html-language-features/server/src/modes/typescript/*', - '!extensions/*/server/bin/*' + '!extensions/*/server/bin/*', + '!src/vs/editor/test/node/classification/typescript-test.ts', ]; const eslintFilter = [ @@ -175,6 +176,17 @@ gulp.task('tslint', () => { function hygiene(some) { let errorCount = 0; + const productJson = es.through(function (file) { + const product = JSON.parse(file.contents.toString('utf8')); + + if (product.extensionsGallery) { + console.error('product.json: Contains "extensionsGallery"'); + errorCount++; + } + + this.emit('data', file); + }); + const indentation = es.through(function (file) { const lines = file.contents.toString('utf8').split(/\r\n|\r|\n/); file.__lines = lines; @@ -258,8 +270,13 @@ function hygiene(some) { input = some; } + const productJsonFilter = filter('product.json', { restore: true }); + const result = input .pipe(filter(f => !f.stat.isDirectory())) + .pipe(productJsonFilter) + .pipe(process.env['BUILD_SOURCEVERSION'] ? es.through() : productJson) + .pipe(productJsonFilter.restore) .pipe(filter(indentationFilter)) .pipe(indentation) .pipe(filter(copyrightFilter)) diff --git a/build/gulpfile.mixin.js b/build/gulpfile.mixin.js deleted file mode 100644 index 690cc8748..000000000 --- a/build/gulpfile.mixin.js +++ /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. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; - -const gulp = require('gulp'); -const json = require('gulp-json-editor'); -const buffer = require('gulp-buffer'); -const filter = require('gulp-filter'); -const es = require('event-stream'); -const vfs = require('vinyl-fs'); -const fancyLog = require('fancy-log'); -const ansiColors = require('ansi-colors'); - -gulp.task('mixin', function () { - const quality = process.env['VSCODE_QUALITY']; - - if (!quality) { - console.log('Missing VSCODE_QUALITY, skipping mixin'); - return; - } - - const productJsonFilter = filter('product.json', { restore: true }); - - fancyLog(ansiColors.blue('[mixin]'), `Mixing in sources:`); - return vfs - .src(`quality/${quality}/**`, { base: `quality/${quality}` }) - .pipe(filter(function (f) { return !f.isDirectory(); })) - .pipe(productJsonFilter) - .pipe(buffer()) - .pipe(json(o => Object.assign({}, require('../product.json'), o))) - .pipe(productJsonFilter.restore) - .pipe(es.mapSync(function (f) { - fancyLog(ansiColors.blue('[mixin]'), f.relative, ansiColors.green('✔︎')); - return f; - })) - .pipe(gulp.dest('.')); -}); \ No newline at end of file diff --git a/build/gulpfile.reh.js b/build/gulpfile.reh.js new file mode 100644 index 000000000..7085c4f8f --- /dev/null +++ b/build/gulpfile.reh.js @@ -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. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +const gulp = require('gulp'); + +const path = require('path'); +const es = require('event-stream'); +const util = require('./lib/util'); +const task = require('./lib/task'); +const vfs = require('vinyl-fs'); +const flatmap = require('gulp-flatmap'); +const gunzip = require('gulp-gunzip'); +const untar = require('gulp-untar'); +const File = require('vinyl'); +const fs = require('fs'); +const remote = require('gulp-remote-retry-src'); +const rename = require('gulp-rename'); +const filter = require('gulp-filter'); +const cp = require('child_process'); + +const REPO_ROOT = path.dirname(__dirname); + +const BUILD_TARGETS = [ + { platform: 'win32', arch: 'ia32', pkgTarget: 'node8-win-x86' }, + { platform: 'win32', arch: 'x64', pkgTarget: 'node8-win-x64' }, + { platform: 'darwin', arch: null, pkgTarget: 'node8-macos-x64' }, + { platform: 'linux', arch: 'ia32', pkgTarget: 'node8-linux-x86' }, + { platform: 'linux', arch: 'x64', pkgTarget: 'node8-linux-x64' }, + { platform: 'linux', arch: 'armhf', pkgTarget: 'node8-linux-armv7' }, + { platform: 'linux', arch: 'alpine', pkgTarget: 'node8-linux-alpine' }, +]; + +const noop = () => { return Promise.resolve(); }; + +gulp.task('vscode-reh-win32-ia32-min', noop); +gulp.task('vscode-reh-win32-x64-min', noop); +gulp.task('vscode-reh-darwin-min', noop); +gulp.task('vscode-reh-linux-x64-min', noop); +gulp.task('vscode-reh-linux-armhf-min', noop); +gulp.task('vscode-reh-linux-alpine-min', noop); + +gulp.task('vscode-reh-web-win32-ia32-min', noop); +gulp.task('vscode-reh-web-win32-x64-min', noop); +gulp.task('vscode-reh-web-darwin-min', noop); +gulp.task('vscode-reh-web-linux-x64-min', noop); +gulp.task('vscode-reh-web-linux-alpine-min', noop); + +function getNodeVersion() { + const yarnrc = fs.readFileSync(path.join(REPO_ROOT, 'remote', '.yarnrc'), 'utf8'); + const target = /^target "(.*)"$/m.exec(yarnrc)[1]; + return target; +} + +const nodeVersion = getNodeVersion(); + +BUILD_TARGETS.forEach(({ platform, arch }) => { + if (platform === 'darwin') { + arch = 'x64'; + } + + gulp.task(task.define(`node-${platform}-${arch}`, () => { + const nodePath = path.join('.build', 'node', `v${nodeVersion}`, `${platform}-${arch}`); + + if (!fs.existsSync(nodePath)) { + util.rimraf(nodePath); + + return nodejs(platform, arch) + .pipe(vfs.dest(nodePath)); + } + + return Promise.resolve(null); + })); +}); + +const defaultNodeTask = gulp.task(`node-${process.platform}-${process.arch}`); + +if (defaultNodeTask) { + gulp.task(task.define('node', defaultNodeTask)); +} + +function nodejs(platform, arch) { + if (arch === 'ia32') { + arch = 'x86'; + } + + if (platform === 'win32') { + return remote(`/dist/v${nodeVersion}/win-${arch}/node.exe`, { base: 'https://nodejs.org' }) + .pipe(rename('node.exe')); + } + + if (arch === 'alpine') { + const contents = cp.execSync(`docker run --rm node:${nodeVersion}-alpine /bin/sh -c 'cat \`which node\`'`, { maxBuffer: 100 * 1024 * 1024, encoding: 'buffer' }); + return es.readArray([new File({ path: 'node', contents, stat: { mode: parseInt('755', 8) } })]); + } + + if (platform === 'darwin') { + arch = 'x64'; + } + + if (arch === 'armhf') { + arch = 'armv7l'; + } + + return remote(`/dist/v${nodeVersion}/node-v${nodeVersion}-${platform}-${arch}.tar.gz`, { base: 'https://nodejs.org' }) + .pipe(flatmap(stream => stream.pipe(gunzip()).pipe(untar()))) + .pipe(filter('**/node')) + .pipe(util.setExecutableBit('**')) + .pipe(rename('node')); +} + +function mixinServer(watch) { + const packageJSONPath = path.join(path.dirname(__dirname), 'package.json'); + function exec(cmdLine) { + console.log(cmdLine); + cp.execSync(cmdLine, { stdio: "inherit" }); + } + function checkout() { + const packageJSON = JSON.parse(fs.readFileSync(packageJSONPath).toString()); + exec('git fetch distro'); + exec(`git checkout ${packageJSON['distro']} -- src/vs/server resources/server`); + exec('git reset HEAD src/vs/server resources/server'); + } + checkout(); + if (watch) { + console.log('Enter watch mode (observing package.json)'); + const watcher = fs.watch(packageJSONPath); + watcher.addListener('change', () => { + try { + checkout(); + } catch (e) { + console.log(e); + } + }); + } + return Promise.resolve(); +} + +gulp.task(task.define('mixin-server', () => mixinServer(false))); +gulp.task(task.define('mixin-server-watch', () => mixinServer(true))); diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index ae37a72fc..99bd930a9 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -21,7 +21,6 @@ const json = require('gulp-json-editor'); const _ = require('underscore'); const util = require('./lib/util'); const task = require('./lib/task'); -const ext = require('./lib/extensions'); const buildfile = require('../src/buildfile'); const common = require('./lib/optimize'); const root = path.dirname(__dirname); @@ -35,6 +34,7 @@ const getElectronVersion = require('./lib/electron').getElectronVersion; const createAsar = require('./lib/asar').createAsar; const minimist = require('minimist'); const { compileBuildTask } = require('./gulpfile.compile'); +const { compileExtensionsBuildTask } = require('./gulpfile.extensions'); const productionDependencies = deps.getProductionDependencies(path.dirname(__dirname)); // @ts-ignore @@ -49,6 +49,7 @@ const nodeModules = ['electron', 'original-fs'] const vscodeEntryPoints = _.flatten([ buildfile.entrypoint('vs/workbench/workbench.main'), buildfile.base, + buildfile.serviceWorker, buildfile.workbench, buildfile.code ]); @@ -62,7 +63,7 @@ const vscodeResources = [ 'out-build/bootstrap-amd.js', 'out-build/bootstrap-window.js', 'out-build/paths.js', - 'out-build/vs/**/*.{svg,png,cur,html}', + 'out-build/vs/**/*.{svg,png,html}', '!out-build/vs/code/browser/**/*.html', 'out-build/vs/base/common/performance.js', 'out-build/vs/base/node/languagePacks.js', @@ -76,8 +77,8 @@ const vscodeResources = [ 'out-build/vs/**/markdown.css', 'out-build/vs/workbench/contrib/tasks/**/*.json', 'out-build/vs/workbench/contrib/welcome/walkThrough/**/*.md', - 'out-build/vs/workbench/services/files/**/*.exe', - 'out-build/vs/workbench/services/files/**/*.md', + 'out-build/vs/platform/files/**/*.exe', + 'out-build/vs/platform/files/**/*.md', 'out-build/vs/code/electron-browser/workbench/**', 'out-build/vs/code/electron-browser/sharedProcess/sharedProcess.js', 'out-build/vs/code/electron-browser/issue/issueReporter.js', @@ -85,47 +86,32 @@ const vscodeResources = [ '!**/test/**' ]; -const BUNDLED_FILE_HEADER = [ - '/*!--------------------------------------------------------', - ' * Copyright (C) Microsoft Corporation. All rights reserved.', - ' *--------------------------------------------------------*/' -].join('\n'); - const optimizeVSCodeTask = task.define('optimize-vscode', task.series( - task.parallel( - util.rimraf('out-vscode'), - compileBuildTask - ), + util.rimraf('out-vscode'), common.optimizeTask({ src: 'out-build', entryPoints: vscodeEntryPoints, resources: vscodeResources, loaderConfig: common.loaderConfig(nodeModules), - header: BUNDLED_FILE_HEADER, out: 'out-vscode', bundleInfo: undefined }) )); +gulp.task(optimizeVSCodeTask); - -const optimizeIndexJSTask = task.define('optimize-index-js', task.series( +const sourceMappingURLBase = `https://ticino.blob.core.windows.net/sourcemaps/${commit}`; +const minifyVSCodeTask = task.define('minify-vscode', task.series( optimizeVSCodeTask, + util.rimraf('out-vscode-min'), () => { const fullpath = path.join(process.cwd(), 'out-vscode/bootstrap-window.js'); const contents = fs.readFileSync(fullpath).toString(); const newContents = contents.replace('[/*BUILD->INSERT_NODE_MODULES*/]', JSON.stringify(nodeModules)); fs.writeFileSync(fullpath, newContents); - } -)); - -const sourceMappingURLBase = `https://ticino.blob.core.windows.net/sourcemaps/${commit}`; -const minifyVSCodeTask = task.define('minify-vscode', task.series( - task.parallel( - util.rimraf('out-vscode-min'), - optimizeIndexJSTask - ), + }, common.minifyTask('out-vscode', `${sourceMappingURLBase}/core`) )); +gulp.task(minifyVSCodeTask); // Package @@ -272,17 +258,14 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op const src = gulp.src(out + '/**', { base: '.' }) .pipe(rename(function (path) { path.dirname = path.dirname.replace(new RegExp('^' + out), 'out'); })) - .pipe(util.setExecutableBit(['**/*.sh'])) - .pipe(filter(['**', '!**/*.js.map'])); + .pipe(util.setExecutableBit(['**/*.sh'])); - const root = path.resolve(path.join(__dirname, '..')); + const extensions = gulp.src('.build/extensions/**', { base: '.build', dot: true }); - const sources = es.merge(src, ext.packageExtensionsStream({ - sourceMappingURLBase: sourceMappingURLBase - })); + const sources = es.merge(src, extensions) + .pipe(filter(['**', '!**/*.js.map'], { dot: true })); let version = packageJson.version; - // @ts-ignore JSON checking: quality is optional const quality = product.quality; if (quality && quality !== 'stable') { @@ -315,32 +298,14 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op // TODO the API should be copied to `out` during compile, not here const api = gulp.src('src/vs/vscode.d.ts').pipe(rename('out/vs/vscode.d.ts')); - const depsSrc = [ - ..._.flatten(productionDependencies.map(d => path.relative(root, d.path)).map(d => [`${d}/**`, `!${d}/**/{test,tests}/**`])), - // @ts-ignore JSON checking: dependencies is optional - ..._.flatten(Object.keys(product.dependencies || {}).map(d => [`node_modules/${d}/**`, `!node_modules/${d}/**/{test,tests}/**`])) - ]; + const telemetry = gulp.src('.build/telemetry/**', { base: '.build/telemetry', dot: true }); + + const root = path.resolve(path.join(__dirname, '..')); + const dependenciesSrc = _.flatten(productionDependencies.map(d => path.relative(root, d.path)).map(d => [`${d}/**`, `!${d}/**/{test,tests}/**`])); - const deps = gulp.src(depsSrc, { base: '.', dot: true }) + const deps = gulp.src(dependenciesSrc, { base: '.', dot: true }) .pipe(filter(['**', '!**/package-lock.json'])) - .pipe(util.cleanNodeModule('fsevents', ['binding.gyp', 'fsevents.cc', 'build/**', 'src/**', 'test/**'], ['**/*.node'])) - .pipe(util.cleanNodeModule('vscode-sqlite3', ['binding.gyp', 'benchmark/**', 'cloudformation/**', 'deps/**', 'test/**', 'build/**', 'src/**'], ['build/Release/*.node'])) - .pipe(util.cleanNodeModule('oniguruma', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['build/Release/*.node', 'src/*.js'])) - .pipe(util.cleanNodeModule('windows-mutex', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node'])) - .pipe(util.cleanNodeModule('native-keymap', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['build/Release/*.node'])) - .pipe(util.cleanNodeModule('native-is-elevated', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['build/Release/*.node'])) - .pipe(util.cleanNodeModule('native-watchdog', ['binding.gyp', 'build/**', 'src/**'], ['build/Release/*.node'])) - .pipe(util.cleanNodeModule('spdlog', ['binding.gyp', 'build/**', 'deps/**', 'src/**', 'test/**'], ['build/Release/*.node'])) - .pipe(util.cleanNodeModule('jschardet', ['dist/**'])) - .pipe(util.cleanNodeModule('windows-foreground-love', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node'])) - .pipe(util.cleanNodeModule('windows-process-tree', ['binding.gyp', 'build/**', 'src/**'], ['**/*.node'])) - .pipe(util.cleanNodeModule('gc-signals', ['binding.gyp', 'build/**', 'src/**', 'deps/**'], ['build/Release/*.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/*.exe', 'build/Release/*.dll', 'build/Release/*.node'])) - .pipe(util.cleanNodeModule('vscode-nsfw', ['binding.gyp', 'build/**', 'src/**', 'openpa/**', 'includes/**'], ['build/Release/*.node', '**/*.a'])) - .pipe(util.cleanNodeModule('vsda', ['binding.gyp', 'README.md', 'build/**', '*.bat', '*.sh', '*.cpp', '*.h'], ['build/Release/vsda.node'])) - .pipe(util.cleanNodeModule('vscode-windows-ca-certs', ['**/*'], ['package.json', '**/*.node'])) - .pipe(util.cleanNodeModule('node-addon-api', ['**/*'])) + .pipe(util.cleanNodeModules(path.join(__dirname, '.nativeignore'))) .pipe(createAsar(path.join(process.cwd(), 'node_modules'), ['**/*.node', '**/vscode-ripgrep/bin/*', '**/node-pty/build/Release/*'], 'app/node_modules.asar')); let all = es.merge( @@ -348,6 +313,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op productJsonStream, license, api, + telemetry, sources, deps ); @@ -397,7 +363,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op .pipe(util.skipDirectories()) .pipe(util.fixWin32DirectoryPermissions()) .pipe(electron(_.extend({}, config, { platform, arch, ffmpegChromium: true }))) - .pipe(filter(['**', '!LICENSE', '!LICENSES.chromium.html', '!version'])); + .pipe(filter(['**', '!LICENSE', '!LICENSES.chromium.html', '!version'], { dot: true })); // result = es.merge(result, gulp.src('resources/completions/**', { base: '.' })); @@ -414,6 +380,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op .pipe(replace('@@VERSION@@', version)) .pipe(replace('@@COMMIT@@', commit)) .pipe(replace('@@APPNAME@@', product.applicationName)) + .pipe(replace('@@DATAFOLDER@@', product.dataFolderName)) .pipe(replace('@@QUALITY@@', quality)) .pipe(rename(function (f) { f.basename = product.applicationName; f.extname = ''; }))); @@ -460,13 +427,18 @@ BUILD_TARGETS.forEach(buildTarget => { const sourceFolderName = `out-vscode${dashed(minified)}`; const destinationFolderName = `VSCode${dashed(platform)}${dashed(arch)}`; - const vscodeTask = task.define(`vscode${dashed(platform)}${dashed(arch)}${dashed(minified)}`, task.series( - task.parallel( - minified ? minifyVSCodeTask : optimizeVSCodeTask, - util.rimraf(path.join(buildRoot, destinationFolderName)) - ), + const vscodeTaskCI = task.define(`vscode${dashed(platform)}${dashed(arch)}${dashed(minified)}-ci`, task.series( + util.rimraf(path.join(buildRoot, destinationFolderName)), packageTask(platform, arch, sourceFolderName, destinationFolderName, opts) )); + gulp.task(vscodeTaskCI); + + const vscodeTask = task.define(`vscode${dashed(platform)}${dashed(arch)}${dashed(minified)}`, task.series( + compileBuildTask, + compileExtensionsBuildTask, + minified ? minifyVSCodeTask : optimizeVSCodeTask, + vscodeTaskCI + )); gulp.task(vscodeTask); }); }); @@ -495,6 +467,8 @@ const apiToken = process.env.TRANSIFEX_API_TOKEN; gulp.task(task.define( 'vscode-translations-push', task.series( + compileBuildTask, + compileExtensionsBuildTask, optimizeVSCodeTask, function () { const pathToMetadata = './out-vscode/nls.metadata.json'; @@ -514,6 +488,8 @@ gulp.task(task.define( gulp.task(task.define( 'vscode-translations-export', task.series( + compileBuildTask, + compileExtensionsBuildTask, optimizeVSCodeTask, function () { const pathToMetadata = './out-vscode/nls.metadata.json'; @@ -551,32 +527,6 @@ gulp.task('vscode-translations-import', function () { })); }); -// Sourcemaps - -gulp.task('upload-vscode-sourcemaps', () => { - const vs = gulp.src('out-vscode-min/**/*.map', { base: 'out-vscode-min' }) - .pipe(es.mapSync(f => { - f.path = `${f.base}/core/${f.relative}`; - return f; - })); - - const extensionsOut = gulp.src('extensions/**/out/**/*.map', { base: '.' }); - const extensionsDist = gulp.src('extensions/**/dist/**/*.map', { base: '.' }); - - return es.merge(vs, extensionsOut, extensionsDist) - .pipe(es.through(function (data) { - // debug - console.log('Uploading Sourcemap', data.relative); - this.emit('data', data); - })) - .pipe(azure.upload({ - account: process.env.AZURE_STORAGE_ACCOUNT, - key: process.env.AZURE_STORAGE_ACCESS_KEY, - container: 'sourcemaps', - prefix: commit + '/' - })); -}); - // This task is only run for the MacOS build const generateVSCodeConfigurationTask = task.define('generate-vscode-configuration', () => { return new Promise((resolve, reject) => { diff --git a/build/gulpfile.vscode.linux.js b/build/gulpfile.vscode.linux.js index 9b0abd18d..a718cfb00 100644 --- a/build/gulpfile.vscode.linux.js +++ b/build/gulpfile.vscode.linux.js @@ -23,7 +23,7 @@ const commit = util.getVersion(root); const linuxPackageRevision = Math.floor(new Date().getTime() / 1000); function getDebPackageArch(arch) { - return { x64: 'amd64', ia32: 'i386', arm: 'armhf', arm64: "arm64" }[arch]; + return { x64: 'amd64', arm: 'armhf', arm64: "arm64" }[arch]; } function prepareDebPackage(arch) { @@ -114,7 +114,7 @@ function getRpmBuildPath(rpmArch) { } function getRpmPackageArch(arch) { - return { x64: 'x86_64', ia32: 'i386', arm: 'armhf', arm64: "arm64" }[arch]; + return { x64: 'x86_64', arm: 'armhf', arm64: "arm64" }[arch]; } function prepareRpmPackage(arch) { @@ -238,7 +238,6 @@ function buildSnapPackage(arch) { } const BUILD_TARGETS = [ - { arch: 'ia32' }, { arch: 'x64' }, { arch: 'arm' }, { arch: 'arm64' }, diff --git a/build/gulpfile.vscode.web.js b/build/gulpfile.vscode.web.js new file mode 100644 index 000000000..11da75e48 --- /dev/null +++ b/build/gulpfile.vscode.web.js @@ -0,0 +1,151 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +const gulp = require('gulp'); +const path = require('path'); +const es = require('event-stream'); +const util = require('./lib/util'); +const task = require('./lib/task'); +const common = require('./lib/optimize'); +const product = require('../product.json'); +const rename = require('gulp-rename'); +const filter = require('gulp-filter'); +const json = require('gulp-json-editor'); +const _ = require('underscore'); +const deps = require('./dependencies'); +const vfs = require('vinyl-fs'); +const packageJson = require('../package.json'); +const { compileBuildTask } = require('./gulpfile.compile'); + +const REPO_ROOT = path.dirname(__dirname); +const commit = util.getVersion(REPO_ROOT); +const BUILD_ROOT = path.dirname(REPO_ROOT); +const WEB_FOLDER = path.join(REPO_ROOT, 'remote', 'web'); + +const productionDependencies = deps.getProductionDependencies(WEB_FOLDER); + +const nodeModules = Object.keys(product.dependencies || {}) + .concat(_.uniq(productionDependencies.map(d => d.name))); + +const vscodeWebResources = [ + + // Workbench + 'out-build/vs/{base,platform,editor,workbench}/**/*.{svg,png,html}', + 'out-build/vs/base/browser/ui/octiconLabel/octicons/**', + 'out-build/vs/**/markdown.css', + + // Webview + 'out-build/vs/workbench/contrib/webview/browser/pre/*.js', + + // Excludes + '!out-build/vs/**/{node,electron-browser,electron-main}/**', + '!out-build/vs/editor/standalone/**', + '!out-build/vs/workbench/**/*-tb.png', + '!**/test/**' +]; + +const buildfile = require('../src/buildfile'); + +const vscodeWebEntryPoints = [ + buildfile.workbenchWeb, + buildfile.serviceWorker, + buildfile.keyboardMaps, + buildfile.base +]; + +const optimizeVSCodeWebTask = task.define('optimize-vscode-web', task.series( + util.rimraf('out-vscode-web'), + common.optimizeTask({ + src: 'out-build', + entryPoints: _.flatten(vscodeWebEntryPoints), + otherSources: [], + resources: vscodeWebResources, + loaderConfig: common.loaderConfig(nodeModules), + out: 'out-vscode-web', + bundleInfo: undefined + }) +)); + +const minifyVSCodeWebTask = task.define('minify-vscode-web', task.series( + optimizeVSCodeWebTask, + util.rimraf('out-vscode-web-min'), + common.minifyTask('out-vscode-web', `https://ticino.blob.core.windows.net/sourcemaps/${commit}/core`) +)); +gulp.task(minifyVSCodeWebTask); + +function packageTask(sourceFolderName, destinationFolderName) { + const destination = path.join(BUILD_ROOT, destinationFolderName); + + return () => { + const src = gulp.src(sourceFolderName + '/**', { base: '.' }) + .pipe(rename(function (path) { path.dirname = path.dirname.replace(new RegExp('^' + sourceFolderName), 'out'); })) + .pipe(filter(['**', '!**/*.js.map'])); + + const sources = es.merge(src); + + let version = packageJson.version; + const quality = product.quality; + + if (quality && quality !== 'stable') { + version += '-' + quality; + } + + const name = product.nameShort; + const packageJsonStream = gulp.src(['remote/web/package.json'], { base: 'remote/web' }) + .pipe(json({ name, version })); + + const date = new Date().toISOString(); + + const productJsonStream = gulp.src(['product.json'], { base: '.' }) + .pipe(json({ commit, date })); + + const license = gulp.src(['remote/LICENSE'], { base: 'remote' }); + + const dependenciesSrc = _.flatten(productionDependencies.map(d => path.relative(REPO_ROOT, d.path)).map(d => [`${d}/**`, `!${d}/**/{test,tests}/**`, `!${d}/.bin/**`])); + + const deps = gulp.src(dependenciesSrc, { base: 'remote/web', dot: true }) + .pipe(filter(['**', '!**/package-lock.json'])) + .pipe(util.cleanNodeModules(path.join(__dirname, '.nativeignore'))); + + const favicon = gulp.src('resources/server/favicon.ico', { base: 'resources/server' }); + + let all = es.merge( + packageJsonStream, + productJsonStream, + license, + sources, + deps, + favicon + ); + + let result = all + .pipe(util.skipDirectories()) + .pipe(util.fixWin32DirectoryPermissions()); + + return result.pipe(vfs.dest(destination)); + }; +} + +const dashed = (str) => (str ? `-${str}` : ``); + +['', 'min'].forEach(minified => { + const sourceFolderName = `out-vscode-web${dashed(minified)}`; + const destinationFolderName = `vscode-web`; + + const vscodeWebTaskCI = task.define(`vscode-web${dashed(minified)}-ci`, task.series( + minified ? minifyVSCodeWebTask : optimizeVSCodeWebTask, + util.rimraf(path.join(BUILD_ROOT, destinationFolderName)), + packageTask(sourceFolderName, destinationFolderName) + )); + gulp.task(vscodeWebTaskCI); + + const vscodeWebTask = task.define(`vscode-web${dashed(minified)}`, task.series( + compileBuildTask, + vscodeWebTaskCI + )); + gulp.task(vscodeWebTask); +}); \ No newline at end of file diff --git a/build/gulpfile.vscode.win32.js b/build/gulpfile.vscode.win32.js index 46543316d..b20efebdb 100644 --- a/build/gulpfile.vscode.win32.js +++ b/build/gulpfile.vscode.win32.js @@ -25,7 +25,7 @@ const zipDir = arch => path.join(repoPath, '.build', `win32-${arch}`, 'archive') const zipPath = arch => path.join(zipDir(arch), `VSCode-win32-${arch}.zip`); const setupDir = (arch, target) => path.join(repoPath, '.build', `win32-${arch}`, `${target}-setup`); const issPath = path.join(__dirname, 'win32', 'code.iss'); -const innoSetupPath = path.join(path.dirname(path.dirname(require.resolve('innosetup-compiler'))), 'bin', 'ISCC.exe'); +const innoSetupPath = path.join(path.dirname(path.dirname(require.resolve('innosetup'))), 'bin', 'ISCC.exe'); const signPS1 = path.join(repoPath, 'build', 'azure-pipelines', 'win32', 'sign.ps1'); function packageInnoSetup(iss, options, cb) { diff --git a/build/lib/compilation.js b/build/lib/compilation.js index 592a5d087..62aff8735 100644 --- a/build/lib/compilation.js +++ b/build/lib/compilation.js @@ -112,7 +112,6 @@ class MonacoGenerator { this._executeSoonTimer = null; this._isWatch = isWatch; this.stream = es.through(); - this._watchers = []; this._watchedFiles = {}; let onWillReadFile = (moduleId, filePath) => { if (!this._isWatch) { @@ -122,26 +121,10 @@ class MonacoGenerator { return; } this._watchedFiles[filePath] = true; - const watcher = fs.watch(filePath); - watcher.addListener('change', () => { + fs.watchFile(filePath, () => { this._declarationResolver.invalidateCache(moduleId); this._executeSoon(); }); - watcher.addListener('error', (err) => { - console.error(`Encountered error while watching ${filePath}.`); - console.log(err); - delete this._watchedFiles[filePath]; - for (let i = 0; i < this._watchers.length; i++) { - if (this._watchers[i] === watcher) { - this._watchers.splice(i, 1); - break; - } - } - watcher.close(); - this._declarationResolver.invalidateCache(moduleId); - this._executeSoon(); - }); - this._watchers.push(watcher); }; this._fsProvider = new class extends monacodts.FSProvider { readFileSync(moduleId, filePath) { @@ -151,11 +134,9 @@ class MonacoGenerator { }; this._declarationResolver = new monacodts.DeclarationResolver(this._fsProvider); if (this._isWatch) { - const recipeWatcher = fs.watch(monacodts.RECIPE_PATH); - recipeWatcher.addListener('change', () => { + fs.watchFile(monacodts.RECIPE_PATH, () => { this._executeSoon(); }); - this._watchers.push(recipeWatcher); } } _executeSoon() { @@ -168,9 +149,6 @@ class MonacoGenerator { this.execute(); }, 20); } - dispose() { - this._watchers.forEach(watcher => watcher.close()); - } _run() { let r = monacodts.run3(this._declarationResolver); if (!r && !this._isWatch) { diff --git a/build/lib/compilation.ts b/build/lib/compilation.ts index b431a134f..f9544af9c 100644 --- a/build/lib/compilation.ts +++ b/build/lib/compilation.ts @@ -137,7 +137,6 @@ class MonacoGenerator { private readonly _isWatch: boolean; public readonly stream: NodeJS.ReadWriteStream; - private readonly _watchers: fs.FSWatcher[]; private readonly _watchedFiles: { [filePath: string]: boolean; }; private readonly _fsProvider: monacodts.FSProvider; private readonly _declarationResolver: monacodts.DeclarationResolver; @@ -145,7 +144,6 @@ class MonacoGenerator { constructor(isWatch: boolean) { this._isWatch = isWatch; this.stream = es.through(); - this._watchers = []; this._watchedFiles = {}; let onWillReadFile = (moduleId: string, filePath: string) => { if (!this._isWatch) { @@ -156,26 +154,10 @@ class MonacoGenerator { } this._watchedFiles[filePath] = true; - const watcher = fs.watch(filePath); - watcher.addListener('change', () => { + fs.watchFile(filePath, () => { this._declarationResolver.invalidateCache(moduleId); this._executeSoon(); }); - watcher.addListener('error', (err) => { - console.error(`Encountered error while watching ${filePath}.`); - console.log(err); - delete this._watchedFiles[filePath]; - for (let i = 0; i < this._watchers.length; i++) { - if (this._watchers[i] === watcher) { - this._watchers.splice(i, 1); - break; - } - } - watcher.close(); - this._declarationResolver.invalidateCache(moduleId); - this._executeSoon(); - }); - this._watchers.push(watcher); }; this._fsProvider = new class extends monacodts.FSProvider { public readFileSync(moduleId: string, filePath: string): Buffer { @@ -186,11 +168,9 @@ class MonacoGenerator { this._declarationResolver = new monacodts.DeclarationResolver(this._fsProvider); if (this._isWatch) { - const recipeWatcher = fs.watch(monacodts.RECIPE_PATH); - recipeWatcher.addListener('change', () => { + fs.watchFile(monacodts.RECIPE_PATH, () => { this._executeSoon(); }); - this._watchers.push(recipeWatcher); } } @@ -206,10 +186,6 @@ class MonacoGenerator { }, 20); } - public dispose(): void { - this._watchers.forEach(watcher => watcher.close()); - } - private _run(): monacodts.IMonacoDeclarationResult | null { let r = monacodts.run3(this._declarationResolver); if (!r && !this._isWatch) { diff --git a/build/lib/electron.js b/build/lib/electron.js index 638713367..63e867a98 100644 --- a/build/lib/electron.js +++ b/build/lib/electron.js @@ -24,7 +24,7 @@ module.exports.getElectronVersion = getElectronVersion; if (require.main === module) { const version = getElectronVersion(); const versionFile = path.join(root, '.build', 'electron', 'version'); - const isUpToDate = fs.existsSync(versionFile) && fs.readFileSync(versionFile, 'utf8') === `v${version}`; + const isUpToDate = fs.existsSync(versionFile) && fs.readFileSync(versionFile, 'utf8') === `${version}`; process.exit(isUpToDate ? 0 : 1); } diff --git a/build/lib/extensions.js b/build/lib/extensions.js index 18c668d64..73d2c7ace 100644 --- a/build/lib/extensions.js +++ b/build/lib/extensions.js @@ -13,7 +13,7 @@ const File = require("vinyl"); const vsce = require("vsce"); const stats_1 = require("./stats"); const util2 = require("./util"); -const remote = require("gulp-remote-src"); +const remote = require("gulp-remote-retry-src"); const vzip = require('gulp-vinyl-zip'); const filter = require("gulp-filter"); const rename = require("gulp-rename"); @@ -23,17 +23,20 @@ const buffer = require('gulp-buffer'); const json = require("gulp-json-editor"); const webpack = require('webpack'); const webpackGulp = require('webpack-stream'); -const root = path.resolve(path.join(__dirname, '..', '..')); -function fromLocal(extensionPath, sourceMappingURLBase) { +const util = require('./util'); +const root = path.dirname(path.dirname(__dirname)); +const commit = util.getVersion(root); +const sourceMappingURLBase = `https://ticino.blob.core.windows.net/sourcemaps/${commit}`; +function fromLocal(extensionPath) { const webpackFilename = path.join(extensionPath, 'extension.webpack.config.js'); if (fs.existsSync(webpackFilename)) { - return fromLocalWebpack(extensionPath, sourceMappingURLBase); + return fromLocalWebpack(extensionPath); } else { return fromLocalNormal(extensionPath); } } -function fromLocalWebpack(extensionPath, sourceMappingURLBase) { +function fromLocalWebpack(extensionPath) { const result = es.through(); const packagedDependencies = []; const packageJsonConfig = require(path.join(extensionPath, 'package.json')); @@ -78,7 +81,7 @@ function fromLocalWebpack(extensionPath, sourceMappingURLBase) { return data; })) .pipe(packageJsonFilter.restore); - const webpackStreams = webpackConfigLocations.map(webpackConfigPath => () => { + const webpackStreams = webpackConfigLocations.map(webpackConfigPath => { const webpackDone = (err, stats) => { fancyLog(`Bundled extension: ${ansiColors.yellow(path.join(path.basename(extensionPath), path.relative(extensionPath, webpackConfigPath)))}...`); if (err) { @@ -104,22 +107,14 @@ function fromLocalWebpack(extensionPath, sourceMappingURLBase) { // source map handling: // * rewrite sourceMappingURL // * save to disk so that upload-task picks this up - if (sourceMappingURLBase) { - const contents = data.contents.toString('utf8'); - data.contents = Buffer.from(contents.replace(/\n\/\/# sourceMappingURL=(.*)$/gm, function (_m, g1) { - return `\n//# sourceMappingURL=${sourceMappingURLBase}/extensions/${path.basename(extensionPath)}/${relativeOutputPath}/${g1}`; - }), 'utf8'); - if (/\.js\.map$/.test(data.path)) { - if (!fs.existsSync(path.dirname(data.path))) { - fs.mkdirSync(path.dirname(data.path)); - } - fs.writeFileSync(data.path, data.contents); - } - } + const contents = data.contents.toString('utf8'); + data.contents = Buffer.from(contents.replace(/\n\/\/# sourceMappingURL=(.*)$/gm, function (_m, g1) { + return `\n//# sourceMappingURL=${sourceMappingURLBase}/extensions/${path.basename(extensionPath)}/${relativeOutputPath}/${g1}`; + }), 'utf8'); this.emit('data', data); })); }); - es.merge(sequence(webpackStreams), patchFilesStream) + es.merge(...webpackStreams, patchFilesStream) // .pipe(es.through(function (data) { // // debug // console.log('out', data.path, data.contents.length); @@ -185,30 +180,7 @@ const excludedExtensions = [ 'ms-vscode.node-debug2', ]; const builtInExtensions = require('../builtInExtensions.json'); -/** - * We're doing way too much stuff at once, with webpack et al. So much stuff - * that while downloading extensions from the marketplace, node js doesn't get enough - * stack frames to complete the download in under 2 minutes, at which point the - * marketplace server cuts off the http request. So, we sequentialize the extensino tasks. - */ -function sequence(streamProviders) { - const result = es.through(); - function pop() { - if (streamProviders.length === 0) { - result.emit('end'); - } - else { - const fn = streamProviders.shift(); - fn() - .on('end', function () { setTimeout(pop, 0); }) - .pipe(result, { end: false }); - } - } - pop(); - return result; -} -function packageExtensionsStream(optsIn) { - const opts = optsIn || {}; +function packageLocalExtensionsStream() { const localExtensionDescriptions = glob.sync('extensions/*/package.json') .map(manifestPath => { const extensionPath = path.dirname(path.join(root, manifestPath)); @@ -216,21 +188,22 @@ function packageExtensionsStream(optsIn) { return { name: extensionName, path: extensionPath }; }) .filter(({ name }) => excludedExtensions.indexOf(name) === -1) - .filter(({ name }) => opts.desiredExtensions ? opts.desiredExtensions.indexOf(name) >= 0 : true) .filter(({ name }) => builtInExtensions.every(b => b.name !== name)); - const localExtensions = () => sequence([...localExtensionDescriptions.map(extension => () => { - return fromLocal(extension.path, opts.sourceMappingURLBase) - .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); - })]); - const localExtensionDependencies = () => gulp.src('extensions/node_modules/**', { base: '.' }); - const marketplaceExtensions = () => es.merge(...builtInExtensions - .filter(({ name }) => opts.desiredExtensions ? opts.desiredExtensions.indexOf(name) >= 0 : true) - .map(extension => { + const nodeModules = gulp.src('extensions/node_modules/**', { base: '.' }); + const localExtensions = localExtensionDescriptions.map(extension => { + return fromLocal(extension.path) + .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); + }); + return es.merge(nodeModules, ...localExtensions) + .pipe(util2.setExecutableBit(['**/*.sh'])); +} +exports.packageLocalExtensionsStream = packageLocalExtensionsStream; +function packageMarketplaceExtensionsStream() { + const extensions = builtInExtensions.map(extension => { return fromMarketplace(extension.name, extension.version, extension.metadata) .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); - })); - return sequence([localExtensions, localExtensionDependencies, marketplaceExtensions]) - .pipe(util2.setExecutableBit(['**/*.sh'])) - .pipe(filter(['**', '!**/*.js.map'])); + }); + return es.merge(extensions) + .pipe(util2.setExecutableBit(['**/*.sh'])); } -exports.packageExtensionsStream = packageExtensionsStream; +exports.packageMarketplaceExtensionsStream = packageMarketplaceExtensionsStream; diff --git a/build/lib/extensions.ts b/build/lib/extensions.ts index 188deaf1a..4b185aff6 100644 --- a/build/lib/extensions.ts +++ b/build/lib/extensions.ts @@ -13,7 +13,7 @@ import * as File from 'vinyl'; import * as vsce from 'vsce'; import { createStatsStream } from './stats'; import * as util2 from './util'; -import remote = require('gulp-remote-src'); +import remote = require('gulp-remote-retry-src'); const vzip = require('gulp-vinyl-zip'); import filter = require('gulp-filter'); import rename = require('gulp-rename'); @@ -23,19 +23,21 @@ const buffer = require('gulp-buffer'); import json = require('gulp-json-editor'); const webpack = require('webpack'); const webpackGulp = require('webpack-stream'); +const util = require('./util'); +const root = path.dirname(path.dirname(__dirname)); +const commit = util.getVersion(root); +const sourceMappingURLBase = `https://ticino.blob.core.windows.net/sourcemaps/${commit}`; -const root = path.resolve(path.join(__dirname, '..', '..')); - -function fromLocal(extensionPath: string, sourceMappingURLBase?: string): Stream { +function fromLocal(extensionPath: string): Stream { const webpackFilename = path.join(extensionPath, 'extension.webpack.config.js'); if (fs.existsSync(webpackFilename)) { - return fromLocalWebpack(extensionPath, sourceMappingURLBase); + return fromLocalWebpack(extensionPath); } else { return fromLocalNormal(extensionPath); } } -function fromLocalWebpack(extensionPath: string, sourceMappingURLBase: string | undefined): Stream { +function fromLocalWebpack(extensionPath: string): Stream { const result = es.through(); const packagedDependencies: string[] = []; @@ -91,7 +93,7 @@ function fromLocalWebpack(extensionPath: string, sourceMappingURLBase: string | .pipe(packageJsonFilter.restore); - const webpackStreams = webpackConfigLocations.map(webpackConfigPath => () => { + const webpackStreams = webpackConfigLocations.map(webpackConfigPath => { const webpackDone = (err: any, stats: any) => { fancyLog(`Bundled extension: ${ansiColors.yellow(path.join(path.basename(extensionPath), path.relative(extensionPath, webpackConfigPath)))}...`); @@ -123,24 +125,16 @@ function fromLocalWebpack(extensionPath: string, sourceMappingURLBase: string | // source map handling: // * rewrite sourceMappingURL // * save to disk so that upload-task picks this up - if (sourceMappingURLBase) { - const contents = (data.contents).toString('utf8'); - data.contents = Buffer.from(contents.replace(/\n\/\/# sourceMappingURL=(.*)$/gm, function (_m, g1) { - return `\n//# sourceMappingURL=${sourceMappingURLBase}/extensions/${path.basename(extensionPath)}/${relativeOutputPath}/${g1}`; - }), 'utf8'); - - if (/\.js\.map$/.test(data.path)) { - if (!fs.existsSync(path.dirname(data.path))) { - fs.mkdirSync(path.dirname(data.path)); - } - fs.writeFileSync(data.path, data.contents); - } - } + const contents = (data.contents).toString('utf8'); + data.contents = Buffer.from(contents.replace(/\n\/\/# sourceMappingURL=(.*)$/gm, function (_m, g1) { + return `\n//# sourceMappingURL=${sourceMappingURLBase}/extensions/${path.basename(extensionPath)}/${relativeOutputPath}/${g1}`; + }), 'utf8'); + this.emit('data', data); })); }); - es.merge(sequence(webpackStreams), patchFilesStream) + es.merge(...webpackStreams, patchFilesStream) // .pipe(es.through(function (data) { // // debug // console.log('out', data.path, data.contents.length); @@ -210,14 +204,6 @@ export function fromMarketplace(extensionName: string, version: string, metadata .pipe(packageJsonFilter.restore); } -interface IPackageExtensionsOptions { - /** - * Set to undefined to package all of them. - */ - desiredExtensions?: string[]; - sourceMappingURLBase?: string; -} - const excludedExtensions = [ 'vscode-api-tests', 'vscode-colorize-tests', @@ -235,33 +221,7 @@ interface IBuiltInExtension { const builtInExtensions: IBuiltInExtension[] = require('../builtInExtensions.json'); -/** - * We're doing way too much stuff at once, with webpack et al. So much stuff - * that while downloading extensions from the marketplace, node js doesn't get enough - * stack frames to complete the download in under 2 minutes, at which point the - * marketplace server cuts off the http request. So, we sequentialize the extensino tasks. - */ -function sequence(streamProviders: { (): Stream }[]): Stream { - const result = es.through(); - - function pop() { - if (streamProviders.length === 0) { - result.emit('end'); - } else { - const fn = streamProviders.shift()!; - fn() - .on('end', function () { setTimeout(pop, 0); }) - .pipe(result, { end: false }); - } - } - - pop(); - return result; -} - -export function packageExtensionsStream(optsIn?: IPackageExtensionsOptions): NodeJS.ReadWriteStream { - const opts = optsIn || {}; - +export function packageLocalExtensionsStream(): NodeJS.ReadWriteStream { const localExtensionDescriptions = (glob.sync('extensions/*/package.json')) .map(manifestPath => { const extensionPath = path.dirname(path.join(root, manifestPath)); @@ -269,26 +229,24 @@ export function packageExtensionsStream(optsIn?: IPackageExtensionsOptions): Nod return { name: extensionName, path: extensionPath }; }) .filter(({ name }) => excludedExtensions.indexOf(name) === -1) - .filter(({ name }) => opts.desiredExtensions ? opts.desiredExtensions.indexOf(name) >= 0 : true) .filter(({ name }) => builtInExtensions.every(b => b.name !== name)); - const localExtensions = () => sequence([...localExtensionDescriptions.map(extension => () => { - return fromLocal(extension.path, opts.sourceMappingURLBase) + const nodeModules = gulp.src('extensions/node_modules/**', { base: '.' }); + const localExtensions = localExtensionDescriptions.map(extension => { + return fromLocal(extension.path) .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); - })]); - - const localExtensionDependencies = () => gulp.src('extensions/node_modules/**', { base: '.' }); - - const marketplaceExtensions = () => es.merge( - ...builtInExtensions - .filter(({ name }) => opts.desiredExtensions ? opts.desiredExtensions.indexOf(name) >= 0 : true) - .map(extension => { - return fromMarketplace(extension.name, extension.version, extension.metadata) - .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); - }) - ); - - return sequence([localExtensions, localExtensionDependencies, marketplaceExtensions]) - .pipe(util2.setExecutableBit(['**/*.sh'])) - .pipe(filter(['**', '!**/*.js.map'])); + }); + + return es.merge(nodeModules, ...localExtensions) + .pipe(util2.setExecutableBit(['**/*.sh'])); +} + +export function packageMarketplaceExtensionsStream(): NodeJS.ReadWriteStream { + const extensions = builtInExtensions.map(extension => { + return fromMarketplace(extension.name, extension.version, extension.metadata) + .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); + }); + + return es.merge(extensions) + .pipe(util2.setExecutableBit(['**/*.sh'])); } diff --git a/build/lib/i18n.resources.json b/build/lib/i18n.resources.json index ac557db62..32b0e6fb4 100644 --- a/build/lib/i18n.resources.json +++ b/build/lib/i18n.resources.json @@ -38,10 +38,6 @@ "name": "vs/workbench/contrib/codeEditor", "project": "vscode-workbench" }, - { - "name": "vs/workbench/contrib/codeinset", - "project": "vscode-workbench" - }, { "name": "vs/workbench/contrib/callHierarchy", "project": "vscode-workbench" @@ -110,6 +106,10 @@ "name": "vs/workbench/contrib/quickopen", "project": "vscode-workbench" }, + { + "name": "vs/workbench/contrib/remote", + "project": "vscode-workbench" + }, { "name": "vs/workbench/contrib/relauncher", "project": "vscode-workbench" diff --git a/build/lib/i18n.ts b/build/lib/i18n.ts index ee75ac1ec..9f53df17b 100644 --- a/build/lib/i18n.ts +++ b/build/lib/i18n.ts @@ -25,7 +25,7 @@ function log(message: any, ...rest: any[]): void { export interface Language { id: string; // language id, e.g. zh-tw, de - translationId?: string; // language id used in translation tools, e.g zh-hant, de (optional, if not set, the id is used) + translationId?: string; // language id used in translation tools, e.g. zh-hant, de (optional, if not set, the id is used) folderName?: string; // language specific folder name, e.g. cht, deu (optional, if not set, the id is used) } diff --git a/build/lib/node.js b/build/lib/node.js new file mode 100644 index 000000000..403ae3d96 --- /dev/null +++ b/build/lib/node.js @@ -0,0 +1,15 @@ +"use strict"; +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +Object.defineProperty(exports, "__esModule", { value: true }); +const path = require("path"); +const fs = require("fs"); +const root = path.dirname(path.dirname(__dirname)); +const yarnrcPath = path.join(root, 'remote', '.yarnrc'); +const yarnrc = fs.readFileSync(yarnrcPath, 'utf8'); +const version = /^target\s+"([^"]+)"$/m.exec(yarnrc)[1]; +const node = process.platform === 'win32' ? 'node.exe' : 'node'; +const nodePath = path.join(root, '.build', 'node', `v${version}`, `${process.platform}-${process.arch}`, node); +console.log(nodePath); diff --git a/build/lib/node.ts b/build/lib/node.ts new file mode 100644 index 000000000..643970344 --- /dev/null +++ b/build/lib/node.ts @@ -0,0 +1,16 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as path from 'path'; +import * as fs from 'fs'; + +const root = path.dirname(path.dirname(__dirname)); +const yarnrcPath = path.join(root, 'remote', '.yarnrc'); +const yarnrc = fs.readFileSync(yarnrcPath, 'utf8'); +const version = /^target\s+"([^"]+)"$/m.exec(yarnrc)![1]; +const node = process.platform === 'win32' ? 'node.exe' : 'node'; +const nodePath = path.join(root, '.build', 'node', `v${version}`, `${process.platform}-${process.arch}`, node); + +console.log(nodePath); \ No newline at end of file diff --git a/build/lib/optimize.js b/build/lib/optimize.js index e4783e185..2b59d9268 100644 --- a/build/lib/optimize.js +++ b/build/lib/optimize.js @@ -111,12 +111,17 @@ function toBundleStream(src, bundledFileHeader, bundles) { return toConcatStream(src, bundledFileHeader, bundle.sources, bundle.dest); })); } +const DEFAULT_FILE_HEADER = [ + '/*!--------------------------------------------------------', + ' * Copyright (C) Microsoft Corporation. All rights reserved.', + ' *--------------------------------------------------------*/' +].join('\n'); function optimizeTask(opts) { const src = opts.src; const entryPoints = opts.entryPoints; const resources = opts.resources; const loaderConfig = opts.loaderConfig; - const bundledFileHeader = opts.header; + const bundledFileHeader = opts.header || DEFAULT_FILE_HEADER; const bundleLoader = (typeof opts.bundleLoader === 'undefined' ? true : opts.bundleLoader); const out = opts.out; return function () { diff --git a/build/lib/optimize.ts b/build/lib/optimize.ts index d15659ca6..6bf1233c3 100644 --- a/build/lib/optimize.ts +++ b/build/lib/optimize.ts @@ -154,7 +154,7 @@ export interface IOptimizeTaskOpts { /** * (basically the Copyright treatment) */ - header: string; + header?: string; /** * (emit bundleInfo.json file) */ @@ -169,12 +169,18 @@ export interface IOptimizeTaskOpts { languages?: Language[]; } +const DEFAULT_FILE_HEADER = [ + '/*!--------------------------------------------------------', + ' * Copyright (C) Microsoft Corporation. All rights reserved.', + ' *--------------------------------------------------------*/' +].join('\n'); + export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStream { const src = opts.src; const entryPoints = opts.entryPoints; const resources = opts.resources; const loaderConfig = opts.loaderConfig; - const bundledFileHeader = opts.header; + const bundledFileHeader = opts.header || DEFAULT_FILE_HEADER; const bundleLoader = (typeof opts.bundleLoader === 'undefined' ? true : opts.bundleLoader); const out = opts.out; diff --git a/build/lib/standalone.js b/build/lib/standalone.js index 63e16442d..7e363da09 100644 --- a/build/lib/standalone.js +++ b/build/lib/standalone.js @@ -31,6 +31,7 @@ function extractEditor(options) { let compilerOptions; if (tsConfig.extends) { compilerOptions = Object.assign({}, require(path.join(options.sourcesRoot, tsConfig.extends)).compilerOptions, tsConfig.compilerOptions); + delete tsConfig.extends; } else { compilerOptions = tsConfig.compilerOptions; @@ -42,6 +43,7 @@ function extractEditor(options) { compilerOptions.declaration = false; compilerOptions.moduleResolution = ts.ModuleResolutionKind.Classic; options.compilerOptions = compilerOptions; + console.log(`Running with shakeLevel ${tss.toStringShakeLevel(options.shakeLevel)}`); let result = tss.shake(options); for (let fileName in result) { if (result.hasOwnProperty(fileName)) { diff --git a/build/lib/standalone.ts b/build/lib/standalone.ts index dfd3c99fe..6a4cdbf77 100644 --- a/build/lib/standalone.ts +++ b/build/lib/standalone.ts @@ -35,6 +35,7 @@ export function extractEditor(options: tss.ITreeShakingOptions & { destRoot: str let compilerOptions: { [key: string]: any }; if (tsConfig.extends) { compilerOptions = Object.assign({}, require(path.join(options.sourcesRoot, tsConfig.extends)).compilerOptions, tsConfig.compilerOptions); + delete tsConfig.extends; } else { compilerOptions = tsConfig.compilerOptions; } @@ -49,6 +50,8 @@ export function extractEditor(options: tss.ITreeShakingOptions & { destRoot: str options.compilerOptions = compilerOptions; + console.log(`Running with shakeLevel ${tss.toStringShakeLevel(options.shakeLevel)}`); + let result = tss.shake(options); for (let fileName in result) { if (result.hasOwnProperty(fileName)) { diff --git a/build/lib/test/i18n.test.js b/build/lib/test/i18n.test.js index 298104865..3dd104259 100644 --- a/build/lib/test/i18n.test.js +++ b/build/lib/test/i18n.test.js @@ -27,14 +27,14 @@ suite('XLF Parser Tests', () => { }); test('JSON file source path to Transifex resource match', () => { const editorProject = 'vscode-editor', workbenchProject = 'vscode-workbench'; - const platform = { name: 'vs/platform', project: editorProject }, editorContrib = { name: 'vs/editor/contrib', project: editorProject }, editor = { name: 'vs/editor', project: editorProject }, base = { name: 'vs/base', project: editorProject }, code = { name: 'vs/code', project: workbenchProject }, workbenchParts = { name: 'vs/workbench/contrib/html', project: workbenchProject }, workbenchServices = { name: 'vs/workbench/services/files', project: workbenchProject }, workbench = { name: 'vs/workbench', project: workbenchProject }; + const platform = { name: 'vs/platform', project: editorProject }, editorContrib = { name: 'vs/editor/contrib', project: editorProject }, editor = { name: 'vs/editor', project: editorProject }, base = { name: 'vs/base', project: editorProject }, code = { name: 'vs/code', project: workbenchProject }, workbenchParts = { name: 'vs/workbench/contrib/html', project: workbenchProject }, workbenchServices = { name: 'vs/workbench/services/textfile', project: workbenchProject }, workbench = { name: 'vs/workbench', project: workbenchProject }; assert.deepEqual(i18n.getResource('vs/platform/actions/browser/menusExtensionPoint'), platform); assert.deepEqual(i18n.getResource('vs/editor/contrib/clipboard/browser/clipboard'), editorContrib); assert.deepEqual(i18n.getResource('vs/editor/common/modes/modesRegistry'), editor); assert.deepEqual(i18n.getResource('vs/base/common/errorMessage'), base); assert.deepEqual(i18n.getResource('vs/code/electron-main/window'), code); assert.deepEqual(i18n.getResource('vs/workbench/contrib/html/browser/webview'), workbenchParts); - assert.deepEqual(i18n.getResource('vs/workbench/services/files/node/fileService'), workbenchServices); + assert.deepEqual(i18n.getResource('vs/workbench/services/textfile/node/testFileService'), workbenchServices); assert.deepEqual(i18n.getResource('vs/workbench/browser/parts/panel/panelActions'), workbench); }); }); diff --git a/build/lib/test/i18n.test.ts b/build/lib/test/i18n.test.ts index eebc77424..29a0f6657 100644 --- a/build/lib/test/i18n.test.ts +++ b/build/lib/test/i18n.test.ts @@ -39,7 +39,7 @@ suite('XLF Parser Tests', () => { base = { name: 'vs/base', project: editorProject }, code = { name: 'vs/code', project: workbenchProject }, workbenchParts = { name: 'vs/workbench/contrib/html', project: workbenchProject }, - workbenchServices = { name: 'vs/workbench/services/files', project: workbenchProject }, + workbenchServices = { name: 'vs/workbench/services/textfile', project: workbenchProject }, workbench = { name: 'vs/workbench', project: workbenchProject}; assert.deepEqual(i18n.getResource('vs/platform/actions/browser/menusExtensionPoint'), platform); @@ -48,7 +48,7 @@ suite('XLF Parser Tests', () => { assert.deepEqual(i18n.getResource('vs/base/common/errorMessage'), base); assert.deepEqual(i18n.getResource('vs/code/electron-main/window'), code); assert.deepEqual(i18n.getResource('vs/workbench/contrib/html/browser/webview'), workbenchParts); - assert.deepEqual(i18n.getResource('vs/workbench/services/files/node/fileService'), workbenchServices); + assert.deepEqual(i18n.getResource('vs/workbench/services/textfile/node/testFileService'), workbenchServices); assert.deepEqual(i18n.getResource('vs/workbench/browser/parts/panel/panelActions'), workbench); }); }); \ No newline at end of file diff --git a/build/lib/treeshaking.js b/build/lib/treeshaking.js index da51ac191..50ff7caa0 100644 --- a/build/lib/treeshaking.js +++ b/build/lib/treeshaking.js @@ -14,6 +14,17 @@ var ShakeLevel; ShakeLevel[ShakeLevel["InnerFile"] = 1] = "InnerFile"; ShakeLevel[ShakeLevel["ClassMembers"] = 2] = "ClassMembers"; })(ShakeLevel = exports.ShakeLevel || (exports.ShakeLevel = {})); +function toStringShakeLevel(shakeLevel) { + switch (shakeLevel) { + case 0 /* Files */: + return 'Files (0)'; + case 1 /* InnerFile */: + return 'InnerFile (1)'; + case 2 /* ClassMembers */: + return 'ClassMembers (2)'; + } +} +exports.toStringShakeLevel = toStringShakeLevel; function printDiagnostics(diagnostics) { for (const diag of diagnostics) { let result = ''; @@ -394,6 +405,7 @@ function markNodes(languageService, options) { || memberName === 'toJSON' || memberName === 'toString' || memberName === 'dispose' // TODO: keeping all `dispose` methods + || /^_(.*)Brand$/.test(memberName || '') // TODO: keeping all members ending with `Brand`... ) { enqueue_black(member); } @@ -513,10 +525,6 @@ function generateResult(languageService, shakeLevel) { // keep method continue; } - if (/^_(.*)Brand$/.test(member.name.getText())) { - // TODO: keep all members ending with `Brand`... - continue; - } let pos = member.pos - node.pos; let end = member.end - node.pos; toWrite = toWrite.substring(0, pos) + toWrite.substring(end); diff --git a/build/lib/treeshaking.ts b/build/lib/treeshaking.ts index 060808312..f09696336 100644 --- a/build/lib/treeshaking.ts +++ b/build/lib/treeshaking.ts @@ -17,6 +17,17 @@ export const enum ShakeLevel { ClassMembers = 2 } +export function toStringShakeLevel(shakeLevel: ShakeLevel): string { + switch(shakeLevel) { + case ShakeLevel.Files: + return 'Files (0)'; + case ShakeLevel.InnerFile: + return 'InnerFile (1)'; + case ShakeLevel.ClassMembers: + return 'ClassMembers (2)'; + } +} + export interface ITreeShakingOptions { /** * The full path to the root where sources are. @@ -513,6 +524,7 @@ function markNodes(languageService: ts.LanguageService, options: ITreeShakingOpt || memberName === 'toJSON' || memberName === 'toString' || memberName === 'dispose'// TODO: keeping all `dispose` methods + || /^_(.*)Brand$/.test(memberName || '') // TODO: keeping all members ending with `Brand`... ) { enqueue_black(member); } @@ -642,10 +654,6 @@ function generateResult(languageService: ts.LanguageService, shakeLevel: ShakeLe // keep method continue; } - if (/^_(.*)Brand$/.test(member.name.getText())) { - // TODO: keep all members ending with `Brand`... - continue; - } let pos = member.pos - node.pos; let end = member.end - node.pos; diff --git a/build/lib/typings/gulp-remote-src.d.ts b/build/lib/typings/gulp-remote-src.d.ts index 6ea57f84f..ff9026b79 100644 --- a/build/lib/typings/gulp-remote-src.d.ts +++ b/build/lib/typings/gulp-remote-src.d.ts @@ -1,4 +1,4 @@ -declare module 'gulp-remote-src' { +declare module 'gulp-remote-retry-src' { import stream = require("stream"); @@ -20,4 +20,4 @@ declare module 'gulp-remote-src' { } export = remote; -} \ No newline at end of file +} diff --git a/build/lib/util.js b/build/lib/util.js index 34ee13695..be2670261 100644 --- a/build/lib/util.js +++ b/build/lib/util.js @@ -8,14 +8,11 @@ const es = require("event-stream"); const debounce = require("debounce"); const _filter = require("gulp-filter"); const rename = require("gulp-rename"); -const _ = require("underscore"); const path = require("path"); const fs = require("fs"); const _rimraf = require("rimraf"); const git = require("./git"); const VinylFile = require("vinyl"); -const download_1 = require("../download/download"); -const REPO_ROOT = path.join(__dirname, '../../'); const NoCancellationToken = { isCancellationRequested: () => false }; function incremental(streamProvider, initial, supportsCancellation) { const input = es.through(); @@ -69,6 +66,9 @@ function fixWin32DirectoryPermissions() { exports.fixWin32DirectoryPermissions = fixWin32DirectoryPermissions; function setExecutableBit(pattern) { const setBit = es.mapSync(f => { + if (!f.stat) { + f.stat = { isFile() { return true; } }; + } f.stat.mode = /* 100755 */ 33261; return f; }); @@ -100,22 +100,18 @@ function skipDirectories() { }); } exports.skipDirectories = skipDirectories; -function cleanNodeModule(name, excludes, includes) { - const toGlob = (path) => '**/node_modules/' + name + (path ? '/' + path : ''); - const negate = (str) => '!' + str; - const allFilter = _filter(toGlob('**'), { restore: true }); - const globs = [toGlob('**')].concat(excludes.map(_.compose(negate, toGlob))); +function cleanNodeModules(rulePath) { + const rules = fs.readFileSync(rulePath, 'utf8') + .split(/\r?\n/g) + .map(line => line.trim()) + .filter(line => line && !/^#/.test(line)); + const excludes = rules.filter(line => !/^!/.test(line)).map(line => `!**/node_modules/${line}`); + const includes = rules.filter(line => /^!/.test(line)).map(line => `**/node_modules/${line.substr(1)}`); const input = es.through(); - const nodeModuleInput = input.pipe(allFilter); - let output = nodeModuleInput.pipe(_filter(globs)); - if (includes) { - const includeGlobs = includes.map(toGlob); - output = es.merge(output, nodeModuleInput.pipe(_filter(includeGlobs))); - } - output = output.pipe(allFilter.restore); + const output = es.merge(input.pipe(_filter(['**', ...excludes])), input.pipe(_filter(includes))); return es.duplex(input, output); } -exports.cleanNodeModule = cleanNodeModule; +exports.cleanNodeModules = cleanNodeModules; function loadSourcemaps() { const input = es.through(); const output = input @@ -182,7 +178,7 @@ function rimraf(dir) { return cb(err); }); }; - retry.taskName = `clean-${path.basename(dir)}`; + retry.taskName = `clean-${path.basename(dir).toLowerCase()}`; return retry; } exports.rimraf = rimraf; @@ -223,38 +219,3 @@ function versionStringToNumber(versionStr) { return parseInt(match[1], 10) * 1e4 + parseInt(match[2], 10) * 1e2 + parseInt(match[3], 10); } exports.versionStringToNumber = versionStringToNumber; -function download(requestOptions) { - const result = es.through(); - const filename = path.join(REPO_ROOT, `.build/tmp-${Date.now()}-${path.posix.basename(requestOptions.path)}`); - const opts = { - requestOptions: requestOptions, - destinationPath: filename - }; - download_1.downloadInExternalProcess(opts).then(() => { - fs.stat(filename, (err, stat) => { - if (err) { - result.emit('error', err); - return; - } - fs.readFile(filename, (err, data) => { - if (err) { - result.emit('error', err); - return; - } - fs.unlink(filename, () => { - result.emit('data', new VinylFile({ - path: path.normalize(requestOptions.path), - stat: stat, - base: path.normalize(requestOptions.path), - contents: data - })); - result.emit('end'); - }); - }); - }); - }, (err) => { - result.emit('error', err); - }); - return result; -} -exports.download = download; diff --git a/build/lib/util.ts b/build/lib/util.ts index 44ac9d0dc..578271e66 100644 --- a/build/lib/util.ts +++ b/build/lib/util.ts @@ -17,9 +17,6 @@ import * as git from './git'; import * as VinylFile from 'vinyl'; import { ThroughStream } from 'through'; import * as sm from 'source-map'; -import { IDownloadOptions, downloadInExternalProcess, IDownloadRequestOptions } from '../download/download'; - -const REPO_ROOT = path.join(__dirname, '../../'); export interface ICancellationToken { isCancellationRequested(): boolean; @@ -96,6 +93,9 @@ export function fixWin32DirectoryPermissions(): NodeJS.ReadWriteStream { export function setExecutableBit(pattern?: string | string[]): NodeJS.ReadWriteStream { const setBit = es.mapSync(f => { + if (!f.stat) { + f.stat = { isFile() { return true; } } as any; + } f.stat.mode = /* 100755 */ 33261; return f; }); @@ -132,23 +132,21 @@ export function skipDirectories(): NodeJS.ReadWriteStream { }); } -export function cleanNodeModule(name: string, excludes: string[], includes?: string[]): NodeJS.ReadWriteStream { - const toGlob = (path: string) => '**/node_modules/' + name + (path ? '/' + path : ''); - const negate = (str: string) => '!' + str; +export function cleanNodeModules(rulePath: string): NodeJS.ReadWriteStream { + const rules = fs.readFileSync(rulePath, 'utf8') + .split(/\r?\n/g) + .map(line => line.trim()) + .filter(line => line && !/^#/.test(line)); - const allFilter = _filter(toGlob('**'), { restore: true }); - const globs = [toGlob('**')].concat(excludes.map(_.compose(negate, toGlob) as (x: string) => string)); + const excludes = rules.filter(line => !/^!/.test(line)).map(line => `!**/node_modules/${line}`); + const includes = rules.filter(line => /^!/.test(line)).map(line => `**/node_modules/${line.substr(1)}`); const input = es.through(); - const nodeModuleInput = input.pipe(allFilter); - let output: NodeJS.ReadWriteStream = nodeModuleInput.pipe(_filter(globs)); - - if (includes) { - const includeGlobs = includes.map(toGlob); - output = es.merge(output, nodeModuleInput.pipe(_filter(includeGlobs))); - } + const output = es.merge( + input.pipe(_filter(['**', ...excludes])), + input.pipe(_filter(includes)) + ); - output = output.pipe(allFilter.restore); return es.duplex(input, output); } @@ -236,7 +234,7 @@ export function rimraf(dir: string): (cb: any) => void { return cb(err); }); }; - retry.taskName = `clean-${path.basename(dir)}`; + retry.taskName = `clean-${path.basename(dir).toLowerCase()}`; return retry; } @@ -283,38 +281,3 @@ export function versionStringToNumber(versionStr: string) { return parseInt(match[1], 10) * 1e4 + parseInt(match[2], 10) * 1e2 + parseInt(match[3], 10); } - -export function download(requestOptions: IDownloadRequestOptions): NodeJS.ReadWriteStream { - const result = es.through(); - const filename = path.join(REPO_ROOT, `.build/tmp-${Date.now()}-${path.posix.basename(requestOptions.path)}`); - const opts: IDownloadOptions = { - requestOptions: requestOptions, - destinationPath: filename - }; - downloadInExternalProcess(opts).then(() => { - fs.stat(filename, (err, stat) => { - if (err) { - result.emit('error', err); - return; - } - fs.readFile(filename, (err, data) => { - if (err) { - result.emit('error', err); - return; - } - fs.unlink(filename, () => { - result.emit('data', new VinylFile({ - path: path.normalize(requestOptions.path), - stat: stat, - base: path.normalize(requestOptions.path), - contents: data - })); - result.emit('end'); - }); - }); - }); - }, (err) => { - result.emit('error', err); - }); - return result; -} diff --git a/build/lib/watch/package.json b/build/lib/watch/package.json index 0d0313401..b26f589ce 100644 --- a/build/lib/watch/package.json +++ b/build/lib/watch/package.json @@ -4,7 +4,8 @@ "description": "", "author": "Microsoft ", "private": true, + "license": "MIT", "devDependencies": { - "gulp-watch": "^4.3.9" + "gulp-watch": "5.0.1" } } diff --git a/build/lib/watch/yarn.lock b/build/lib/watch/yarn.lock index 0f2ac1e20..f7d5d976b 100644 --- a/build/lib/watch/yarn.lock +++ b/build/lib/watch/yarn.lock @@ -7,23 +7,29 @@ abbrev@1: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== -ajv@^4.9.1: - version "4.11.8" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" - integrity sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY= +ansi-colors@1.1.0, ansi-colors@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-1.1.0.tgz#6374b4dd5d4718ff3ce27a671a3b1cad077132a9" + integrity sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA== + dependencies: + ansi-wrap "^0.1.0" + +ansi-gray@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-gray/-/ansi-gray-0.1.1.tgz#2962cf54ec9792c48510a3deb524436861ef7251" + integrity sha1-KWLPVOyXksSFEKPetSRDaGHvclE= dependencies: - co "^4.6.0" - json-stable-stringify "^1.0.1" + ansi-wrap "0.1.0" ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= +ansi-wrap@0.1.0, ansi-wrap@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" + integrity sha1-qCJQ3bABXponyoLoLqYDu/pF768= anymatch@^1.3.0: version "1.3.2" @@ -33,6 +39,14 @@ anymatch@^1.3.0: micromatch "^2.1.5" normalize-path "^2.0.0" +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + aproba@^1.0.3: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" @@ -53,97 +67,69 @@ arr-diff@^2.0.0: dependencies: arr-flatten "^1.0.1" -arr-flatten@^1.0.1: +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= + +arr-flatten@^1.0.1, arr-flatten@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== -array-differ@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031" - integrity sha1-7/UuN1gknTO+QCuLuOVkuytdQDE= - -array-uniq@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" - integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= array-unique@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" integrity sha1-odl8yvy8JiXMcPrc6zalDFiwGlM= -asn1@~0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" - integrity sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y= +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= -assert-plus@1.0.0, assert-plus@^1.0.0: +assign-symbols@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= - -assert-plus@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" - integrity sha1-104bh+ev/A24qttwIfP+SBAasjQ= - -async-each@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" - integrity sha1-GdOGodntxufByF04iu28xW0zYC0= - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= -aws-sign2@~0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" - integrity sha1-FDQt0428yU0OW4fXY81jYSwOeU8= +async-each@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" + integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== -aws4@^1.2.1: - version "1.6.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" - integrity sha1-g+9cqGCysy5KDe7e6MdxudtXRx4= +atob@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= -bcrypt-pbkdf@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" - integrity sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40= +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== dependencies: - tweetnacl "^0.14.3" - -beeper@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/beeper/-/beeper-1.1.1.tgz#e6d5ea8c5dad001304a70b22638447f69cb2f809" - integrity sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak= + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" binary-extensions@^1.0.0: version "1.10.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.10.0.tgz#9aeb9a6c5e88638aad171e167f5900abe24835d0" integrity sha1-muuabF6IY4qtFx4Wf1kAq+JINdA= -block-stream@*: - version "0.0.9" - resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" - integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo= - dependencies: - inherits "~2.0.0" - -boom@2.x.x: - version "2.10.1" - resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" - integrity sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8= - dependencies: - hoek "2.x.x" - brace-expansion@^1.1.7: version "1.1.8" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" @@ -161,64 +147,127 @@ braces@^1.8.2: preserve "^0.2.0" repeat-element "^1.1.2" -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= - -chalk@^1.0.0, chalk@^1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= +braces@^2.3.1, braces@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" -chokidar@^1.6.1: - version "1.7.0" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" - integrity sha1-eY5ol3gVHIB2tLNg5e3SjNortGg= - dependencies: - anymatch "^1.3.0" - async-each "^1.0.0" - glob-parent "^2.0.0" - inherits "^2.0.1" +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +chokidar@^2.0.0: + version "2.1.6" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.6.tgz#b6cad653a929e244ce8a834244164d241fa954c5" + integrity sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g== + dependencies: + anymatch "^2.0.0" + async-each "^1.0.1" + braces "^2.3.2" + glob-parent "^3.1.0" + inherits "^2.0.3" is-binary-path "^1.0.0" - is-glob "^2.0.0" + is-glob "^4.0.0" + normalize-path "^3.0.0" path-is-absolute "^1.0.0" - readdirp "^2.0.0" + readdirp "^2.2.1" + upath "^1.1.1" optionalDependencies: - fsevents "^1.0.0" + fsevents "^1.2.7" + +chownr@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.2.tgz#a18f1e0b269c8a6a5d3c86eb298beb14c3dd7bf6" + integrity sha512-GkfeAQh+QNy3wquu9oIZr6SS5x7wGdSgNQvD10X3r+AZr1Oys22HW8kAmDMvNg2+Dm0TeGaEuO8gFwdBXxwO8A== + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +clone-buffer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58" + integrity sha1-4+JbIHrE5wGvch4staFnksrD3Fg= clone-stats@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-0.0.1.tgz#b88f94a82cf38b8791d58046ea4029ad88ca99d1" integrity sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE= +clone-stats@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680" + integrity sha1-s3gt/4u1R04Yuba/D9/ngvh3doA= + clone@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.3.tgz#298d7e2231660f40c003c2ed3140decf3f53085f" integrity sha1-KY1+IjFmD0DAA8LtMUDezz9TCF8= -co@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= +clone@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" + integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= + +cloneable-readable@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/cloneable-readable/-/cloneable-readable-1.1.3.tgz#120a00cb053bfb63a222e709f9683ea2e11d8cec" + integrity sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ== + dependencies: + inherits "^2.0.1" + process-nextick-args "^2.0.0" + readable-stream "^2.3.5" code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= -combined-stream@^1.0.5, combined-stream@~1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" - integrity sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk= +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= dependencies: - delayed-stream "~1.0.0" + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-support@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" + integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== + +component-emitter@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== concat-map@0.0.1: version "0.0.1" @@ -230,46 +279,61 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0: resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= -core-util-is@1.0.2, core-util-is@~1.0.0: +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + +core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= -cryptiles@2.x.x: - version "2.0.5" - resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" - integrity sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g= - dependencies: - boom "2.x.x" - -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= - dependencies: - assert-plus "^1.0.0" - -dateformat@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-2.2.0.tgz#4065e2013cf9fb916ddfd82efb506ad4c6769062" - integrity sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI= - -debug@^2.2.0: +debug@^2.2.0, debug@^2.3.3: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" -deep-extend@~0.4.0: - version "0.4.2" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" - integrity sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8= +debug@^3.2.6: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== -delayed-stream@~1.0.0: +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" delegates@^1.0.0: version "1.0.0" @@ -281,25 +345,6 @@ detect-libc@^1.0.2: resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.2.tgz#71ad5d204bf17a6a6ca8f450c61454066ef461e1" integrity sha1-ca1dIEvxempsqPRQxhRUBm70YeE= -duplexer2@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.0.2.tgz#c614dcf67e2fb14995a91711e5a617e8a60a31db" - integrity sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds= - dependencies: - readable-stream "~1.1.9" - -ecc-jsbn@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" - integrity sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU= - dependencies: - jsbn "~0.1.0" - -escape-string-regexp@^1.0.2: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - expand-brackets@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" @@ -307,6 +352,19 @@ expand-brackets@^0.1.4: dependencies: is-posix-bracket "^0.1.0" +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + expand-range@^1.8.1: version "1.8.2" resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" @@ -314,10 +372,20 @@ expand-range@^1.8.1: dependencies: fill-range "^2.1.0" -extend@~3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" - integrity sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ= +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" extglob@^0.3.1: version "0.3.2" @@ -326,17 +394,27 @@ extglob@^0.3.1: dependencies: is-extglob "^1.0.0" -extsprintf@1.3.0, extsprintf@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= - -fancy-log@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.0.tgz#45be17d02bb9917d60ccffd4995c999e6c8c9948" - integrity sha1-Rb4X0Cu5kX1gzP/UmVyZnmyMmUg= +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +fancy-log@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.2.tgz#f41125e3d84f2e7d89a43d06d958c8f78be16be1" + integrity sha1-9BEl49hPLn2JpD0G2VjI94vha+E= dependencies: - chalk "^1.1.1" + ansi-gray "^0.1.1" + color-support "^1.1.3" time-stamp "^1.0.0" filename-regex@^2.0.0: @@ -355,6 +433,16 @@ fill-range@^2.1.0: repeat-element "^1.1.2" repeat-string "^1.5.2" +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + first-chunk-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-2.0.0.tgz#1bdecdb8e083c0664b91945581577a43a9f31d70" @@ -362,7 +450,7 @@ first-chunk-stream@^2.0.0: dependencies: readable-stream "^2.0.2" -for-in@^1.0.1: +for-in@^1.0.1, for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= @@ -374,51 +462,32 @@ for-own@^0.1.4: dependencies: for-in "^1.0.1" -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= + dependencies: + map-cache "^0.2.2" -form-data@~2.1.1: - version "2.1.4" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" - integrity sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE= +fs-minipass@^1.2.5: + version "1.2.6" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.6.tgz#2c5cc30ded81282bfe8a0d7c7c1853ddeb102c07" + integrity sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ== dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.5" - mime-types "^2.1.12" + minipass "^2.2.1" fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fsevents@^1.0.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.3.tgz#11f82318f5fe7bb2cd22965a108e9306208216d8" - integrity sha512-WIr7iDkdmdbxu/Gh6eKEZJL6KPE74/5MEsf2whTOFNxbIoIixogroLdKYqB6FDav4Wavh/lZdzzd3b2KxIXC5Q== +fsevents@^1.2.7: + version "1.2.9" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.9.tgz#3f5ed66583ccd6f400b5a00db6f7e861363e388f" + integrity sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw== dependencies: - nan "^2.3.0" - node-pre-gyp "^0.6.39" - -fstream-ignore@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" - integrity sha1-nDHa40dnAY/h0kmyTa2mfQktoQU= - dependencies: - fstream "^1.0.0" - inherits "2" - minimatch "^3.0.0" - -fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: - version "1.0.11" - resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" - integrity sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE= - dependencies: - graceful-fs "^4.1.2" - inherits "~2.0.0" - mkdirp ">=0.5 0" - rimraf "2" + nan "^2.12.1" + node-pre-gyp "^0.12.0" gauge@~2.7.3: version "2.7.4" @@ -434,12 +503,10 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= - dependencies: - assert-plus "^1.0.0" +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= glob-base@^0.3.0: version "0.3.0" @@ -456,7 +523,7 @@ glob-parent@^2.0.0: dependencies: is-glob "^2.0.0" -glob-parent@^3.0.1: +glob-parent@^3.0.1, glob-parent@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= @@ -476,120 +543,83 @@ glob@^7.0.5: once "^1.3.0" path-is-absolute "^1.0.0" -glogg@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/glogg/-/glogg-1.0.0.tgz#7fe0f199f57ac906cf512feead8f90ee4a284fc5" - integrity sha1-f+DxmfV6yQbPUS/urY+Q7kooT8U= - dependencies: - sparkles "^1.0.0" +graceful-fs@^4.1.11: + version "4.2.0" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.0.tgz#8d8fdc73977cb04104721cb53666c1ca64cd328b" + integrity sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg== graceful-fs@^4.1.2: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" integrity sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg= -gulp-util@^3.0.7: - version "3.0.8" - resolved "https://registry.yarnpkg.com/gulp-util/-/gulp-util-3.0.8.tgz#0054e1e744502e27c04c187c3ecc505dd54bbb4f" - integrity sha1-AFTh50RQLifATBh8PsxQXdVLu08= - dependencies: - array-differ "^1.0.0" - array-uniq "^1.0.2" - beeper "^1.0.0" - chalk "^1.0.0" - dateformat "^2.0.0" - fancy-log "^1.1.0" - gulplog "^1.0.0" - has-gulplog "^0.1.0" - lodash._reescape "^3.0.0" - lodash._reevaluate "^3.0.0" - lodash._reinterpolate "^3.0.0" - lodash.template "^3.0.0" - minimist "^1.1.0" - multipipe "^0.1.2" - object-assign "^3.0.0" - replace-ext "0.0.1" - through2 "^2.0.0" - vinyl "^0.5.0" - -gulp-watch@^4.3.9: - version "4.3.11" - resolved "https://registry.yarnpkg.com/gulp-watch/-/gulp-watch-4.3.11.tgz#162fc563de9fc770e91f9a7ce3955513a9a118c0" - integrity sha1-Fi/FY96fx3DpH5p845VVE6mhGMA= +gulp-watch@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/gulp-watch/-/gulp-watch-5.0.1.tgz#83d378752f5bfb46da023e73c17ed1da7066215d" + integrity sha512-HnTSBdzAOFIT4wmXYPDUn783TaYAq9bpaN05vuZNP5eni3z3aRx0NAKbjhhMYtcq76x4R1wf4oORDGdlrEjuog== dependencies: + ansi-colors "1.1.0" anymatch "^1.3.0" - chokidar "^1.6.1" + chokidar "^2.0.0" + fancy-log "1.3.2" glob-parent "^3.0.1" - gulp-util "^3.0.7" object-assign "^4.1.0" path-is-absolute "^1.0.1" + plugin-error "1.0.1" readable-stream "^2.2.2" slash "^1.0.0" - vinyl "^1.2.0" + vinyl "^2.1.0" vinyl-file "^2.0.0" -gulplog@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/gulplog/-/gulplog-1.0.0.tgz#e28c4d45d05ecbbed818363ce8f9c5926229ffe5" - integrity sha1-4oxNRdBey77YGDY86PnFkmIp/+U= - dependencies: - glogg "^1.0.0" - -har-schema@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" - integrity sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4= - -har-validator@~4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" - integrity sha1-M0gdDxu/9gDdID11gSpqX7oALio= - dependencies: - ajv "^4.9.1" - har-schema "^1.0.5" +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= dependencies: - ansi-regex "^2.0.0" + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" -has-gulplog@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/has-gulplog/-/has-gulplog-0.1.0.tgz#6414c82913697da51590397dafb12f22967811ce" - integrity sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4= +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= dependencies: - sparkles "^1.0.0" + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" -has-unicode@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= -hawk@3.1.3, hawk@~3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" - integrity sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ= +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= dependencies: - boom "2.x.x" - cryptiles "2.x.x" - hoek "2.x.x" - sntp "1.x.x" + is-number "^3.0.0" + kind-of "^4.0.0" -hoek@2.x.x: - version "2.16.3" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" - integrity sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0= +iconv-lite@^0.4.4: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" -http-signature@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" - integrity sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8= +ignore-walk@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" + integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ== dependencies: - assert-plus "^0.2.0" - jsprim "^1.2.2" - sshpk "^1.7.0" + minimatch "^3.0.4" inflight@^1.0.4: version "1.0.6" @@ -599,16 +629,35 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@^2.0.1, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= +inherits@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + ini@~1.3.0: version "1.3.4" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" integrity sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4= +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== + dependencies: + kind-of "^6.0.0" + is-binary-path@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" @@ -621,6 +670,38 @@ is-buffer@^1.1.5: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== + dependencies: + kind-of "^6.0.0" + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + is-dotfile@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" @@ -633,17 +714,24 @@ is-equal-shallow@^0.1.3: dependencies: is-primitive "^2.0.0" -is-extendable@^0.1.1: +is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + is-extglob@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA= -is-extglob@^2.1.0: +is-extglob@^2.1.0, is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= @@ -669,6 +757,13 @@ is-glob@^3.1.0: dependencies: is-extglob "^2.1.0" +is-glob@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + is-number@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" @@ -683,6 +778,13 @@ is-number@^3.0.0: dependencies: kind-of "^3.0.2" +is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + is-posix-bracket@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" @@ -693,20 +795,15 @@ is-primitive@^2.0.0: resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU= -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= - is-utf8@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== isarray@1.0.0, isarray@~1.0.0: version "1.0.0" @@ -720,49 +817,12 @@ isobject@^2.0.0: dependencies: isarray "1.0.0" -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= - -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= - -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= - -json-stable-stringify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" - integrity sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8= - dependencies: - jsonify "~0.0.0" - -json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= - -jsonify@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" - integrity sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM= - -jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= -kind-of@^3.0.2: +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= @@ -776,104 +836,27 @@ kind-of@^4.0.0: dependencies: is-buffer "^1.1.5" -lodash._basecopy@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" - integrity sha1-jaDmqHbPNEwK2KVIghEd08XHyjY= - -lodash._basetostring@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz#d1861d877f824a52f669832dcaf3ee15566a07d5" - integrity sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U= - -lodash._basevalues@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz#5b775762802bde3d3297503e26300820fdf661b7" - integrity sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc= - -lodash._getnative@^3.0.0: - version "3.9.1" - resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" - integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U= +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== -lodash._isiterateecall@^3.0.0: - version "3.0.9" - resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" - integrity sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw= +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== -lodash._reescape@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reescape/-/lodash._reescape-3.0.0.tgz#2b1d6f5dfe07c8a355753e5f27fac7f1cde1616a" - integrity sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo= - -lodash._reevaluate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz#58bc74c40664953ae0b124d806996daca431e2ed" - integrity sha1-WLx0xAZklTrgsSTYBpltrKQx4u0= - -lodash._reinterpolate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" - integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= - -lodash._root@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" - integrity sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI= - -lodash.escape@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-3.2.0.tgz#995ee0dc18c1b48cc92effae71a10aab5b487698" - integrity sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg= - dependencies: - lodash._root "^3.0.0" - -lodash.isarguments@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" - integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo= +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= -lodash.isarray@^3.0.0: - version "3.0.4" - resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" - integrity sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U= - -lodash.keys@^3.0.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" - integrity sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo= - dependencies: - lodash._getnative "^3.0.0" - lodash.isarguments "^3.0.0" - lodash.isarray "^3.0.0" - -lodash.restparam@^3.0.0: - version "3.6.1" - resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" - integrity sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU= - -lodash.template@^3.0.0: - version "3.6.2" - resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-3.6.2.tgz#f8cdecc6169a255be9098ae8b0c53d378931d14f" - integrity sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8= - dependencies: - lodash._basecopy "^3.0.0" - lodash._basetostring "^3.0.0" - lodash._basevalues "^3.0.0" - lodash._isiterateecall "^3.0.0" - lodash._reinterpolate "^3.0.0" - lodash.escape "^3.0.0" - lodash.keys "^3.0.0" - lodash.restparam "^3.0.0" - lodash.templatesettings "^3.0.0" - -lodash.templatesettings@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz#fb307844753b66b9f1afa54e262c745307dba8e5" - integrity sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU= +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= dependencies: - lodash._reinterpolate "^3.0.0" - lodash.escape "^3.0.0" + object-visit "^1.0.0" micromatch@^2.1.5: version "2.3.11" @@ -894,19 +877,26 @@ micromatch@^2.1.5: parse-glob "^3.0.4" regex-cache "^0.4.2" -mime-db@~1.30.0: - version "1.30.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" - integrity sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE= - -mime-types@^2.1.12, mime-types@~2.1.7: - version "2.1.17" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a" - integrity sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo= - dependencies: - mime-db "~1.30.0" - -minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4: +micromatch@^3.1.10, micromatch@^3.1.4: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== @@ -918,12 +908,35 @@ minimist@0.0.8: resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= -minimist@^1.1.0, minimist@^1.2.0: +minimist@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= -"mkdirp@>=0.5 0", mkdirp@^0.5.1: +minipass@^2.2.1, minipass@^2.3.5: + version "2.3.5" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" + integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA== + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614" + integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA== + dependencies: + minipass "^2.2.1" + +mixin-deep@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp@^0.5.0, mkdirp@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= @@ -935,34 +948,57 @@ ms@2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= -multipipe@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-0.1.2.tgz#2a8f2ddf70eed564dff2d57f1e1a137d9f05078b" - integrity sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s= - dependencies: - duplexer2 "0.0.2" - -nan@^2.3.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.7.0.tgz#d95bf721ec877e08db276ed3fc6eb78f9083ad46" - integrity sha1-2Vv3IeyHfgjbJ27T/G63j5CDrUY= - -node-pre-gyp@^0.6.39: - version "0.6.39" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz#c00e96860b23c0e1420ac7befc5044e1d78d8649" - integrity sha512-OsJV74qxnvz/AMGgcfZoDaeDXKD3oY3QVIbBmwszTFkRisTSXbMQyn4UWzUMOtA5SVhrBZOTp0wcoSBgfMfMmQ== +ms@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +nan@^2.12.1: + version "2.14.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" + integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +needle@^2.2.1: + version "2.4.0" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c" + integrity sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg== + dependencies: + debug "^3.2.6" + iconv-lite "^0.4.4" + sax "^1.2.4" + +node-pre-gyp@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149" + integrity sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A== dependencies: detect-libc "^1.0.2" - hawk "3.1.3" mkdirp "^0.5.1" + needle "^2.2.1" nopt "^4.0.1" + npm-packlist "^1.1.6" npmlog "^4.0.2" - rc "^1.1.7" - request "2.81.0" + rc "^1.2.7" rimraf "^2.6.1" semver "^5.3.0" - tar "^2.2.1" - tar-pack "^3.4.0" + tar "^4" nopt@^4.0.1: version "4.0.1" @@ -972,13 +1008,31 @@ nopt@^4.0.1: abbrev "1" osenv "^0.1.4" -normalize-path@^2.0.0, normalize-path@^2.0.1: +normalize-path@^2.0.0, normalize-path@^2.0.1, normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= dependencies: remove-trailing-separator "^1.0.1" +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-bundled@^1.0.1: + version "1.0.6" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd" + integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g== + +npm-packlist@^1.1.6: + version "1.4.4" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.4.tgz#866224233850ac534b63d1a6e76050092b5d2f44" + integrity sha512-zTLo8UcVYtDU3gdeaFu2Xu0n0EvelfHDGuqtNIn5RO7yQj4H1TqNdBc/yZjxnWA0PVB8D3Woyp0i5B43JwQ6Vw== + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + npmlog@^4.0.2: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" @@ -994,21 +1048,27 @@ number-is-nan@^1.0.0: resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= -oauth-sign@~0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" - integrity sha1-Rqarfwrq2N6unsBWV4C31O/rnUM= - -object-assign@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2" - integrity sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I= - object-assign@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + dependencies: + isobject "^3.0.0" + object.omit@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" @@ -1017,7 +1077,14 @@ object.omit@^2.0.0: for-own "^0.1.4" is-extendable "^0.1.1" -once@^1.3.0, once@^1.3.3: +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + dependencies: + isobject "^3.0.1" + +once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= @@ -1052,6 +1119,11 @@ parse-glob@^3.0.4: is-extglob "^1.0.0" is-glob "^2.0.0" +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + path-dirname@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" @@ -1062,11 +1134,6 @@ path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= -performance-now@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" - integrity sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU= - pify@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -1084,26 +1151,36 @@ pinkie@^2.0.0: resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= +plugin-error@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/plugin-error/-/plugin-error-1.0.1.tgz#77016bd8919d0ac377fdcdd0322328953ca5781c" + integrity sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA== + dependencies: + ansi-colors "^1.0.1" + arr-diff "^4.0.0" + arr-union "^3.1.0" + extend-shallow "^3.0.2" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks= +process-nextick-args@^2.0.0, process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + process-nextick-args@~1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" integrity sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M= -punycode@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" - integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= - -qs@~6.4.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" - integrity sha1-E+JtKK1rD/qpExLNO/cI7TUecjM= - randomatic@^1.1.3: version "1.1.7" resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" @@ -1112,17 +1189,17 @@ randomatic@^1.1.3: is-number "^3.0.0" kind-of "^4.0.0" -rc@^1.1.7: - version "1.2.2" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.2.tgz#d8ce9cb57e8d64d9c7badd9876c7c34cbe3c7077" - integrity sha1-2M6ctX6NZNnHut2YdsfDTL48cHc= +rc@^1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== dependencies: - deep-extend "~0.4.0" + deep-extend "^0.6.0" ini "~1.3.0" minimist "^1.2.0" strip-json-comments "~2.0.1" -readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2: +readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.2.2: version "2.3.3" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" integrity sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ== @@ -1135,25 +1212,27 @@ readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4, readable string_decoder "~1.0.3" util-deprecate "~1.0.1" -readable-stream@~1.1.9: - version "1.1.14" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" - integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= +readable-stream@^2.3.5: + version "2.3.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== dependencies: core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" -readdirp@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" - integrity sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg= +readdirp@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== dependencies: - graceful-fs "^4.1.2" - minimatch "^3.0.2" + graceful-fs "^4.1.11" + micromatch "^3.1.10" readable-stream "^2.0.2" - set-immediate-shim "^1.0.1" regex-cache@^0.4.2: version "0.4.4" @@ -1162,6 +1241,14 @@ regex-cache@^0.4.2: dependencies: is-equal-shallow "^0.1.3" +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + remove-trailing-separator@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" @@ -1172,7 +1259,7 @@ repeat-element@^1.1.2: resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" integrity sha1-7wiaF40Ug7quTZPrmLT55OEdmQo= -repeat-string@^1.5.2: +repeat-string@^1.5.2, repeat-string@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= @@ -1182,46 +1269,55 @@ replace-ext@0.0.1: resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924" integrity sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ= -request@2.81.0: - version "2.81.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" - integrity sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA= - dependencies: - aws-sign2 "~0.6.0" - aws4 "^1.2.1" - caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.0" - forever-agent "~0.6.1" - form-data "~2.1.1" - har-validator "~4.2.1" - hawk "~3.1.3" - http-signature "~1.1.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.7" - oauth-sign "~0.8.1" - performance-now "^0.2.0" - qs "~6.4.0" - safe-buffer "^5.0.1" - stringstream "~0.0.4" - tough-cookie "~2.3.0" - tunnel-agent "^0.6.0" - uuid "^3.0.0" - -rimraf@2, rimraf@^2.5.1, rimraf@^2.6.1: +replace-ext@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb" + integrity sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs= + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + +rimraf@^2.6.1: version "2.6.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" integrity sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w== dependencies: glob "^7.0.5" -safe-buffer@^5.0.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: +safe-buffer@^5.1.2: + version "5.2.0" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" + integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" integrity sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg== +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sax@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + semver@^5.3.0: version "5.4.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" @@ -1232,10 +1328,15 @@ set-blocking@~2.0.0: resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= -set-immediate-shim@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" - integrity sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E= +set-value@^2.0.0, set-value@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" signal-exit@^3.0.0: version "3.0.2" @@ -1247,32 +1348,71 @@ slash@^1.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= -sntp@1.x.x: - version "1.0.9" - resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" - integrity sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg= +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== dependencies: - hoek "2.x.x" + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" -sparkles@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.0.tgz#1acbbfb592436d10bbe8f785b7cc6f82815012c3" - integrity sha1-Gsu/tZJDbRC76PeFt8xvgoFQEsM= - -sshpk@^1.7.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3" - integrity sha1-US322mKHFEMW3EwY/hzx2UBzm+M= - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - dashdash "^1.12.0" - getpass "^0.1.1" - optionalDependencies: - bcrypt-pbkdf "^1.0.0" - ecc-jsbn "~0.1.1" - jsbn "~0.1.0" - tweetnacl "~0.14.0" +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +source-map-resolve@^0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" + integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== + dependencies: + atob "^2.1.1" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= + +source-map@^0.5.6: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" string-width@^1.0.1, string-width@^1.0.2: version "1.0.2" @@ -1283,11 +1423,6 @@ string-width@^1.0.1, string-width@^1.0.2: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= - string_decoder@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" @@ -1295,10 +1430,12 @@ string_decoder@~1.0.3: dependencies: safe-buffer "~5.1.0" -stringstream@~0.0.4: - version "0.0.5" - resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" - integrity sha1-TkhM1N5aC7vuGORjB3EKioFiGHg= +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" @@ -1327,90 +1464,87 @@ strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= - -tar-pack@^3.4.0: - version "3.4.1" - resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.1.tgz#e1dbc03a9b9d3ba07e896ad027317eb679a10a1f" - integrity sha512-PPRybI9+jM5tjtCbN2cxmmRU7YmqT3Zv/UDy48tAh2XRkLa9bAORtSWLkVc13+GJF+cdTh1yEnHEk3cpTaL5Kg== - dependencies: - debug "^2.2.0" - fstream "^1.0.10" - fstream-ignore "^1.0.5" - once "^1.3.3" - readable-stream "^2.1.4" - rimraf "^2.5.1" - tar "^2.2.1" - uid-number "^0.0.6" - -tar@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" - integrity sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE= +tar@^4: + version "4.4.10" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.10.tgz#946b2810b9a5e0b26140cf78bea6b0b0d689eba1" + integrity sha512-g2SVs5QIxvo6OLp0GudTqEf05maawKUxXru104iaayWA09551tFCTI8f1Asb4lPfkBr91k07iL4c11XO3/b0tA== dependencies: - block-stream "*" - fstream "^1.0.2" - inherits "2" - -through2@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" - integrity sha1-AARWmzfHx0ujnEPzzteNGtlBQL4= - dependencies: - readable-stream "^2.1.5" - xtend "~4.0.1" + chownr "^1.1.1" + fs-minipass "^1.2.5" + minipass "^2.3.5" + minizlib "^1.2.1" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.3" time-stamp@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3" integrity sha1-dkpaEa9QVhkhsTPztE5hhofg9cM= -tough-cookie@~2.3.0: - version "2.3.3" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561" - integrity sha1-C2GKVWW23qkL80JdBNVe3EdadWE= +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= dependencies: - punycode "^1.4.1" + is-number "^3.0.0" + repeat-string "^1.6.1" -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== dependencies: - safe-buffer "^5.0.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= +union-value@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^2.0.1" -uid-number@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" - integrity sha1-DqEOgDXo61uOREnwbaHHMGY7qoE= +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +upath@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.2.tgz#3db658600edaeeccbe6db5e684d67ee8c2acd068" + integrity sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q== + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= -uuid@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" - integrity sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g== - -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - vinyl-file@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/vinyl-file/-/vinyl-file-2.0.0.tgz#a7ebf5ffbefda1b7d18d140fcb07b223efb6751a" @@ -1423,16 +1557,7 @@ vinyl-file@^2.0.0: strip-bom-stream "^2.0.0" vinyl "^1.1.0" -vinyl@^0.5.0: - version "0.5.3" - resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.5.3.tgz#b0455b38fc5e0cf30d4325132e461970c2091cde" - integrity sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4= - dependencies: - clone "^1.0.0" - clone-stats "^0.0.1" - replace-ext "0.0.1" - -vinyl@^1.1.0, vinyl@^1.2.0: +vinyl@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-1.2.0.tgz#5c88036cf565e5df05558bfc911f8656df218884" integrity sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ= @@ -1441,6 +1566,18 @@ vinyl@^1.1.0, vinyl@^1.2.0: clone-stats "^0.0.1" replace-ext "0.0.1" +vinyl@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.2.0.tgz#d85b07da96e458d25b2ffe19fece9f2caa13ed86" + integrity sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg== + dependencies: + clone "^2.1.1" + clone-buffer "^1.0.0" + clone-stats "^1.0.0" + cloneable-readable "^1.0.0" + remove-trailing-separator "^1.0.1" + replace-ext "^1.0.0" + wide-align@^1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" @@ -1453,7 +1590,7 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -xtend@~4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" - integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= +yallist@^3.0.0, yallist@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" + integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A== diff --git a/build/monaco/api.js b/build/monaco/api.js index 297510d14..5cd0be820 100644 --- a/build/monaco/api.js +++ b/build/monaco/api.js @@ -306,8 +306,8 @@ function generateDeclarationFile(recipe, sourceFileGetter) { let usageImports = []; let usage = []; let failed = false; - usage.push(`var a;`); - usage.push(`var b;`); + usage.push(`var a: any;`); + usage.push(`var b: any;`); const generateUsageImport = (moduleId) => { let importName = 'm' + (++usageCounter); usageImports.push(`import * as ${importName} from './${moduleId.replace(/\.d\.ts$/, '')}';`); diff --git a/build/monaco/api.ts b/build/monaco/api.ts index 767218816..ef9c9a584 100644 --- a/build/monaco/api.ts +++ b/build/monaco/api.ts @@ -366,8 +366,8 @@ function generateDeclarationFile(recipe: string, sourceFileGetter: SourceFileGet let failed = false; - usage.push(`var a;`); - usage.push(`var b;`); + usage.push(`var a: any;`); + usage.push(`var b: any;`); const generateUsageImport = (moduleId: string) => { let importName = 'm' + (++usageCounter); diff --git a/build/monaco/monaco.d.ts.recipe b/build/monaco/monaco.d.ts.recipe index ed3a8f5d2..afba093b2 100644 --- a/build/monaco/monaco.d.ts.recipe +++ b/build/monaco/monaco.d.ts.recipe @@ -5,6 +5,8 @@ declare namespace monaco { + // THIS IS A GENERATED FILE. DO NOT EDIT DIRECTLY. + export type Thenable = PromiseLike; export interface IDisposable { diff --git a/build/monaco/monaco.usage.recipe b/build/monaco/monaco.usage.recipe index 13290a7ab..f1a74a25e 100644 --- a/build/monaco/monaco.usage.recipe +++ b/build/monaco/monaco.usage.recipe @@ -30,7 +30,7 @@ import * as editorAPI from './vs/editor/editor.api'; a = (>b).type; a = (b).start; a = (b).end; - a = (>b).getProxyObject; // IWorkerClient + a = (>b).getProxyObject; // IWorkerClient a = create1; a = create2; a = (b).extensionId; diff --git a/build/npm/postinstall.js b/build/npm/postinstall.js index 02755e171..cd4109219 100644 --- a/build/npm/postinstall.js +++ b/build/npm/postinstall.js @@ -20,13 +20,10 @@ function yarnInstall(location, opts) { const raw = process.env['npm_config_argv'] || '{}'; const argv = JSON.parse(raw); const original = argv.original || []; - const args = ['install']; + const args = original.filter(arg => arg === '--ignore-optional' || arg === '--frozen-lockfile'); - if (original.indexOf('--ignore-optional') > -1) { - args.push('--ignore-optional'); - } - - console.log('Installing dependencies in \'%s\'.', location); + console.log(`Installing dependencies in ${location}...`); + console.log(`$ yarn ${args.join(' ')}`); const result = cp.spawnSync(yarn, args, opts); if (result.error || result.status !== 0) { @@ -36,6 +33,10 @@ function yarnInstall(location, opts) { yarnInstall('extensions'); // node modules shared by all extensions +yarnInstall('remote'); // node modules used by vscode server + +yarnInstall('remote/web'); // node modules used by vscode web + const allExtensionFolders = fs.readdirSync('extensions'); const extensions = allExtensionFolders.filter(e => { try { diff --git a/build/npm/update-distro.js b/build/npm/update-distro.js new file mode 100644 index 000000000..947a4967d --- /dev/null +++ b/build/npm/update-distro.js @@ -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. + *--------------------------------------------------------------------------------------------*/ + +const cp = require('child_process'); +const path = require('path'); +const fs = require('fs'); + +const rootPath = path.dirname(path.dirname(path.dirname(__dirname))); +const vscodePath = path.join(rootPath, 'vscode'); +const distroPath = path.join(rootPath, 'vscode-distro'); +const commit = cp.execSync('git rev-parse HEAD', { cwd: distroPath, encoding: 'utf8' }).trim(); +const packageJsonPath = path.join(vscodePath, 'package.json'); +const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); + +packageJson.distro = commit; +fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2)); \ No newline at end of file diff --git a/build/npm/update-grammar.js b/build/npm/update-grammar.js index 522b29412..5321b7b1d 100644 --- a/build/npm/update-grammar.js +++ b/build/npm/update-grammar.js @@ -82,7 +82,7 @@ function getCommitSha(repoId, repoPath) { }); } -exports.update = function (repoId, repoPath, dest, modifyGrammar, version = 'master') { +exports.update = function (repoId, repoPath, dest, modifyGrammar, version = 'master', packageJsonPathOverride = '') { var contentPath = 'https://raw.githubusercontent.com/' + repoId + `/${version}/` + repoPath; console.log('Reading from ' + contentPath); return download(contentPath).then(function (content) { @@ -128,7 +128,11 @@ exports.update = function (repoId, repoPath, dest, modifyGrammar, version = 'mas // Add commit sha to cgmanifest. if (currentCommitDate > commitDate) { - let packageJsonPath = 'https://raw.githubusercontent.com/' + repoId + `/${info.commitSha}/package.json`; + let packageJsonPath = 'https://raw.githubusercontent.com/' + repoId + `/${info.commitSha}/`; + if (packageJsonPathOverride) { + packageJsonPath += packageJsonPathOverride; + } + packageJsonPath += '/package.json'; for (let i = 0; i < cgmanifestRead.registrations.length; i++) { if (cgmanifestRead.registrations[i].component.git.repositoryUrl.substr(cgmanifestRead.registrations[i].component.git.repositoryUrl.length - repoId.length, repoId.length) === repoId) { cgmanifestRead.registrations[i].component.git.commitHash = info.commitSha; diff --git a/build/package.json b/build/package.json index 49495b1c1..a382150c3 100644 --- a/build/package.json +++ b/build/package.json @@ -1,6 +1,7 @@ { "name": "code-oss-dev-build", "version": "1.0.0", + "license": "MIT", "devDependencies": { "@types/ansi-colors": "^3.2.0", "@types/azure": "0.9.19", @@ -19,7 +20,7 @@ "@types/minimatch": "^3.0.3", "@types/minimist": "^1.2.0", "@types/mocha": "2.2.39", - "@types/node": "8.0.33", + "@types/node": "^10.14.8", "@types/pump": "^1.0.1", "@types/request": "^2.47.0", "@types/rimraf": "^2.0.2", @@ -28,7 +29,7 @@ "@types/uglify-es": "^3.0.0", "@types/underscore": "^1.8.9", "@types/xml2js": "0.0.33", - "applicationinsights": "1.0.6", + "applicationinsights": "1.0.8", "azure-storage": "^2.1.0", "documentdb": "1.13.0", "github-releases": "^0.4.1", @@ -39,8 +40,9 @@ "minimist": "^1.2.0", "request": "^2.85.0", "tslint": "^5.9.1", - "typescript": "3.4.5", + "typescript": "3.5.2", "vsce": "1.48.0", + "vscode-telemetry-extractor": "1.5.3", "xml2js": "^0.4.17" }, "scripts": { @@ -49,4 +51,4 @@ "postinstall": "npm run compile", "npmCheckJs": "tsc --noEmit" } -} \ No newline at end of file +} diff --git a/build/win32/Cargo.lock b/build/win32/Cargo.lock index dcc1440b3..3c95fb34c 100644 --- a/build/win32/Cargo.lock +++ b/build/win32/Cargo.lock @@ -1,3 +1,5 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. [[package]] name = "build_const" version = "0.2.0" @@ -27,7 +29,7 @@ dependencies = [ [[package]] name = "inno_updater" -version = "0.7.1" +version = "0.8.0" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "crc 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/build/win32/code.iss b/build/win32/code.iss index ea31a50c9..831b31a3c 100644 --- a/build/win32/code.iss +++ b/build/win32/code.iss @@ -1034,7 +1034,7 @@ begin AltArch := '32'; end; - if not Result then begin + if not Result and not WizardSilent() then begin MsgBox('Please uninstall the ' + AltArch + '-bit version of {#NameShort} before installing this ' + ThisArch + '-bit version.', mbInformation, MB_OK); end; end; diff --git a/build/win32/i18n/messages.en.isl b/build/win32/i18n/messages.en.isl index 4bd6c75ad..a6aab59b9 100644 --- a/build/win32/i18n/messages.en.isl +++ b/build/win32/i18n/messages.en.isl @@ -2,7 +2,7 @@ AddContextMenuFiles=Add "Open with %1" action to Windows Explorer file context menu AddContextMenuFolders=Add "Open with %1" action to Windows Explorer directory context menu AssociateWithFiles=Register %1 as an editor for supported file types -AddToPath=Add to PATH (available after restart) +AddToPath=Add to PATH (requires shell restart) RunAfter=Run %1 after installation Other=Other: SourceFile=%1 Source File \ No newline at end of file diff --git a/build/win32/inno_updater.exe b/build/win32/inno_updater.exe index 140065f67..baca28361 100644 Binary files a/build/win32/inno_updater.exe and b/build/win32/inno_updater.exe differ diff --git a/build/yarn.lock b/build/yarn.lock index 3d6f61278..23ac4d9b8 100644 --- a/build/yarn.lock +++ b/build/yarn.lock @@ -2,6 +2,14 @@ # yarn lockfile v1 +"@dsherret/to-absolute-glob@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@dsherret/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz#1f6475dc8bd974cea07a2daf3864b317b1dd332c" + integrity sha1-H2R13IvZdM6gei2vOGSzF7HdMyw= + dependencies: + is-absolute "^1.0.0" + is-negated-glob "^1.0.0" + "@gulp-sourcemaps/map-sources@1.X": version "1.0.0" resolved "https://registry.yarnpkg.com/@gulp-sourcemaps/map-sources/-/map-sources-1.0.0.tgz#890ae7c5d8c877f6d384860215ace9d7ec945bda" @@ -10,6 +18,27 @@ normalize-path "^2.0.1" through2 "^2.0.3" +"@nodelib/fs.scandir@2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.1.tgz#7fa8fed654939e1a39753d286b48b4836d00e0eb" + integrity sha512-NT/skIZjgotDSiXs0WqYhgcuBKhUMgfekCmCGtkUAiLqZdOnrdjmZr9wRl3ll64J9NF79uZ4fk16Dx0yMc/Xbg== + dependencies: + "@nodelib/fs.stat" "2.0.1" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.1", "@nodelib/fs.stat@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.1.tgz#814f71b1167390cfcb6a6b3d9cdeb0951a192c14" + integrity sha512-+RqhBlLn6YRBGOIoVYthsG0J9dfpO79eJyN7BYBkZJtfqrBwf2KK+rD/M/yjZR6WBmIhAgOV7S60eCgaSWtbFw== + +"@nodelib/fs.walk@^1.2.1": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.2.tgz#6a6450c5e17012abd81450eb74949a4d970d2807" + integrity sha512-J/DR3+W12uCzAJkw7niXDcqcKBg6+5G5Q/ZpThpGNzAUz70eOR6RV4XnnSN01qHZiVl0eavoxJsBypQoKsV2QQ== + dependencies: + "@nodelib/fs.scandir" "2.1.1" + fastq "^1.6.0" + "@types/ansi-colors@^3.2.0": version "3.2.0" resolved "https://registry.yarnpkg.com/@types/ansi-colors/-/ansi-colors-3.2.0.tgz#3e4fe85d9131ce1c6994f3040bd0b25306c16a6e" @@ -166,10 +195,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.51.tgz#b31d716fb8d58eeb95c068a039b9b6292817d5fb" integrity sha512-El3+WJk2D/ppWNd2X05aiP5l2k4EwF7KwheknQZls+I26eSICoWRhRIJ56jGgw2dqNGQ5LtNajmBU2ajS28EvQ== -"@types/node@8.0.33": - version "8.0.33" - resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.33.tgz#1126e94374014e54478092830704f6ea89df04cd" - integrity sha512-vmCdO8Bm1ExT+FWfC9sd9r4jwqM7o97gGy2WBshkkXbf/2nLAJQUrZfIhw27yVOtLUev6kSZc4cav/46KbDd8A== +"@types/node@^10.14.8": + version "10.14.13" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.13.tgz#ac786d623860adf39a3f51d629480aacd6a6eec7" + integrity sha512-yN/FNNW1UYsRR1wwAoyOwqvDuLDtVXnaJTZ898XIw/Q5cCaeVAlVwvsmXLX5PuiScBYwZsZU4JYSHB3TvfdwvQ== "@types/pump@^1.0.1": version "1.0.1" @@ -328,10 +357,10 @@ ansi-wrap@0.1.0: resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" integrity sha1-qCJQ3bABXponyoLoLqYDu/pF768= -applicationinsights@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.0.6.tgz#bc201810de91cea910dab34e8ad35ecde488edeb" - integrity sha512-VQT3kBpJVPw5fCO5n+WUeSx0VHjxFtD7znYbILBlVgOS9/cMDuGFmV2Br3ObzFyZUDGNbEfW36fD1y2/vAiCKw== +applicationinsights@1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.0.8.tgz#db6e3d983cf9f9405fe1ee5ba30ac6e1914537b5" + integrity sha512-KzOOGdphOS/lXWMFZe5440LUdFbrLpMvh2SaRxn7BmiI550KAoSb2gIhiq6kJZ9Ir3AxRRztjhzif+e5P5IXIg== dependencies: diagnostic-channel "0.2.0" diagnostic-channel-publishers "0.2.1" @@ -344,16 +373,36 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" +array-back@^3.0.1: + version "3.1.0" + resolved "https://registry.yarnpkg.com/array-back/-/array-back-3.1.0.tgz#b8859d7a508871c9a7b2cf42f99428f65e96bfb0" + integrity sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q== + array-differ@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031" integrity sha1-7/UuN1gknTO+QCuLuOVkuytdQDE= +array-differ@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-3.0.0.tgz#3cbb3d0f316810eafcc47624734237d6aee4ae6b" + integrity sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg== + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + array-uniq@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= +arrify@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" + integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== + asn1@~0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" @@ -481,6 +530,13 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +braces@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + browserify-mime@~1.2.9: version "1.2.9" resolved "https://registry.yarnpkg.com/browserify-mime/-/browserify-mime-1.2.9.tgz#aeb1af28de6c0d7a6a2ce40adb68ff18422af31f" @@ -548,6 +604,11 @@ co@^4.6.0: resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= +code-block-writer@9.4.1: + version "9.4.1" + resolved "https://registry.yarnpkg.com/code-block-writer/-/code-block-writer-9.4.1.tgz#1448fca79dfc7a3649000f4c85be6bc770604c4c" + integrity sha512-LHAB+DL4YZDcwK8y/kAxZ0Lf/ncwLh/Ux4cTVWbPwIdrf1gPxXiPcwpz8r8/KqXu1aD+Raz46EOxDjFlbyO6bA== + color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -584,6 +645,16 @@ combined-stream@^1.0.5, combined-stream@~1.0.5: dependencies: delayed-stream "~1.0.0" +command-line-args@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.1.1.tgz#88e793e5bb3ceb30754a86863f0401ac92fd369a" + integrity sha512-hL/eG8lrll1Qy1ezvkant+trihbGnaKaeEjj6Scyr3DN+RC7iQ5Rz84IeLERfAWDGo0HBSNAakczwgCilDXnWg== + dependencies: + array-back "^3.0.1" + find-replace "^3.0.0" + lodash.camelcase "^4.3.0" + typical "^4.0.0" + commander@^2.12.1, commander@^2.8.1: version "2.19.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" @@ -710,6 +781,13 @@ diff@^3.2.0: resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + documentdb@1.13.0: version "1.13.0" resolved "https://registry.yarnpkg.com/documentdb/-/documentdb-1.13.0.tgz#bba6f03150b2f42498cec4261bc439d834a33f8b" @@ -829,11 +907,30 @@ fast-deep-equal@^1.0.0: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" integrity sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ= +fast-glob@^3.0.3: + version "3.0.4" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.0.4.tgz#d484a41005cb6faeb399b951fd1bd70ddaebb602" + integrity sha512-wkIbV6qg37xTJwqSsdnIphL1e+LaGz4AIQqr00mIubMaEhv1/HEmJ0uuCGZRNRUkZZmOB5mJKO0ZUTVq+SxMQg== + dependencies: + "@nodelib/fs.stat" "^2.0.1" + "@nodelib/fs.walk" "^1.2.1" + glob-parent "^5.0.0" + is-glob "^4.0.1" + merge2 "^1.2.3" + micromatch "^4.0.2" + fast-json-stable-stringify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= +fastq@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.6.0.tgz#4ec8a38f4ac25f21492673adb7eae9cfef47d1c2" + integrity sha512-jmxqQ3Z/nXoeyDmWAzF9kH1aGZSis6e/SbfPmJpUnyZ0ogr6iscHQaml4wsEepEWSdtmpy+eVXmCRIMpxaXqOA== + dependencies: + reusify "^1.0.0" + fd-slicer@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" @@ -841,6 +938,20 @@ fd-slicer@~1.1.0: dependencies: pend "~1.2.0" +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +find-replace@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-replace/-/find-replace-3.0.0.tgz#3e7e23d3b05167a76f770c9fbd5258b0def68c38" + integrity sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ== + dependencies: + array-back "^3.0.1" + forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" @@ -864,6 +975,15 @@ form-data@~2.3.1: combined-stream "1.0.6" mime-types "^2.1.12" +fs-extra@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -886,6 +1006,13 @@ github-releases@^0.4.1: prettyjson "1.2.1" request "2.81.0" +glob-parent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.0.0.tgz#1dc99f0f39b006d3e92c2c284068382f0c20e954" + integrity sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg== + dependencies: + is-glob "^4.0.1" + glob@^7.0.6, glob@^7.1.1: version "7.1.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" @@ -898,6 +1025,32 @@ glob@^7.0.6, glob@^7.1.1: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^7.1.3: + version "7.1.4" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" + integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globby@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/globby/-/globby-10.0.1.tgz#4782c34cb75dd683351335c5829cc3420e606b22" + integrity sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A== + dependencies: + "@types/glob" "^7.1.1" + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.0.3" + glob "^7.1.3" + ignore "^5.1.1" + merge2 "^1.2.3" + slash "^3.0.0" + glogg@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/glogg/-/glogg-1.0.1.tgz#dcf758e44789cc3f3d32c1f3562a3676e6a34810" @@ -910,6 +1063,11 @@ graceful-fs@4.X: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" integrity sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg= +graceful-fs@^4.1.6, graceful-fs@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.0.tgz#8d8fdc73977cb04104721cb53666c1ca64cd328b" + integrity sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg== + gulp-bom@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/gulp-bom/-/gulp-bom-1.0.0.tgz#38a183a07187bd57a7922d37977441f379df2abf" @@ -1086,6 +1244,11 @@ iconv-lite@0.4.23: dependencies: safer-buffer ">= 2.1.2 < 3" +ignore@^5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.2.tgz#e28e584d43ad7e92f96995019cc43b9e1ac49558" + integrity sha512-vdqWBp7MyzdmHkkRWV5nY+PfGRbYbahfuvsBCh277tq+w9zyNi7h5CYJCK0kmzti9kU+O/cB7sE8HvKv6aXAKQ== + inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -1094,21 +1257,75 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= +is-absolute@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-absolute/-/is-absolute-1.0.0.tgz#395e1ae84b11f26ad1795e73c17378e48a301576" + integrity sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA== + dependencies: + is-relative "^1.0.0" + is-windows "^1.0.1" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-glob@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + +is-negated-glob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-negated-glob/-/is-negated-glob-1.0.0.tgz#6910bca5da8c95e784b5751b976cf5a10fee36d2" + integrity sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI= + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-relative@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-1.0.0.tgz#a1bb6935ce8c5dba1e8b9754b9b2dcc020e2260d" + integrity sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA== + dependencies: + is-unc-path "^1.0.0" + is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= +is-unc-path@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-unc-path/-/is-unc-path-1.0.0.tgz#d731e8898ed090a12c352ad2eaed5095ad322c9d" + integrity sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ== + dependencies: + unc-path-regex "^0.1.2" + is-utf8@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= +is-windows@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + isarray@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" @@ -1171,6 +1388,13 @@ json-stringify-safe@~5.0.1: resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + optionalDependencies: + graceful-fs "^4.1.6" + jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" @@ -1248,6 +1472,11 @@ lodash._root@^3.0.0: resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" integrity sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI= +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= + lodash.escape@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-3.2.0.tgz#995ee0dc18c1b48cc92effae71a10aab5b487698" @@ -1331,6 +1560,19 @@ mdurl@^1.0.1: resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= +merge2@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.3.tgz#7ee99dbd69bb6481689253f018488a1b902b0ed5" + integrity sha512-gdUU1Fwj5ep4kplwcmftruWofEFt6lfpkkr3h860CXbAB9c3hGb55EOL2ali0Td5oebvW0E1+3Sr+Ur7XfKpRA== + +micromatch@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" + integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== + dependencies: + braces "^3.0.1" + picomatch "^2.0.5" + mime-db@~1.30.0: version "1.30.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" @@ -1382,6 +1624,17 @@ ms@2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= +multimatch@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-4.0.0.tgz#8c3c0f6e3e8449ada0af3dd29efb491a375191b3" + integrity sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ== + dependencies: + "@types/minimatch" "^3.0.3" + array-differ "^3.0.0" + array-union "^2.1.0" + arrify "^2.0.1" + minimatch "^3.0.4" + multipipe@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-0.1.2.tgz#2a8f2ddf70eed564dff2d57f1e1a137d9f05078b" @@ -1480,6 +1733,11 @@ path-parse@^1.0.5: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + pend@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" @@ -1495,6 +1753,11 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= +picomatch@^2.0.5: + version "2.0.7" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.0.7.tgz#514169d8c7cd0bdbeecc8a2609e34a7163de69f6" + integrity sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA== + prettyjson@1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prettyjson/-/prettyjson-1.2.1.tgz#fcffab41d19cab4dfae5e575e64246619b12d289" @@ -1667,6 +1930,16 @@ resolve@^1.3.2: dependencies: path-parse "^1.0.5" +reusify@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +run-parallel@^1.1.9: + version "1.1.9" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" + integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== + safe-buffer@^5.0.1, safe-buffer@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" @@ -1702,6 +1975,11 @@ semver@^5.1.0, semver@^5.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + sntp@1.x.x: version "1.0.9" resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" @@ -1825,6 +2103,13 @@ tmp@0.0.29: dependencies: os-tmpdir "~1.0.1" +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + tough-cookie@~2.3.0: version "2.3.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561" @@ -1839,6 +2124,20 @@ tough-cookie@~2.3.3: dependencies: punycode "^1.4.1" +ts-morph@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-3.1.3.tgz#bbfa1d14481ee23bdd1c030340ccf4a243cfc844" + integrity sha512-CwjgyJTtd3f8vBi7Vr0IOgdOY6Wi/Tq0MhieXOE2B5ns5WWRD7BwMNHtv+ZufKI/S2U/lMrh+Q3bOauE4tsv2g== + dependencies: + "@dsherret/to-absolute-glob" "^2.0.2" + code-block-writer "9.4.1" + fs-extra "^8.1.0" + glob-parent "^5.0.0" + globby "^10.0.1" + is-negated-glob "^1.0.0" + multimatch "^4.0.0" + typescript "^3.0.1" + tslib@^1.8.0, tslib@^1.8.1: version "1.9.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" @@ -1894,16 +2193,31 @@ typed-rest-client@^0.9.0: tunnel "0.0.4" underscore "1.8.3" -typescript@3.4.5: - version "3.4.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.5.tgz#2d2618d10bb566572b8d7aad5180d84257d70a99" - integrity sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw== +typescript@3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.2.tgz#a09e1dc69bc9551cadf17dba10ee42cf55e5d56c" + integrity sha512-7KxJovlYhTX5RaRbUdkAXN1KUZ8PwWlTzQdHV6xNqvuFOs7+WBo10TQUqT19Q/Jz2hk5v9TQDIhyLhhJY4p5AA== + +typescript@^3.0.1: + version "3.5.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.3.tgz#c830f657f93f1ea846819e929092f5fe5983e977" + integrity sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g== + +typical@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4" + integrity sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw== uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.5.tgz#0c65f15f815aa08b560a61ce8b4db7ffc3f45376" integrity sha512-JoLI4g5zv5qNyT09f4YAvEZIIV1oOjqnewYg5D38dkQljIzpPT296dbIGvKro3digYI1bkb7W6EP1y4uDlmzLg== +unc-path-regex@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa" + integrity sha1-5z3T17DXxe2G+6xrCufYxqadUPo= + underscore@1.8.3, underscore@~1.8.3: version "1.8.3" resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" @@ -1914,6 +2228,11 @@ underscore@^1.8.3: resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.1.tgz#06dce34a0e68a7babc29b365b8e74b8925203961" integrity sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg== +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + urix@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" @@ -1994,6 +2313,20 @@ vsce@1.48.0: yauzl "^2.3.1" yazl "^2.2.2" +vscode-ripgrep@^1.5.5: + version "1.5.5" + resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.5.tgz#24c0e9cb356cf889c98e15ecb58f9cf654a1d961" + integrity sha512-OrPrAmcun4+uZAuNcQvE6CCPskh+5AsjANod/Q3zRcJcGNxgoOSGlQN9RPtatkUNmkN8Nn8mZBnS1jMylu/dKg== + +vscode-telemetry-extractor@1.5.3: + version "1.5.3" + resolved "https://registry.yarnpkg.com/vscode-telemetry-extractor/-/vscode-telemetry-extractor-1.5.3.tgz#c17f9065a47425edafd23ea161e80c23274e009d" + integrity sha512-feioJ1e1KyMa9rzblnLbSOduo+Ny0l62H3/bSDgfgCSnU/km+tTSYxPBvZHVr7iQfQGC95J61yC/ObqS9EbaQg== + dependencies: + command-line-args "^5.1.1" + ts-morph "^3.1.3" + vscode-ripgrep "^1.5.5" + vso-node-api@6.1.2-preview: version "6.1.2-preview" resolved "https://registry.yarnpkg.com/vso-node-api/-/vso-node-api-6.1.2-preview.tgz#aab3546df2451ecd894e071bb99b5df19c5fa78f" diff --git a/cglicenses.json b/cglicenses.json index 3d96813f3..b7f408109 100644 --- a/cglicenses.json +++ b/cglicenses.json @@ -6,694 +6,768 @@ // DO NOT EDIT THIS FILE UNLESS THE OSS TOOL INDICATES THAT YOU SHOULD. // [ -{ - // Reason: The license at https://github.com/aadsm/jschardet/blob/master/LICENSE - // does not include a clear Copyright statement and does not credit authors. - "name": "jschardet", - "licenseDetail": [ - "Chardet was originally ported from C++ by Mark Pilgrim. It is now maintained", - " by Dan Blanchard and Ian Cordasco, and was formerly maintained by Erik Rose.", - " JSChardet was ported from python to JavaScript by António Afonso ", - " (https://github.com/aadsm/jschardet) and transformed into an npm package by ", - "Markus Ast (https://github.com/brainafk)", - "", - "GNU LESSER GENERAL PUBLIC LICENSE", - "\t\t Version 2.1, February 1999", - "", - " Copyright (C) 1991,", - "1999 Free Software Foundation, Inc.", - " 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA", - " Everyone is permitted to copy and distribute verbatim copies", - " of this license document, but changing it is not allowed.", - "", - "[This is the first released version of the Lesser GPL. It also counts", - " as the successor of the GNU Library Public License, version 2, hence", - " the version number 2.1.", - "]", - "", - "\t\t\t Preamble", - "", - " The licenses for most software are designed to take away your", - "freedom to share and change it. By contrast, the GNU General Public", - "Licenses are intended to guarantee your freedom to share and change", - "free software--to make sure the software is free for all its users.", - "", - " This license, the Lesser General Public License, applies to some", - "specially designated software packages--typically libraries--of the", - "Free Software Foundation and other authors who decide to use it. You", - "can use it too, but we suggest you first think carefully about whether", - "this license or the ordinary General Public License is the better", - "strategy to use in any particular case, based on the explanations below.", - "", - " When we speak of free software, we are referring to freedom of use,", - "not price. Our General Public Licenses are designed to make sure that", - "you have the freedom to distribute copies of free software (and charge", - "for this service if you wish); that you receive source code or can get", - "it if you want it; that you can change the software and use pieces of", - "it in new free programs; and that you are informed that you can do", - "these things.", - "", - " To protect your rights, we need to make restrictions that forbid", - "distributors to deny you these rights or to ask you to surrender these", - "rights. These restrictions translate to certain responsibilities for", - "you if you distribute copies of the library or if you modify it.", - "", - " For example, if you distribute copies of the library, whether gratis", - "or for a fee, you must give the recipients all the rights that we gave", - "you. You must make sure that they, too, receive or can get the source", - "code. If you link other code with the library, you must provide", - "complete object files to the recipients, so that they can relink them", - "with the library after making changes to the library and recompiling", - "it. And you must show them these terms so they know their rights.", - "", - " We protect your rights with a two-step method: (1) we copyright the", - "library, and (2) we offer you this license, which gives you legal", - "permission to copy, distribute and/or modify the library.", - "", - " To protect each distributor, we want to make it very clear that", - "there is no warranty for the free library. Also, if the library is", - "modified by someone else and passed on, the recipients should know", - "that what they have is not the original version, so that the original", - "author's reputation will not be affected by problems that might be", - "introduced by others.", - "", - " Finally, software patents pose a constant threat to the existence of", - "any free program. We wish to make sure that a company cannot", - "effectively restrict the users of a free program by obtaining a", - "restrictive license from a patent holder. Therefore, we insist that", - "any patent license obtained for a version of the library must be", - "consistent with the full freedom of use specified in this license.", - "", - " Most GNU software, including some libraries, is covered by the", - "ordinary GNU General Public License. This license, the GNU Lesser", - "General Public License, applies to certain designated libraries, and", - "is quite different from the ordinary General Public License. We use", - "this license for certain libraries in order to permit linking those", - "libraries into non-free programs.", - "", - " When a program is linked with a library, whether statically or using", - "a shared library, the combination of the two is legally speaking a", - "combined work, a derivative of the original library. The ordinary", - "General Public License therefore permits such linking only if the", - "entire combination fits its criteria of freedom. The Lesser General", - "Public License permits more lax criteria for linking other code with", - "the library.", - "", - " We call this license the \"Lesser\" General Public License because it", - "does Less to protect the user's freedom than the ordinary General", - "Public License. It also provides other free software developers Less", - "of an advantage over competing non-free programs. These disadvantages", - "are the reason we use the ordinary General Public License for many", - "libraries. However, the Lesser license provides advantages in certain", - "special circumstances.", - "", - " For example, on rare occasions, there may be a special need to", - "encourage the widest possible use of a certain library, so that it becomes", - "a de-facto standard. To achieve this, non-free programs must be", - "allowed to use the library. A more frequent case is that a free", - "library does the same job as widely used non-free libraries. In this", - "case, there is little to gain by limiting the free library to free", - "software only, so we use the Lesser General Public License.", - "", - " In other cases, permission to use a particular library in non-free", - "programs enables a greater number of people to use a large body of", - "free software. For example, permission to use the GNU C Library in", - "non-free programs enables many more people to use the whole GNU", - "operating system, as well as its variant, the GNU/Linux operating", - "system.", - "", - " Although the Lesser General Public License is Less protective of the", - "users' freedom, it does ensure that the user of a program that is", - "linked with the Library has the freedom and the wherewithal to run", - "that program using a modified version of the Library.", - "", - " The precise terms and conditions for copying, distribution and", - "modification follow. Pay close attention to the difference between a", - "\"work based on the library\" and a \"work that uses the library\". The", - "former contains code derived from the library, whereas the latter must", - "be combined with the library in order to run.", - "", - "\t\t GNU LESSER GENERAL PUBLIC LICENSE", - " TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION", - "", - " 0. This License Agreement applies to any software library or other", - "program which contains a notice placed by the copyright holder or", - "other authorized party saying it may be distributed under the terms of", - "this Lesser General Public License (also called \"this License\").", - "Each licensee is addressed as \"you\".", - "", - " A \"library\" means a collection of software functions and/or data", - "prepared so as to be conveniently linked with application programs", - "(which use some of those functions and data) to form executables.", - "", - " The \"Library\", below, refers to any such software library or work", - "which has been distributed under these terms. A \"work based on the", - "Library\" means either the Library or any derivative work under", - "copyright law: that is to say, a work containing the Library or a", - "portion of it, either verbatim or with modifications and/or translated", - "straightforwardly into another language. (Hereinafter, translation is", - "included without limitation in the term \"modification\".)", - "", - " \"Source code\" for a work means the preferred form of the work for", - "making modifications to it. For a library, complete source code means", - "all the source code for all modules it contains, plus any associated", - "interface definition files, plus the scripts used to control compilation", - "and installation of the library.", - "", - " Activities other than copying, distribution and modification are not", - "covered by this License; they are outside its scope. The act of", - "running a program using the Library is not restricted, and output from", - "such a program is covered only if its contents constitute a work based", - "on the Library (independent of the use of the Library in a tool for", - "writing it). Whether that is true depends on what the Library does", - "and what the program that uses the Library does.", - "", - " 1. You may copy and distribute verbatim copies of the Library's", - "complete source code as you receive it, in any medium, provided that", - "you conspicuously and appropriately publish on each copy an", - "appropriate copyright notice and disclaimer of warranty; keep intact", - "all the notices that refer to this License and to the absence of any", - "warranty; and distribute a copy of this License along with the", - "Library.", - "", - " You may charge a fee for the physical act of transferring a copy,", - "and you may at your option offer warranty protection in exchange for a", - "fee.", - "", - " 2. You may modify your copy or copies of the Library or any portion", - "of it, thus forming a work based on the Library, and copy and", - "distribute such modifications or work under the terms of Section 1", - "above, provided that you also meet all of these conditions:", - "", - " a) The modified work must itself be a software library.", - "", - " b) You must cause the files modified to carry prominent notices", - " stating that you changed the files and the date of any change.", - "", - " c) You must cause the whole of the work to be licensed at no", - " charge to all third parties under the terms of this License.", - "", - " d) If a facility in the modified Library refers to a function or a", - " table of data to be supplied by an application program that uses", - " the facility, other than as an argument passed when the facility", - " is invoked, then you must make a good faith effort to ensure that,", - " in the event an application does not supply such function or", - " table, the facility still operates, and performs whatever part of", - " its purpose remains meaningful.", - "", - " (For example, a function in a library to compute square roots has", - " a purpose that is entirely well-defined independent of the", - " application. Therefore, Subsection 2d requires that any", - " application-supplied function or table used by this function must", - " be optional: if the application does not supply it, the square", - " root function must still compute square roots.)", - "", - "These requirements apply to the modified work as a whole. If", - "identifiable sections of that work are not derived from the Library,", - "and can be reasonably considered independent and separate works in", - "themselves, then this License, and its terms, do not apply to those", - "sections when you distribute them as separate works. But when you", - "distribute the same sections as part of a whole which is a work based", - "on the Library, the distribution of the whole must be on the terms of", - "this License, whose permissions for other licensees extend to the", - "entire whole, and thus to each and every part regardless of who wrote", - "it.", - "", - "Thus, it is not the intent of this section to claim rights or contest", - "your rights to work written entirely by you; rather, the intent is to", - "exercise the right to control the distribution of derivative or", - "collective works based on the Library.", - "", - "In addition, mere aggregation of another work not based on the Library", - "with the Library (or with a work based on the Library) on a volume of", - "a storage or distribution medium does not bring the other work under", - "the scope of this License.", - "", - " 3. You may opt to apply the terms of the ordinary GNU General Public", - "License instead of this License to a given copy of the Library. To do", - "this, you must alter all the notices that refer to this License, so", - "that they refer to the ordinary GNU General Public License, version 2,", - "instead of to this License. (If a newer version than version 2 of the", - "ordinary GNU General Public License has appeared, then you can specify", - "that version instead if you wish.) Do not make any other change in", - "these notices.", - "", - " Once this change is made in a given copy, it is irreversible for", - "that copy, so the ordinary GNU General Public License applies to all", - "subsequent copies and derivative works made from that copy.", - "", - " This option is useful when you wish to copy part of the code of", - "the Library into a program that is not a library.", - "", - " 4. You may copy and distribute the Library (or a portion or", - "derivative of it, under Section 2) in object code or executable form", - "under the terms of Sections 1 and 2 above provided that you accompany", - "it with the complete corresponding machine-readable source code, which", - "must be distributed under the terms of Sections 1 and 2 above on a", - "medium customarily used for software interchange.", - "", - " If distribution of object code is made by offering access to copy", - "from a designated place, then offering equivalent access to copy the", - "source code from the same place satisfies the requirement to", - "distribute the source code, even though third parties are not", - "compelled to copy the source along with the object code.", - "", - " 5. A program that contains no derivative of any portion of the", - "Library, but is designed to work with the Library by being compiled or", - "linked with it, is called a \"work that uses the Library\". Such a", - "work, in isolation, is not a derivative work of the Library, and", - "therefore falls outside the scope of this License.", - "", - " However, linking a \"work that uses the Library\" with the Library", - "creates an executable that is a derivative of the Library (because it", - "contains portions of the Library), rather than a \"work that uses the", - "library\". The executable is therefore covered by this License.", - "Section 6 states terms for distribution of such executables.", - "", - " When a \"work that uses the Library\" uses material from a header file", - "that is part of the Library, the object code for the work may be a", - "derivative work of the Library even though the source code is not.", - "Whether this is true is especially significant if the work can be", - "linked without the Library, or if the work is itself a library. The", - "threshold for this to be true is not precisely defined by law.", - "", - " If such an object file uses only numerical parameters, data", - "structure layouts and accessors, and small macros and small inline", - "functions (ten lines or less in length), then the use of the object", - "file is unrestricted, regardless of whether it is legally a derivative", - "work. (Executables containing this object code plus portions of the", - "Library will still fall under Section 6.)", - "", - " Otherwise, if the work is a derivative of the Library, you may", - "distribute the object code for the work under the terms of Section 6.", - "Any executables containing that work also fall under Section 6,", - "whether or not they are linked directly with the Library itself.", - "", - " 6. As an exception to the Sections above, you may also combine or", - "link a \"work that uses the Library\" with the Library to produce a", - "work containing portions of the Library, and distribute that work", - "under terms of your choice, provided that the terms permit", - "modification of the work for the customer's own use and reverse", - "engineering for debugging such modifications.", - "", - " You must give prominent notice with each copy of the work that the", - "Library is used in it and that the Library and its use are covered by", - "this License. You must supply a copy of this License. If the work", - "during execution displays copyright notices, you must include the", - "copyright notice for the Library among them, as well as a reference", - "directing the user to the copy of this License. Also, you must do one", - "of these things:", - "", - " a) Accompany the work with the complete corresponding", - " machine-readable source code for the Library including whatever", - " changes were used in the work (which must be distributed under", - " Sections 1 and 2 above); and, if the work is an executable linked", - " with the Library, with the complete machine-readable \"work that", - " uses the Library\", as object code and/or source code, so that the", - " user can modify the Library and then relink to produce a modified", - " executable containing the modified Library. (It is understood", - " that the user who changes the contents of definitions files in the", - " Library will not necessarily be able to recompile the application", - " to use the modified definitions.)", - "", - " b) Use a suitable shared library mechanism for linking with the", - " Library. A suitable mechanism is one that (1) uses at run time a", - " copy of the library already present on the user's computer system,", - " rather than copying library functions into the executable, and (2)", - " will operate properly with a modified version of the library, if", - " the user installs one, as long as the modified version is", - " interface-compatible with the version that the work was made with.", - "", - " c) Accompany the work with a written offer, valid for at", - " least three years, to give the same user the materials", - " specified in Subsection 6a, above, for a charge no more", - " than the cost of performing this distribution.", - "", - " d) If distribution of the work is made by offering access to copy", - " from a designated place, offer equivalent access to copy the above", - " specified materials from the same place.", - "", - " e) Verify that the user has already received a copy of these", - " materials or that you have already sent this user a copy.", - "", - " For an executable, the required form of the \"work that uses the", - "Library\" must include any data and utility programs needed for", - "reproducing the executable from it. However, as a special exception,", - "the materials to be distributed need not include anything that is", - "normally distributed (in either source or binary form) with the major", - "components (compiler, kernel, and so on) of the operating system on", - "which the executable runs, unless that component itself accompanies", - "the executable.", - "", - " It may happen that this requirement contradicts the license", - "restrictions of other proprietary libraries that do not normally", - "accompany the operating system. Such a contradiction means you cannot", - "use both them and the Library together in an executable that you", - "distribute.", - "", - " 7. You may place library facilities that are a work based on the", - "Library side-by-side in a single library together with other library", - "facilities not covered by this License, and distribute such a combined", - "library, provided that the separate distribution of the work based on", - "the Library and of the other library facilities is otherwise", - "permitted, and provided that you do these two things:", - "", - " a) Accompany the combined library with a copy of the same work", - " based on the Library, uncombined with any other library", - " facilities. This must be distributed under the terms of the", - " Sections above.", - "", - " b) Give prominent notice with the combined library of the fact", - " that part of it is a work based on the Library, and explaining", - " where to find the accompanying uncombined form of the same work.", - "", - " 8. You may not copy, modify, sublicense, link with, or distribute", - "the Library except as expressly provided under this License. Any", - "attempt otherwise to copy, modify, sublicense, link with, or", - "distribute the Library is void, and will automatically terminate your", - "rights under this License. However, parties who have received copies,", - "or rights, from you under this License will not have their licenses", - "terminated so long as such parties remain in full compliance.", - "", - " 9. You are not required to accept this License, since you have not", - "signed it. However, nothing else grants you permission to modify or", - "distribute the Library or its derivative works. These actions are", - "prohibited by law if you do not accept this License. Therefore, by", - "modifying or distributing the Library (or any work based on the", - "Library), you indicate your acceptance of this License to do so, and", - "all its terms and conditions for copying, distributing or modifying", - "the Library or works based on it.", - "", - " 10. Each time you redistribute the Library (or any work based on the", - "Library), the recipient automatically receives a license from the", - "original licensor to copy, distribute, link with or modify the Library", - "subject to these terms and conditions. You may not impose any further", - "restrictions on the recipients' exercise of the rights granted herein.", - "You are not responsible for enforcing compliance by third parties with", - "this License.", - "", - " 11. If, as a consequence of a court judgment or allegation of patent", - "infringement or for any other reason (not limited to patent issues),", - "conditions are imposed on you (whether by court order, agreement or", - "otherwise) that contradict the conditions of this License, they do not", - "excuse you from the conditions of this License. If you cannot", - "distribute so as to satisfy simultaneously your obligations under this", - "License and any other pertinent obligations, then as a consequence you", - "may not distribute the Library at all. For example, if a patent", - "license would not permit royalty-free redistribution of the Library by", - "all those who receive copies directly or indirectly through you, then", - "the only way you could satisfy both it and this License would be to", - "refrain entirely from distribution of the Library.", - "", - "If any portion of this section is held invalid or unenforceable under any", - "particular circumstance, the balance of the section is intended to apply,", - "and the section as a whole is intended to apply in other circumstances.", - "", - "It is not the purpose of this section to induce you to infringe any", - "patents or other property right claims or to contest validity of any", - "such claims; this section has the sole purpose of protecting the", - "integrity of the free software distribution system which is", - "implemented by public license practices. Many people have made", - "generous contributions to the wide range of software distributed", - "through that system in reliance on consistent application of that", - "system; it is up to the author/donor to decide if he or she is willing", - "to distribute software through any other system and a licensee cannot", - "impose that choice.", - "", - "This section is intended to make thoroughly clear what is believed to", - "be a consequence of the rest of this License.", - "", - " 12. If the distribution and/or use of the Library is restricted in", - "certain countries either by patents or by copyrighted interfaces, the", - "original copyright holder who places the Library under this License may add", - "an explicit geographical distribution limitation excluding those countries,", - "so that distribution is permitted only in or among countries not thus", - "excluded. In such case, this License incorporates the limitation as if", - "written in the body of this License.", - "", - " 13. The Free Software Foundation may publish revised and/or new", - "versions of the Lesser General Public License from time to time.", - "Such new versions will be similar in spirit to the present version,", - "but may differ in detail to address new problems or concerns.", - "", - "Each version is given a distinguishing version number. If the Library", - "specifies a version number of this License which applies to it and", - "\"any later version\", you have the option of following the terms and", - "conditions either of that version or of any later version published by", - "the Free Software Foundation. If the Library does not specify a", - "license version number, you may choose any version ever published by", - "the Free Software Foundation.", - "", - " 14. If you wish to incorporate parts of the Library into other free", - "programs whose distribution conditions are incompatible with these,", - "write to the author to ask for permission. For software which is", - "copyrighted by the Free Software Foundation, write to the Free", - "Software Foundation; we sometimes make exceptions for this. Our", - "decision will be guided by the two goals of preserving the free status", - "of all derivatives of our free software and of promoting the sharing", - "and reuse of software generally.", - "", - "\t\t\t NO WARRANTY", - "", - " 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO", - "WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.", - "EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR", - "OTHER PARTIES PROVIDE THE LIBRARY \"AS IS\" WITHOUT WARRANTY OF ANY", - "KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE", - "IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR", - "PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE", - "LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME", - "THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.", - "", - " 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN", - "WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY", - "AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU", - "FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR", - "CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE", - "LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING", - "RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A", - "FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF", - "SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH", - "DAMAGES.", - "", - "\t\t END OF TERMS AND CONDITIONS", - "", - " How to Apply These Terms to Your New Libraries", - "", - " If you develop a new library, and you want it to be of the greatest", - "possible use to the public, we recommend making it free software that", - "everyone can redistribute and change. You can do so by permitting", - "redistribution under these terms (or, alternatively, under the terms of the", - "ordinary General Public License).", - "", - " To apply these terms, attach the following notices to the library. It is", - "safest to attach them to the start of each source file to most effectively", - "convey the exclusion of warranty; and each file should have at least the", - "\"copyright\" line and a pointer to where the full notice is found.", - "", - " ", - " Copyright (C) ", - "", - " This library is free software; you can redistribute it and/or", - " modify it under the terms of the GNU Lesser General Public", - " License as published by the Free Software Foundation; either", - " version 2.1 of the License, or (at your option) any later version.", - "", - " This library is distributed in the hope that it will be useful,", - " but WITHOUT ANY WARRANTY; without even the implied warranty of", - " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU", - " Lesser General Public License for more details.", - "", - " You should have received a copy of the GNU Lesser General Public", - " License along with this library; if not, write to the Free Software", - " Foundation, Inc.,", - "51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA", - "", - "Also add information on how to contact you by electronic and paper mail.", - "", - "You should also get your employer (if you work as a programmer) or your", - "school, if any, to sign a \"copyright disclaimer\" for the library, if", - "necessary. Here is a sample; alter the names:", - "", - " Yoyodyne, Inc., hereby disclaims all copyright interest in the", - " library `Frob' (a library for tweaking knobs) written by James Random Hacker.", - "", - " ,", - "1 April 1990", - " Ty Coon, President of Vice", - "", - "That's all there is to it!" - ] -}, -{ - // Added here because the module `parse5` has a dependency to it. - // The module `parse5` is shipped via the `extension-editing` built-in extension. - // The module `parse5` does not want to remove it https://github.com/inikulin/parse5/issues/225 - "name": "@types/node", - "licenseDetail": [ - "This project is licensed under the MIT license.", - "Copyrights are respective of each contributor listed at the beginning of each definition file.", - "", - "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." - ] -}, -{ - // 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 - "name": "typescript", - "licenseDetail": [ - "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:", - "", - "You must give any other recipients of the Work or Derivative Works a copy of this License; and", - "", - "You must cause any modified files to carry prominent notices stating that You changed the files; and", - "", - "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", - "", - "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" - ] -}, -{ - // This module comes in from https://github.com/Microsoft/vscode-node-debug2/blob/master/package-lock.json - "name": "@types/source-map", - "licenseDetail": [ - "This project is licensed under the MIT license.", - "Copyrights are respective of each contributor listed at the beginning of each definition file.", - "", - "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." - ] -}, -{ - "name": "tunnel-agent", - "licenseDetail": [ - "Copyright (c) tunnel-agent authors", - "", - "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:", - "", - "You must give any other recipients of the Work or Derivative Works a copy of this License; and", - "", - "You must cause any modified files to carry prominent notices stating that You changed the files; and", - "", - "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", - "", - "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" - ] -}, -{ - // Waiting for https://github.com/segmentio/noop-logger/issues/2 - "name": "noop-logger", - "licenseDetail": [ - "This project is licensed under the MIT license.", - "Copyrights are respective of each contributor listed at the beginning of each definition file.", - "", - "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." - ] -} -] \ No newline at end of file + { + // Reason: The license at https://github.com/aadsm/jschardet/blob/master/LICENSE + // does not include a clear Copyright statement and does not credit authors. + "name": "jschardet", + "licenseDetail": [ + "Chardet was originally ported from C++ by Mark Pilgrim. It is now maintained", + " by Dan Blanchard and Ian Cordasco, and was formerly maintained by Erik Rose.", + " JSChardet was ported from python to JavaScript by António Afonso ", + " (https://github.com/aadsm/jschardet) and transformed into an npm package by ", + "Markus Ast (https://github.com/brainafk)", + "", + "GNU LESSER GENERAL PUBLIC LICENSE", + "\t\t Version 2.1, February 1999", + "", + " Copyright (C) 1991,", + "1999 Free Software Foundation, Inc.", + " 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA", + " Everyone is permitted to copy and distribute verbatim copies", + " of this license document, but changing it is not allowed.", + "", + "[This is the first released version of the Lesser GPL. It also counts", + " as the successor of the GNU Library Public License, version 2, hence", + " the version number 2.1.", + "]", + "", + "\t\t\t Preamble", + "", + " The licenses for most software are designed to take away your", + "freedom to share and change it. By contrast, the GNU General Public", + "Licenses are intended to guarantee your freedom to share and change", + "free software--to make sure the software is free for all its users.", + "", + " This license, the Lesser General Public License, applies to some", + "specially designated software packages--typically libraries--of the", + "Free Software Foundation and other authors who decide to use it. You", + "can use it too, but we suggest you first think carefully about whether", + "this license or the ordinary General Public License is the better", + "strategy to use in any particular case, based on the explanations below.", + "", + " When we speak of free software, we are referring to freedom of use,", + "not price. Our General Public Licenses are designed to make sure that", + "you have the freedom to distribute copies of free software (and charge", + "for this service if you wish); that you receive source code or can get", + "it if you want it; that you can change the software and use pieces of", + "it in new free programs; and that you are informed that you can do", + "these things.", + "", + " To protect your rights, we need to make restrictions that forbid", + "distributors to deny you these rights or to ask you to surrender these", + "rights. These restrictions translate to certain responsibilities for", + "you if you distribute copies of the library or if you modify it.", + "", + " For example, if you distribute copies of the library, whether gratis", + "or for a fee, you must give the recipients all the rights that we gave", + "you. You must make sure that they, too, receive or can get the source", + "code. If you link other code with the library, you must provide", + "complete object files to the recipients, so that they can relink them", + "with the library after making changes to the library and recompiling", + "it. And you must show them these terms so they know their rights.", + "", + " We protect your rights with a two-step method: (1) we copyright the", + "library, and (2) we offer you this license, which gives you legal", + "permission to copy, distribute and/or modify the library.", + "", + " To protect each distributor, we want to make it very clear that", + "there is no warranty for the free library. Also, if the library is", + "modified by someone else and passed on, the recipients should know", + "that what they have is not the original version, so that the original", + "author's reputation will not be affected by problems that might be", + "introduced by others.", + "", + " Finally, software patents pose a constant threat to the existence of", + "any free program. We wish to make sure that a company cannot", + "effectively restrict the users of a free program by obtaining a", + "restrictive license from a patent holder. Therefore, we insist that", + "any patent license obtained for a version of the library must be", + "consistent with the full freedom of use specified in this license.", + "", + " Most GNU software, including some libraries, is covered by the", + "ordinary GNU General Public License. This license, the GNU Lesser", + "General Public License, applies to certain designated libraries, and", + "is quite different from the ordinary General Public License. We use", + "this license for certain libraries in order to permit linking those", + "libraries into non-free programs.", + "", + " When a program is linked with a library, whether statically or using", + "a shared library, the combination of the two is legally speaking a", + "combined work, a derivative of the original library. The ordinary", + "General Public License therefore permits such linking only if the", + "entire combination fits its criteria of freedom. The Lesser General", + "Public License permits more lax criteria for linking other code with", + "the library.", + "", + " We call this license the \"Lesser\" General Public License because it", + "does Less to protect the user's freedom than the ordinary General", + "Public License. It also provides other free software developers Less", + "of an advantage over competing non-free programs. These disadvantages", + "are the reason we use the ordinary General Public License for many", + "libraries. However, the Lesser license provides advantages in certain", + "special circumstances.", + "", + " For example, on rare occasions, there may be a special need to", + "encourage the widest possible use of a certain library, so that it becomes", + "a de-facto standard. To achieve this, non-free programs must be", + "allowed to use the library. A more frequent case is that a free", + "library does the same job as widely used non-free libraries. In this", + "case, there is little to gain by limiting the free library to free", + "software only, so we use the Lesser General Public License.", + "", + " In other cases, permission to use a particular library in non-free", + "programs enables a greater number of people to use a large body of", + "free software. For example, permission to use the GNU C Library in", + "non-free programs enables many more people to use the whole GNU", + "operating system, as well as its variant, the GNU/Linux operating", + "system.", + "", + " Although the Lesser General Public License is Less protective of the", + "users' freedom, it does ensure that the user of a program that is", + "linked with the Library has the freedom and the wherewithal to run", + "that program using a modified version of the Library.", + "", + " The precise terms and conditions for copying, distribution and", + "modification follow. Pay close attention to the difference between a", + "\"work based on the library\" and a \"work that uses the library\". The", + "former contains code derived from the library, whereas the latter must", + "be combined with the library in order to run.", + "", + "\t\t GNU LESSER GENERAL PUBLIC LICENSE", + " TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION", + "", + " 0. This License Agreement applies to any software library or other", + "program which contains a notice placed by the copyright holder or", + "other authorized party saying it may be distributed under the terms of", + "this Lesser General Public License (also called \"this License\").", + "Each licensee is addressed as \"you\".", + "", + " A \"library\" means a collection of software functions and/or data", + "prepared so as to be conveniently linked with application programs", + "(which use some of those functions and data) to form executables.", + "", + " The \"Library\", below, refers to any such software library or work", + "which has been distributed under these terms. A \"work based on the", + "Library\" means either the Library or any derivative work under", + "copyright law: that is to say, a work containing the Library or a", + "portion of it, either verbatim or with modifications and/or translated", + "straightforwardly into another language. (Hereinafter, translation is", + "included without limitation in the term \"modification\".)", + "", + " \"Source code\" for a work means the preferred form of the work for", + "making modifications to it. For a library, complete source code means", + "all the source code for all modules it contains, plus any associated", + "interface definition files, plus the scripts used to control compilation", + "and installation of the library.", + "", + " Activities other than copying, distribution and modification are not", + "covered by this License; they are outside its scope. The act of", + "running a program using the Library is not restricted, and output from", + "such a program is covered only if its contents constitute a work based", + "on the Library (independent of the use of the Library in a tool for", + "writing it). Whether that is true depends on what the Library does", + "and what the program that uses the Library does.", + "", + " 1. You may copy and distribute verbatim copies of the Library's", + "complete source code as you receive it, in any medium, provided that", + "you conspicuously and appropriately publish on each copy an", + "appropriate copyright notice and disclaimer of warranty; keep intact", + "all the notices that refer to this License and to the absence of any", + "warranty; and distribute a copy of this License along with the", + "Library.", + "", + " You may charge a fee for the physical act of transferring a copy,", + "and you may at your option offer warranty protection in exchange for a", + "fee.", + "", + " 2. You may modify your copy or copies of the Library or any portion", + "of it, thus forming a work based on the Library, and copy and", + "distribute such modifications or work under the terms of Section 1", + "above, provided that you also meet all of these conditions:", + "", + " a) The modified work must itself be a software library.", + "", + " b) You must cause the files modified to carry prominent notices", + " stating that you changed the files and the date of any change.", + "", + " c) You must cause the whole of the work to be licensed at no", + " charge to all third parties under the terms of this License.", + "", + " d) If a facility in the modified Library refers to a function or a", + " table of data to be supplied by an application program that uses", + " the facility, other than as an argument passed when the facility", + " is invoked, then you must make a good faith effort to ensure that,", + " in the event an application does not supply such function or", + " table, the facility still operates, and performs whatever part of", + " its purpose remains meaningful.", + "", + " (For example, a function in a library to compute square roots has", + " a purpose that is entirely well-defined independent of the", + " application. Therefore, Subsection 2d requires that any", + " application-supplied function or table used by this function must", + " be optional: if the application does not supply it, the square", + " root function must still compute square roots.)", + "", + "These requirements apply to the modified work as a whole. If", + "identifiable sections of that work are not derived from the Library,", + "and can be reasonably considered independent and separate works in", + "themselves, then this License, and its terms, do not apply to those", + "sections when you distribute them as separate works. But when you", + "distribute the same sections as part of a whole which is a work based", + "on the Library, the distribution of the whole must be on the terms of", + "this License, whose permissions for other licensees extend to the", + "entire whole, and thus to each and every part regardless of who wrote", + "it.", + "", + "Thus, it is not the intent of this section to claim rights or contest", + "your rights to work written entirely by you; rather, the intent is to", + "exercise the right to control the distribution of derivative or", + "collective works based on the Library.", + "", + "In addition, mere aggregation of another work not based on the Library", + "with the Library (or with a work based on the Library) on a volume of", + "a storage or distribution medium does not bring the other work under", + "the scope of this License.", + "", + " 3. You may opt to apply the terms of the ordinary GNU General Public", + "License instead of this License to a given copy of the Library. To do", + "this, you must alter all the notices that refer to this License, so", + "that they refer to the ordinary GNU General Public License, version 2,", + "instead of to this License. (If a newer version than version 2 of the", + "ordinary GNU General Public License has appeared, then you can specify", + "that version instead if you wish.) Do not make any other change in", + "these notices.", + "", + " Once this change is made in a given copy, it is irreversible for", + "that copy, so the ordinary GNU General Public License applies to all", + "subsequent copies and derivative works made from that copy.", + "", + " This option is useful when you wish to copy part of the code of", + "the Library into a program that is not a library.", + "", + " 4. You may copy and distribute the Library (or a portion or", + "derivative of it, under Section 2) in object code or executable form", + "under the terms of Sections 1 and 2 above provided that you accompany", + "it with the complete corresponding machine-readable source code, which", + "must be distributed under the terms of Sections 1 and 2 above on a", + "medium customarily used for software interchange.", + "", + " If distribution of object code is made by offering access to copy", + "from a designated place, then offering equivalent access to copy the", + "source code from the same place satisfies the requirement to", + "distribute the source code, even though third parties are not", + "compelled to copy the source along with the object code.", + "", + " 5. A program that contains no derivative of any portion of the", + "Library, but is designed to work with the Library by being compiled or", + "linked with it, is called a \"work that uses the Library\". Such a", + "work, in isolation, is not a derivative work of the Library, and", + "therefore falls outside the scope of this License.", + "", + " However, linking a \"work that uses the Library\" with the Library", + "creates an executable that is a derivative of the Library (because it", + "contains portions of the Library), rather than a \"work that uses the", + "library\". The executable is therefore covered by this License.", + "Section 6 states terms for distribution of such executables.", + "", + " When a \"work that uses the Library\" uses material from a header file", + "that is part of the Library, the object code for the work may be a", + "derivative work of the Library even though the source code is not.", + "Whether this is true is especially significant if the work can be", + "linked without the Library, or if the work is itself a library. The", + "threshold for this to be true is not precisely defined by law.", + "", + " If such an object file uses only numerical parameters, data", + "structure layouts and accessors, and small macros and small inline", + "functions (ten lines or less in length), then the use of the object", + "file is unrestricted, regardless of whether it is legally a derivative", + "work. (Executables containing this object code plus portions of the", + "Library will still fall under Section 6.)", + "", + " Otherwise, if the work is a derivative of the Library, you may", + "distribute the object code for the work under the terms of Section 6.", + "Any executables containing that work also fall under Section 6,", + "whether or not they are linked directly with the Library itself.", + "", + " 6. As an exception to the Sections above, you may also combine or", + "link a \"work that uses the Library\" with the Library to produce a", + "work containing portions of the Library, and distribute that work", + "under terms of your choice, provided that the terms permit", + "modification of the work for the customer's own use and reverse", + "engineering for debugging such modifications.", + "", + " You must give prominent notice with each copy of the work that the", + "Library is used in it and that the Library and its use are covered by", + "this License. You must supply a copy of this License. If the work", + "during execution displays copyright notices, you must include the", + "copyright notice for the Library among them, as well as a reference", + "directing the user to the copy of this License. Also, you must do one", + "of these things:", + "", + " a) Accompany the work with the complete corresponding", + " machine-readable source code for the Library including whatever", + " changes were used in the work (which must be distributed under", + " Sections 1 and 2 above); and, if the work is an executable linked", + " with the Library, with the complete machine-readable \"work that", + " uses the Library\", as object code and/or source code, so that the", + " user can modify the Library and then relink to produce a modified", + " executable containing the modified Library. (It is understood", + " that the user who changes the contents of definitions files in the", + " Library will not necessarily be able to recompile the application", + " to use the modified definitions.)", + "", + " b) Use a suitable shared library mechanism for linking with the", + " Library. A suitable mechanism is one that (1) uses at run time a", + " copy of the library already present on the user's computer system,", + " rather than copying library functions into the executable, and (2)", + " will operate properly with a modified version of the library, if", + " the user installs one, as long as the modified version is", + " interface-compatible with the version that the work was made with.", + "", + " c) Accompany the work with a written offer, valid for at", + " least three years, to give the same user the materials", + " specified in Subsection 6a, above, for a charge no more", + " than the cost of performing this distribution.", + "", + " d) If distribution of the work is made by offering access to copy", + " from a designated place, offer equivalent access to copy the above", + " specified materials from the same place.", + "", + " e) Verify that the user has already received a copy of these", + " materials or that you have already sent this user a copy.", + "", + " For an executable, the required form of the \"work that uses the", + "Library\" must include any data and utility programs needed for", + "reproducing the executable from it. However, as a special exception,", + "the materials to be distributed need not include anything that is", + "normally distributed (in either source or binary form) with the major", + "components (compiler, kernel, and so on) of the operating system on", + "which the executable runs, unless that component itself accompanies", + "the executable.", + "", + " It may happen that this requirement contradicts the license", + "restrictions of other proprietary libraries that do not normally", + "accompany the operating system. Such a contradiction means you cannot", + "use both them and the Library together in an executable that you", + "distribute.", + "", + " 7. You may place library facilities that are a work based on the", + "Library side-by-side in a single library together with other library", + "facilities not covered by this License, and distribute such a combined", + "library, provided that the separate distribution of the work based on", + "the Library and of the other library facilities is otherwise", + "permitted, and provided that you do these two things:", + "", + " a) Accompany the combined library with a copy of the same work", + " based on the Library, uncombined with any other library", + " facilities. This must be distributed under the terms of the", + " Sections above.", + "", + " b) Give prominent notice with the combined library of the fact", + " that part of it is a work based on the Library, and explaining", + " where to find the accompanying uncombined form of the same work.", + "", + " 8. You may not copy, modify, sublicense, link with, or distribute", + "the Library except as expressly provided under this License. Any", + "attempt otherwise to copy, modify, sublicense, link with, or", + "distribute the Library is void, and will automatically terminate your", + "rights under this License. However, parties who have received copies,", + "or rights, from you under this License will not have their licenses", + "terminated so long as such parties remain in full compliance.", + "", + " 9. You are not required to accept this License, since you have not", + "signed it. However, nothing else grants you permission to modify or", + "distribute the Library or its derivative works. These actions are", + "prohibited by law if you do not accept this License. Therefore, by", + "modifying or distributing the Library (or any work based on the", + "Library), you indicate your acceptance of this License to do so, and", + "all its terms and conditions for copying, distributing or modifying", + "the Library or works based on it.", + "", + " 10. Each time you redistribute the Library (or any work based on the", + "Library), the recipient automatically receives a license from the", + "original licensor to copy, distribute, link with or modify the Library", + "subject to these terms and conditions. You may not impose any further", + "restrictions on the recipients' exercise of the rights granted herein.", + "You are not responsible for enforcing compliance by third parties with", + "this License.", + "", + " 11. If, as a consequence of a court judgment or allegation of patent", + "infringement or for any other reason (not limited to patent issues),", + "conditions are imposed on you (whether by court order, agreement or", + "otherwise) that contradict the conditions of this License, they do not", + "excuse you from the conditions of this License. If you cannot", + "distribute so as to satisfy simultaneously your obligations under this", + "License and any other pertinent obligations, then as a consequence you", + "may not distribute the Library at all. For example, if a patent", + "license would not permit royalty-free redistribution of the Library by", + "all those who receive copies directly or indirectly through you, then", + "the only way you could satisfy both it and this License would be to", + "refrain entirely from distribution of the Library.", + "", + "If any portion of this section is held invalid or unenforceable under any", + "particular circumstance, the balance of the section is intended to apply,", + "and the section as a whole is intended to apply in other circumstances.", + "", + "It is not the purpose of this section to induce you to infringe any", + "patents or other property right claims or to contest validity of any", + "such claims; this section has the sole purpose of protecting the", + "integrity of the free software distribution system which is", + "implemented by public license practices. Many people have made", + "generous contributions to the wide range of software distributed", + "through that system in reliance on consistent application of that", + "system; it is up to the author/donor to decide if he or she is willing", + "to distribute software through any other system and a licensee cannot", + "impose that choice.", + "", + "This section is intended to make thoroughly clear what is believed to", + "be a consequence of the rest of this License.", + "", + " 12. If the distribution and/or use of the Library is restricted in", + "certain countries either by patents or by copyrighted interfaces, the", + "original copyright holder who places the Library under this License may add", + "an explicit geographical distribution limitation excluding those countries,", + "so that distribution is permitted only in or among countries not thus", + "excluded. In such case, this License incorporates the limitation as if", + "written in the body of this License.", + "", + " 13. The Free Software Foundation may publish revised and/or new", + "versions of the Lesser General Public License from time to time.", + "Such new versions will be similar in spirit to the present version,", + "but may differ in detail to address new problems or concerns.", + "", + "Each version is given a distinguishing version number. If the Library", + "specifies a version number of this License which applies to it and", + "\"any later version\", you have the option of following the terms and", + "conditions either of that version or of any later version published by", + "the Free Software Foundation. If the Library does not specify a", + "license version number, you may choose any version ever published by", + "the Free Software Foundation.", + "", + " 14. If you wish to incorporate parts of the Library into other free", + "programs whose distribution conditions are incompatible with these,", + "write to the author to ask for permission. For software which is", + "copyrighted by the Free Software Foundation, write to the Free", + "Software Foundation; we sometimes make exceptions for this. Our", + "decision will be guided by the two goals of preserving the free status", + "of all derivatives of our free software and of promoting the sharing", + "and reuse of software generally.", + "", + "\t\t\t NO WARRANTY", + "", + " 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO", + "WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.", + "EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR", + "OTHER PARTIES PROVIDE THE LIBRARY \"AS IS\" WITHOUT WARRANTY OF ANY", + "KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE", + "IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR", + "PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE", + "LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME", + "THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.", + "", + " 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN", + "WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY", + "AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU", + "FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR", + "CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE", + "LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING", + "RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A", + "FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF", + "SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH", + "DAMAGES.", + "", + "\t\t END OF TERMS AND CONDITIONS", + "", + " How to Apply These Terms to Your New Libraries", + "", + " If you develop a new library, and you want it to be of the greatest", + "possible use to the public, we recommend making it free software that", + "everyone can redistribute and change. You can do so by permitting", + "redistribution under these terms (or, alternatively, under the terms of the", + "ordinary General Public License).", + "", + " To apply these terms, attach the following notices to the library. It is", + "safest to attach them to the start of each source file to most effectively", + "convey the exclusion of warranty; and each file should have at least the", + "\"copyright\" line and a pointer to where the full notice is found.", + "", + " ", + " Copyright (C) ", + "", + " This library is free software; you can redistribute it and/or", + " modify it under the terms of the GNU Lesser General Public", + " License as published by the Free Software Foundation; either", + " version 2.1 of the License, or (at your option) any later version.", + "", + " This library is distributed in the hope that it will be useful,", + " but WITHOUT ANY WARRANTY; without even the implied warranty of", + " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU", + " Lesser General Public License for more details.", + "", + " You should have received a copy of the GNU Lesser General Public", + " License along with this library; if not, write to the Free Software", + " Foundation, Inc.,", + "51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA", + "", + "Also add information on how to contact you by electronic and paper mail.", + "", + "You should also get your employer (if you work as a programmer) or your", + "school, if any, to sign a \"copyright disclaimer\" for the library, if", + "necessary. Here is a sample; alter the names:", + "", + " Yoyodyne, Inc., hereby disclaims all copyright interest in the", + " library `Frob' (a library for tweaking knobs) written by James Random Hacker.", + "", + " ,", + "1 April 1990", + " Ty Coon, President of Vice", + "", + "That's all there is to it!" + ] + }, + { + // Added here because the module `parse5` has a dependency to it. + // The module `parse5` is shipped via the `extension-editing` built-in extension. + // The module `parse5` does not want to remove it https://github.com/inikulin/parse5/issues/225 + "name": "@types/node", + "licenseDetail": [ + "This project is licensed under the MIT license.", + "Copyrights are respective of each contributor listed at the beginning of each definition file.", + "", + "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." + ] + }, + { + // 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 + "name": "typescript", + "licenseDetail": [ + "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:", + "", + "You must give any other recipients of the Work or Derivative Works a copy of this License; and", + "", + "You must cause any modified files to carry prominent notices stating that You changed the files; and", + "", + "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", + "", + "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" + ] + }, + { + // This module comes in from https://github.com/Microsoft/vscode-node-debug2/blob/master/package-lock.json + "name": "@types/source-map", + "licenseDetail": [ + "This project is licensed under the MIT license.", + "Copyrights are respective of each contributor listed at the beginning of each definition file.", + "", + "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." + ] + }, + { + "name": "tunnel-agent", + "licenseDetail": [ + "Copyright (c) tunnel-agent authors", + "", + "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:", + "", + "You must give any other recipients of the Work or Derivative Works a copy of this License; and", + "", + "You must cause any modified files to carry prominent notices stating that You changed the files; and", + "", + "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", + "", + "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" + ] + }, + { + // Waiting for https://github.com/segmentio/noop-logger/issues/2 + "name": "noop-logger", + "licenseDetail": [ + "This project is licensed under the MIT license.", + "Copyrights are respective of each contributor listed at the beginning of each definition file.", + "", + "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." + ] + }, + { + "name": "xterm-addon-search", + "licenseDetail": [ + "Copyright (c) 2017, The xterm.js authors (https://github.com/xtermjs/xterm.js)", + "", + "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." + ] + }, + { + "name": "xterm-addon-web-links", + "licenseDetail": [ + "Copyright (c) 2017, The xterm.js authors (https://github.com/xtermjs/xterm.js)", + "", + "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." + ] + }, + { + "name": "atob", + "licenseDetail": [ + "The MIT License (MIT)", + "", + "Copyright (c) 2015 AJ ONeal", + "", + "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/cgmanifest.json b/cgmanifest.json index 01cdd8df5..638303702 100644 --- a/cgmanifest.json +++ b/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "chromium", "repositoryUrl": "https://chromium.googlesource.com/chromium/src", - "commitHash": "164c37e3f235134c88e80fac2a182cfba3f07f00" + "commitHash": "c6a08e5368de4352903e702cde750b33239a50ab" } }, "licenseDetail": [ @@ -40,20 +40,7 @@ "SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ], "isOnlyProductionDependency": true, - "version": "66.0.3359.181" - }, - { - "component": { - "type": "git", - "git": { - "name": "libchromiumcontent", - "repositoryUrl": "https://github.com/electron/libchromiumcontent", - "commitHash": "7ea271f92018b1eeb8e70ec6de8c29f9758a0c05" - } - }, - "isOnlyProductionDependency": true, - "license": "MIT", - "version": "66.0.3359.181" + "version": "69.0.3497.128" }, { "component": { @@ -61,11 +48,11 @@ "git": { "name": "nodejs", "repositoryUrl": "https://github.com/nodejs/node", - "commitHash": "5cbb905c1af7cea2d709932d59827d7c6d03ef4a" + "commitHash": "8c70b2084ce5f76ea1e3b3c4ccdeee4483fe338b" } }, "isOnlyProductionDependency": true, - "version": "10.2.0" + "version": "10.11.0" }, { "component": { @@ -73,12 +60,12 @@ "git": { "name": "electron", "repositoryUrl": "https://github.com/electron/electron", - "commitHash": "e84a6860e35e14b4031b88bb9b49841cdb89a305" + "commitHash": "36ea114ac0616e469e75ae94e6d53af48925e036" } }, "isOnlyProductionDependency": true, "license": "MIT", - "version": "3.1.8" + "version": "4.2.7" }, { "component": { @@ -111,11 +98,11 @@ "git": { "name": "vscode-octicons-font", "repositoryUrl": "https://github.com/Microsoft/vscode-octicons-font", - "commitHash": "4f69de3a233ed501c2098e33047e116ac2fbbf42" + "commitHash": "415cd5b42ab699b6b46c0bf011ada0a2ae50bfb4" } }, "license": "MIT", - "version": "1.1.0" + "version": "1.3.1" }, { "component": { diff --git a/extensions/bat/package.json b/extensions/bat/package.json index c54d1a4ce..00bd84e4a 100644 --- a/extensions/bat/package.json +++ b/extensions/bat/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "*" }, "scripts": { "update-grammar": "node ../../build/npm/update-grammar.js mmims/language-batchfile grammars/batchfile.cson ./syntaxes/batchfile.tmLanguage.json" diff --git a/extensions/clojure/cgmanifest.json b/extensions/clojure/cgmanifest.json index 1a9d69c56..3a72fefb3 100644 --- a/extensions/clojure/cgmanifest.json +++ b/extensions/clojure/cgmanifest.json @@ -6,11 +6,11 @@ "git": { "name": "atom/language-clojure", "repositoryUrl": "https://github.com/atom/language-clojure", - "commitHash": "ecc790326bc8e14220e4d2d72a392a30876c3219" + "commitHash": "de877502aa4a77ccdc2c7f0c9180436aea3effff" } }, "license": "MIT", - "version": "0.22.6", + "version": "0.22.7", "description": "The file syntaxes/clojure.tmLanguage.json was derived from the Atom package https://github.com/atom/language-clojure which was originally converted from the TextMate bundle https://github.com/mmcgrana/textmate-clojure." } ], diff --git a/extensions/clojure/package.json b/extensions/clojure/package.json index 769b9f467..334278434 100644 --- a/extensions/clojure/package.json +++ b/extensions/clojure/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "*" }, "scripts": { "update-grammar": "node ../../build/npm/update-grammar.js atom/language-clojure grammars/clojure.cson ./syntaxes/clojure.tmLanguage.json" diff --git a/extensions/clojure/syntaxes/clojure.tmLanguage.json b/extensions/clojure/syntaxes/clojure.tmLanguage.json index 3d059513a..29c25edfa 100644 --- a/extensions/clojure/syntaxes/clojure.tmLanguage.json +++ b/extensions/clojure/syntaxes/clojure.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-clojure/commit/ecc790326bc8e14220e4d2d72a392a30876c3219", + "version": "https://github.com/atom/language-clojure/commit/de877502aa4a77ccdc2c7f0c9180436aea3effff", "name": "Clojure", "scopeName": "source.clojure", "patterns": [ @@ -83,7 +83,7 @@ "name": "constant.numeric.ratio.clojure" }, { - "match": "(-?\\d+[rR][0-9a-zA-Z]+)", + "match": "(-?\\d+[rR]\\w+)", "name": "constant.numeric.arbitrary-radix.clojure" }, { @@ -116,17 +116,17 @@ ] }, "keyword": { - "match": "(?<=(\\s|\\(|\\[|\\{)):[a-zA-Z0-9\\#\\.\\-\\_\\:\\+\\=\\>\\<\\/\\!\\?\\*]+(?=(\\s|\\)|\\]|\\}|\\,))", + "match": "(?<=(\\s|\\(|\\[|\\{)):[\\w\\#\\.\\-\\_\\:\\+\\=\\>\\<\\/\\!\\?\\*]+(?=(\\s|\\)|\\]|\\}|\\,))", "name": "constant.keyword.clojure" }, "keyfn": { "patterns": [ { - "match": "(?<=(\\s|\\(|\\[|\\{))(if(-[-a-z\\?]*)?|when(-[-a-z]*)?|for(-[-a-z]*)?|cond|do|let(-[-a-z\\?]*)?|binding|loop|recur|fn|throw[a-z\\-]*|try|catch|finally|([a-z]*case))(?=(\\s|\\)|\\]|\\}))", + "match": "(?<=(\\s|\\(|\\[|\\{))(if(-[-\\p{Ll}\\?]*)?|when(-[-\\p{Ll}]*)?|for(-[-\\p{Ll}]*)?|cond|do|let(-[-\\p{Ll}\\?]*)?|binding|loop|recur|fn|throw[\\p{Ll}\\-]*|try|catch|finally|([\\p{Ll}]*case))(?=(\\s|\\)|\\]|\\}))", "name": "storage.control.clojure" }, { - "match": "(?<=(\\s|\\(|\\[|\\{))(declare-?|(in-)?ns|import|use|require|load|compile|(def[a-z\\-]*))(?=(\\s|\\)|\\]|\\}))", + "match": "(?<=(\\s|\\(|\\[|\\{))(declare-?|(in-)?ns|import|use|require|load|compile|(def[\\p{Ll}\\-]*))(?=(\\s|\\)|\\]|\\}))", "name": "keyword.control.clojure" } ] @@ -309,7 +309,7 @@ "include": "#dynamic-variables" }, { - "match": "([a-zA-Z\\.\\-\\_\\+\\=\\>\\<\\!\\?\\*][\\w\\.\\-\\_\\:\\+\\=\\>\\<\\!\\?\\*\\d]*)", + "match": "([\\p{L}\\.\\-\\_\\+\\=\\>\\<\\!\\?\\*][\\w\\.\\-\\_\\:\\+\\=\\>\\<\\!\\?\\*\\d]*)", "name": "entity.global.clojure" }, { @@ -387,7 +387,7 @@ "namespace-symbol": { "patterns": [ { - "match": "([a-zA-Z\\.\\-\\_\\+\\=\\>\\<\\!\\?\\*][\\w\\.\\-\\_\\:\\+\\=\\>\\<\\!\\?\\*\\d]*)/", + "match": "([\\p{L}\\.\\-\\_\\+\\=\\>\\<\\!\\?\\*][\\w\\.\\-\\_\\:\\+\\=\\>\\<\\!\\?\\*\\d]*)/", "captures": { "1": { "name": "meta.symbol.namespace.clojure" @@ -399,13 +399,13 @@ "symbol": { "patterns": [ { - "match": "([a-zA-Z\\.\\-\\_\\+\\=\\>\\<\\!\\?\\*][\\w\\.\\-\\_\\:\\+\\=\\>\\<\\!\\?\\*\\d]*)", + "match": "([\\p{L}\\.\\-\\_\\+\\=\\>\\<\\!\\?\\*][\\w\\.\\-\\_\\:\\+\\=\\>\\<\\!\\?\\*\\d]*)", "name": "meta.symbol.clojure" } ] }, "var": { - "match": "(?<=(\\s|\\(|\\[|\\{)\\#)'[a-zA-Z0-9\\.\\-\\_\\:\\+\\=\\>\\<\\/\\!\\?\\*]+(?=(\\s|\\)|\\]|\\}))", + "match": "(?<=(\\s|\\(|\\[|\\{)\\#)'[\\w\\.\\-\\_\\:\\+\\=\\>\\<\\/\\!\\?\\*]+(?=(\\s|\\)|\\]|\\}))", "name": "meta.var.clojure" }, "vector": { diff --git a/extensions/coffeescript/package.json b/extensions/coffeescript/package.json index 8d9293a88..df5f8ff7c 100644 --- a/extensions/coffeescript/package.json +++ b/extensions/coffeescript/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "*" }, "scripts": { "update-grammar": "node ../../build/npm/update-grammar.js atom/language-coffee-script grammars/coffeescript.cson ./syntaxes/coffeescript.tmLanguage.json" diff --git a/extensions/configuration-editing/package.json b/extensions/configuration-editing/package.json index bb9690a07..e555d6145 100644 --- a/extensions/configuration-editing/package.json +++ b/extensions/configuration-editing/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "^1.0.0" }, @@ -96,10 +97,18 @@ { "fileMatch": "/.vscode/extensions.json", "url": "vscode://schemas/extensions" + }, + { + "fileMatch": "/.devcontainer/devcontainer.json", + "url": "./schemas/devContainer.schema.json" + }, + { + "fileMatch": "/.devcontainer.json", + "url": "./schemas/devContainer.schema.json" } ] }, "devDependencies": { - "@types/node": "^10.12.21" + "@types/node": "^10.14.8" } } diff --git a/extensions/configuration-editing/schemas/devContainer.schema.json b/extensions/configuration-editing/schemas/devContainer.schema.json new file mode 100644 index 000000000..55950a902 --- /dev/null +++ b/extensions/configuration-editing/schemas/devContainer.schema.json @@ -0,0 +1,181 @@ +{ + "$schema": "http://json-schema.org/schema#", + "description": "Defines a dev container", + "allowComments": true, + "type": "object", + "definitions": { + "devContainerCommon": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "A name to show for the workspace folder." + }, + "extensions": { + "type": "array", + "description": "An array of extensions that should be installed into the container.", + "items": { + "type": "string" + } + }, + "settings": { + "$ref": "vscode://schemas/settings/machine", + "description": "Machine specific settings that should be copied into the container." + }, + "postCreateCommand": { + "type": [ + "string", + "array" + ], + "description": "A command to run after creating the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", + "items": { + "type": "string" + } + }, + "devPort": { + "type": "integer", + "description": "The port VS Code can use to connect to its backend." + } + } + }, + "nonComposeBase": { + "type": "object", + "properties": { + "appPort": { + "type": [ + "integer", + "string", + "array" + ], + "description": "Application ports that are exposed by the container. This can be a single port or an array of ports. Each port can be a number or a string. A number is mapped to the same port on the host. A string is passed to Docker unchanged and can be used to map ports differently, e.g. \"8000:8010\".", + "items": { + "type": [ + "integer", + "string" + ] + } + }, + "runArgs": { + "type": "array", + "description": "The arguments required when starting in the container.", + "items": { + "type": "string" + } + }, + "shutdownAction": { + "type": "string", + "enum": [ + "none", + "stopContainer" + ], + "description": "Action to take when VS Code is shutting down. The default is to stop the container." + }, + "overrideCommand": { + "type": "boolean", + "description": "Whether to overwrite the command specified in the image. The default is true." + }, + "workspaceFolder": { + "type": "string", + "description": "The path of the workspace folder inside the container." + }, + "workspaceMount": { + "type": "string", + "description": "The --mount parameter for docker run. The default is to mount the project folder at /workspaces/$project." + } + } + }, + "dockerFileContainer": { + "type": "object", + "properties": { + "dockerFile": { + "type": "string", + "description": "The location of the Dockerfile that defines the contents of the container. The path is relative to the folder containing the `devcontainer.json` file." + }, + "context": { + "type": "string", + "description": "The location of the context folder for building the Docker image. The path is relative to the folder containing the `devcontainer.json` file." + } + }, + "required": [ + "dockerFile" + ] + }, + "imageContainer": { + "type": "object", + "properties": { + "image": { + "type": "string", + "description": "The docker image that will be used to create the container." + } + }, + "required": [ + "image" + ] + }, + "composeContainer": { + "type": "object", + "properties": { + "dockerComposeFile": { + "type": [ + "string", + "array" + ], + "description": "The name of the docker-compose file(s) used to start the services.", + "items": { + "type": "string" + } + }, + "service": { + "type": "string", + "description": "The service you want to work on." + }, + "workspaceFolder": { + "type": "string", + "description": "The path of the workspace folder inside the container." + }, + "shutdownAction": { + "type": "string", + "enum": [ + "none", + "stopCompose" + ], + "description": "Action to take when VS Code is shutting down. The default is to stop the containers." + } + }, + "required": [ + "dockerComposeFile", + "service", + "workspaceFolder" + ] + } + }, + "allOf": [ + { + "oneOf": [ + { + "allOf": [ + { + "oneOf": [ + { + "$ref": "#/definitions/dockerFileContainer" + }, + { + "$ref": "#/definitions/imageContainer" + } + ] + }, + { + "$ref": "#/definitions/nonComposeBase" + } + ] + }, + { + "$ref": "#/definitions/composeContainer" + } + ] + }, + { + "$ref": "#/definitions/devContainerCommon" + } + ] +} \ No newline at end of file diff --git a/extensions/configuration-editing/src/extension.ts b/extensions/configuration-editing/src/extension.ts index 913c52888..aff533d86 100644 --- a/extensions/configuration-editing/src/extension.ts +++ b/extensions/configuration-editing/src/extension.ts @@ -63,11 +63,20 @@ function registerVariableCompletions(pattern: string): vscode.Disposable { const indexOf$ = document.lineAt(position.line).text.indexOf('$'); const startPosition = indexOf$ >= 0 ? new vscode.Position(position.line, indexOf$) : position; - return [{ label: 'workspaceFolder', detail: localize('workspaceFolder', "The path of the folder opened in VS Code") }, { label: 'workspaceFolderBasename', detail: localize('workspaceFolderBasename', "The name of the folder opened in VS Code without any slashes (/)") }, - { label: 'relativeFile', detail: localize('relativeFile', "The current opened file relative to ${workspaceFolder}") }, { label: 'file', detail: localize('file', "The current opened file") }, { label: 'cwd', detail: localize('cwd', "The task runner's current working directory on startup") }, - { label: 'lineNumber', detail: localize('lineNumber', "The current selected line number in the active file") }, { label: 'selectedText', detail: localize('selectedText', "The current selected text in the active file") }, - { label: 'fileDirname', detail: localize('fileDirname', "The current opened file's dirname") }, { label: 'fileExtname', detail: localize('fileExtname', "The current opened file's extension") }, { label: 'fileBasename', detail: localize('fileBasename', "The current opened file's basename") }, - { label: 'fileBasenameNoExtension', detail: localize('fileBasenameNoExtension', "The current opened file's basename with no file extension") }].map(variable => ({ + return [ + { label: 'workspaceFolder', detail: localize('workspaceFolder', "The path of the folder opened in VS Code") }, + { label: 'workspaceFolderBasename', detail: localize('workspaceFolderBasename', "The name of the folder opened in VS Code without any slashes (/)") }, + { label: 'relativeFile', detail: localize('relativeFile', "The current opened file relative to ${workspaceFolder}") }, + { label: 'relativeFileDirname', detail: localize('relativeFileDirname', "The current opened file's dirname relative to ${workspaceFolder}") }, + { label: 'file', detail: localize('file', "The current opened file") }, + { label: 'cwd', detail: localize('cwd', "The task runner's current working directory on startup") }, + { label: 'lineNumber', detail: localize('lineNumber', "The current selected line number in the active file") }, + { label: 'selectedText', detail: localize('selectedText', "The current selected text in the active file") }, + { label: 'fileDirname', detail: localize('fileDirname', "The current opened file's dirname") }, + { label: 'fileExtname', detail: localize('fileExtname', "The current opened file's extension") }, + { label: 'fileBasename', detail: localize('fileBasename', "The current opened file's basename") }, + { label: 'fileBasenameNoExtension', detail: localize('fileBasenameNoExtension', "The current opened file's basename with no file extension") } + ].map(variable => ({ label: '${' + variable.label + '}', range: new vscode.Range(startPosition, position), detail: variable.detail diff --git a/extensions/configuration-editing/yarn.lock b/extensions/configuration-editing/yarn.lock index 49c471660..ce653f097 100644 --- a/extensions/configuration-editing/yarn.lock +++ b/extensions/configuration-editing/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@types/node@^10.12.21": - version "10.12.21" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.21.tgz#7e8a0c34cf29f4e17a36e9bd0ea72d45ba03908e" - integrity sha512-CBgLNk4o3XMnqMc0rhb6lc77IwShMEglz05deDcn2lQxyXEZivfwgYJu7SMha9V5XcrP6qZuevTHV/QrN2vjKQ== +"@types/node@^10.14.8": + version "10.14.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9" + integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw== jsonc-parser@2.0.2: version "2.0.2" diff --git a/extensions/cpp/build/update-grammars.js b/extensions/cpp/build/update-grammars.js index 406b32615..29761cdaf 100644 --- a/extensions/cpp/build/update-grammars.js +++ b/extensions/cpp/build/update-grammars.js @@ -6,8 +6,8 @@ var updateGrammar = require('../../../build/npm/update-grammar'); -updateGrammar.update('jeff-hykin/cpp-textmate-grammar', '/syntaxes/c.tmLanguage.json', './syntaxes/c.tmLanguage.json'); -updateGrammar.update('jeff-hykin/cpp-textmate-grammar', '/syntaxes/cpp.tmLanguage.json', './syntaxes/cpp.tmLanguage.json'); +updateGrammar.update('jeff-hykin/cpp-textmate-grammar', '/syntaxes/c.tmLanguage.json', './syntaxes/c.tmLanguage.json', undefined, 'master', 'source/languages/cpp'); +updateGrammar.update('jeff-hykin/cpp-textmate-grammar', '/syntaxes/cpp.tmLanguage.json', './syntaxes/cpp.tmLanguage.json', undefined, 'master', 'source/languages/cpp'); // `source.c.platform` which is still included by other grammars updateGrammar.update('textmate/c.tmbundle', 'Syntaxes/Platform.tmLanguage', './syntaxes/platform.tmLanguage.json'); diff --git a/extensions/cpp/cgmanifest.json b/extensions/cpp/cgmanifest.json index aba5bb7f1..6716fa1a2 100644 --- a/extensions/cpp/cgmanifest.json +++ b/extensions/cpp/cgmanifest.json @@ -6,11 +6,11 @@ "git": { "name": "jeff-hykin/cpp-textmate-grammar", "repositoryUrl": "https://github.com/jeff-hykin/cpp-textmate-grammar", - "commitHash": "3fa2a8862b6a06ca381f8e46eb782e5dd014d426" + "commitHash": "992c5ba8789288707f2a13778452d644677d9699" } }, "license": "MIT", - "version": "1.8.8", + "version": "1.12.18", "description": "The files syntaxes/c.json and syntaxes/c++.json were derived from https://github.com/atom/language-c which was originally converted from the C TextMate bundle https://github.com/textmate/c.tmbundle." }, { diff --git a/extensions/cpp/language-configuration.json b/extensions/cpp/language-configuration.json index e50df32dd..d430c4d15 100644 --- a/extensions/cpp/language-configuration.json +++ b/extensions/cpp/language-configuration.json @@ -29,4 +29,4 @@ "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 ff7ddb102..6d8ae8b81 100644 --- a/extensions/cpp/package.json +++ b/extensions/cpp/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "*" }, "scripts": { "update-grammar": "node ./build/update-grammars.js" @@ -17,7 +18,7 @@ }, { "id": "cpp", - "extensions": [ ".cpp", ".cc", ".cxx", ".hpp", ".hh", ".hxx", ".h", ".ino", ".inl", ".ipp" ], + "extensions": [ ".cpp", ".cc", ".cxx", ".hpp", ".hh", ".hxx", ".h", ".i", ".ino", ".inl", ".ipp", ".hpp.in", ".h.in" ], "aliases": [ "C++", "Cpp", "cpp"], "configuration": "./language-configuration.json" }], @@ -44,4 +45,4 @@ "path": "./snippets/cpp.json" }] } -} \ No newline at end of file +} diff --git a/extensions/cpp/syntaxes/c.tmLanguage.json b/extensions/cpp/syntaxes/c.tmLanguage.json index e02a6d883..91be1a66b 100644 --- a/extensions/cpp/syntaxes/c.tmLanguage.json +++ b/extensions/cpp/syntaxes/c.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/jeff-hykin/cpp-textmate-grammar/commit/98cbae6aca391825a7612825f9677f22fe70dd68", + "version": "https://github.com/jeff-hykin/cpp-textmate-grammar/commit/1a24b4aa383169919f0d92cf2735ac35a3e7db3c", "name": "C", "scopeName": "source.c", "patterns": [ @@ -17,6 +17,9 @@ { "include": "#preprocessor-rule-conditional" }, + { + "include": "#predefined_macros" + }, { "include": "#comments" }, @@ -267,108 +270,1819 @@ "1": { "name": "keyword.control.directive.pragma.c" }, - "2": { - "name": "punctuation.definition.directive.c" - } - }, - "end": "(?=(?://|/\\*))|(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?|\\?\\?>)|(?=[;>\\[\\]=]))", + "patterns": [ + { + "name": "meta.head.switch.c", + "begin": "\\G ?", + "end": "((?:\\{|<%|\\?\\?<|(?=;)))", + "endCaptures": { + "1": { + "name": "punctuation.section.block.begin.bracket.curly.switch.c" + } + }, + "patterns": [ + { + "include": "#switch_conditional_parentheses" + }, + { + "include": "$base" + } + ] + }, + { + "name": "meta.body.switch.c", + "begin": "(?<=\\{|<%|\\?\\?<)", + "end": "(\\}|%>|\\?\\?>)", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.switch.c" + } + }, + "patterns": [ + { + "include": "#default_statement" + }, + { + "include": "#case_statement" + }, + { + "include": "$base" + }, + { + "include": "#block_innards" + } + ] + }, + { + "name": "meta.tail.switch.c", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "include": "$base" + } + ] + } + ] + }, + "switch_conditional_parentheses": { + "name": "meta.conditional.switch.c", + "begin": "((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()", + "beginCaptures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.c punctuation.definition.comment.begin.c" + }, + "3": { + "name": "comment.block.c" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.c punctuation.definition.comment.end.c" + }, + { + "match": "\\*", + "name": "comment.block.c" + } + ] + }, + "5": { + "name": "punctuation.section.parens.begin.bracket.round.conditional.switch.c" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.parens.end.bracket.round.conditional.switch.c" + } + }, + "patterns": [ + { + "include": "#evaluation_context" + }, + { + "include": "#c_conditional_context" + } + ] + }, + "static_assert": { + "begin": "((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()", + "beginCaptures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.c punctuation.definition.comment.begin.c" + }, + "3": { + "name": "comment.block.c" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.c punctuation.definition.comment.end.c" + }, + { + "match": "\\*", + "name": "comment.block.c" + } + ] + }, + "5": { + "name": "keyword.other.static_assert.c" + }, + "6": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "7": { + "name": "comment.block.c punctuation.definition.comment.begin.c" + }, + "8": { + "name": "comment.block.c" + }, + "9": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.c punctuation.definition.comment.end.c" + }, + { + "match": "\\*", + "name": "comment.block.c" + } + ] + }, + "10": { + "name": "punctuation.section.arguments.begin.bracket.round.static_assert.c" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.arguments.end.bracket.round.static_assert.c" + } + }, + "patterns": [ + { + "name": "meta.static_assert.message.c", + "begin": "(,)\\s*(?=(?:L|u8|u|U\\s*\\\")?)", + "beginCaptures": { + "1": { + "name": "punctuation.separator.delimiter.comma.c" + } + }, + "end": "(?=\\))", + "patterns": [ + { + "include": "#string_context" + }, + { + "include": "#string_context_c" + } + ] + }, + { + "include": "#evaluation_context" + } + ] + }, + "backslash_escapes": { + "match": "(?x)\\\\ (\n\\\\\t\t\t |\n[abefnprtv'\"?] |\n[0-3]\\d{,2}\t |\n[4-7]\\d?\t\t|\nx[a-fA-F0-9]{,2} |\nu[a-fA-F0-9]{,4} |\nU[a-fA-F0-9]{,8} )", + "name": "constant.character.escape.c" + }, + "c_conditional_context": { + "patterns": [ + { + "include": "$base" + }, + { + "include": "#block_innards" + } + ] + }, + "evalutation_context": { + "patterns": [ + { + "include": "#function-call-innards" + }, + { + "include": "$base" + } + ] + }, + "member_access": { + "match": "((?:[a-zA-Z_]\\w*|(?<=\\]|\\)))\\s*)(?:((?:\\.\\*|\\.))|((?:->\\*|->)))((?:[a-zA-Z_]\\w*\\s*(?:(?:(?:\\.\\*|\\.))|(?:(?:->\\*|->)))\\s*)*)\\s*(\\b(?!(?:void|char|short|int|signed|unsigned|long|float|double|bool|_Bool|_Complex|_Imaginary|u_char|u_short|u_int|u_long|ushort|uint|u_quad_t|quad_t|qaddr_t|caddr_t|daddr_t|div_t|dev_t|fixpt_t|blkcnt_t|blksize_t|gid_t|in_addr_t|in_port_t|ino_t|key_t|mode_t|nlink_t|id_t|pid_t|off_t|segsz_t|swblk_t|uid_t|id_t|clock_t|size_t|ssize_t|time_t|useconds_t|suseconds_t|pthread_attr_t|pthread_cond_t|pthread_condattr_t|pthread_mutex_t|pthread_mutexattr_t|pthread_once_t|pthread_rwlock_t|pthread_rwlockattr_t|pthread_t|pthread_key_t|int8_t|int16_t|int32_t|int64_t|uint8_t|uint16_t|uint32_t|uint64_t|int_least8_t|int_least16_t|int_least32_t|int_least64_t|uint_least8_t|uint_least16_t|uint_least32_t|uint_least64_t|int_fast8_t|int_fast16_t|int_fast32_t|int_fast64_t|uint_fast8_t|uint_fast16_t|uint_fast32_t|uint_fast64_t|intptr_t|uintptr_t|intmax_t|intmax_t|uintmax_t|uintmax_t|memory_order|atomic_bool|atomic_char|atomic_schar|atomic_uchar|atomic_short|atomic_ushort|atomic_int|atomic_uint|atomic_long|atomic_ulong|atomic_llong|atomic_ullong|atomic_char16_t|atomic_char32_t|atomic_wchar_t|atomic_int_least8_t|atomic_uint_least8_t|atomic_int_least16_t|atomic_uint_least16_t|atomic_int_least32_t|atomic_uint_least32_t|atomic_int_least64_t|atomic_uint_least64_t|atomic_int_fast8_t|atomic_uint_fast8_t|atomic_int_fast16_t|atomic_uint_fast16_t|atomic_int_fast32_t|atomic_uint_fast32_t|atomic_int_fast64_t|atomic_uint_fast64_t|atomic_intptr_t|atomic_uintptr_t|atomic_size_t|atomic_ptrdiff_t|atomic_intmax_t|atomic_uintmax_t)\\b)[a-zA-Z_]\\w*\\b(?!\\())", + "captures": { + "1": { + "name": "variable.other.object.access.c" + }, + "2": { + "name": "punctuation.separator.dot-access.c" + }, + "3": { + "name": "punctuation.separator.pointer-access.c" + }, + "4": { + "patterns": [ + { + "include": "#member_access" + }, + { + "include": "#method_access" + }, + { + "match": "((?:[a-zA-Z_]\\w*|(?<=\\]|\\)))\\s*)(?:((?:\\.\\*|\\.))|((?:->\\*|->)))", + "captures": { + "1": { + "name": "variable.other.object.access.c" + }, + "2": { + "name": "punctuation.separator.dot-access.c" + }, + "3": { + "name": "punctuation.separator.pointer-access.c" + } + } + } + ] + }, + "5": { + "name": "variable.other.member.c" + } + } + }, + "method_access": { + "contentName": "meta.function-call.member.c", + "begin": "((?:[a-zA-Z_]\\w*|(?<=\\]|\\)))\\s*)(?:((?:\\.\\*|\\.))|((?:->\\*|->)))((?:[a-zA-Z_]\\w*\\s*(?:(?:(?:\\.\\*|\\.))|(?:(?:->\\*|->)))\\s*)*)\\s*([a-zA-Z_]\\w*)(\\()", + "beginCaptures": { + "1": { + "name": "variable.other.object.access.c" + }, + "2": { + "name": "punctuation.separator.dot-access.c" + }, + "3": { + "name": "punctuation.separator.pointer-access.c" + }, + "4": { + "patterns": [ + { + "include": "#member_access" + }, + { + "include": "#method_access" + }, + { + "match": "((?:[a-zA-Z_]\\w*|(?<=\\]|\\)))\\s*)(?:((?:\\.\\*|\\.))|((?:->\\*|->)))", + "captures": { + "1": { + "name": "variable.other.object.access.c" + }, + "2": { + "name": "punctuation.separator.dot-access.c" + }, + "3": { + "name": "punctuation.separator.pointer-access.c" + } + } + } + ] + }, + "5": { + "name": "entity.name.function.member.c" + }, + "6": { + "name": "punctuation.section.arguments.begin.bracket.round.function.member.c" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.arguments.end.bracket.round.function.member.c" + } + }, + "patterns": [ + { + "include": "#function-call-innards" + } + ] + }, + "predefined_macros": { + "patterns": [ + { + "match": "\\b__cplusplus\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__cplusplus.c" + }, + { + "match": "\\b__DATE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__DATE__.c" + }, + { + "match": "\\b__FILE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__FILE__.c" + }, + { + "match": "\\b__LINE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__LINE__.c" + }, + { + "match": "\\b__STDC__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__STDC__.c" + }, + { + "match": "\\b__STDC_HOSTED__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__STDC_HOSTED__.c" + }, + { + "match": "\\b__STDC_NO_COMPLEX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__STDC_NO_COMPLEX__.c" + }, + { + "match": "\\b__STDC_VERSION__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__STDC_VERSION__.c" + }, + { + "match": "\\b__STDCPP_THREADS__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__STDCPP_THREADS__.c" + }, + { + "match": "\\b__TIME__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__TIME__.c" + }, + { + "match": "\\bNDEBUG\\b", + "name": "entity.name.other.preprocessor.macro.predefined.NDEBUG.c" + }, + { + "match": "\\b__OBJC__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__OBJC__.c" + }, + { + "match": "\\b__ASSEMBLER__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__ASSEMBLER__.c" + }, + { + "match": "\\b__ATOM__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__ATOM__.c" + }, + { + "match": "\\b__AVX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__AVX__.c" + }, + { + "match": "\\b__AVX2__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__AVX2__.c" + }, + { + "match": "\\b_CHAR_UNSIGNED\\b", + "name": "entity.name.other.preprocessor.macro.predefined._CHAR_UNSIGNED.c" + }, + { + "match": "\\b__CLR_VER\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__CLR_VER.c" + }, + { + "match": "\\b_CONTROL_FLOW_GUARD\\b", + "name": "entity.name.other.preprocessor.macro.predefined._CONTROL_FLOW_GUARD.c" + }, + { + "match": "\\b__COUNTER__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__COUNTER__.c" + }, + { + "match": "\\b__cplusplus_cli\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__cplusplus_cli.c" + }, + { + "match": "\\b__cplusplus_winrt\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__cplusplus_winrt.c" + }, + { + "match": "\\b_CPPRTTI\\b", + "name": "entity.name.other.preprocessor.macro.predefined._CPPRTTI.c" + }, + { + "match": "\\b_CPPUNWIND\\b", + "name": "entity.name.other.preprocessor.macro.predefined._CPPUNWIND.c" + }, + { + "match": "\\b_DEBUG\\b", + "name": "entity.name.other.preprocessor.macro.predefined._DEBUG.c" + }, + { + "match": "\\b_DLL\\b", + "name": "entity.name.other.preprocessor.macro.predefined._DLL.c" + }, + { + "match": "\\b__FUNCDNAME__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__FUNCDNAME__.c" + }, + { + "match": "\\b__FUNCSIG__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__FUNCSIG__.c" + }, + { + "match": "\\b__FUNCTION__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__FUNCTION__.c" + }, + { + "match": "\\b_INTEGRAL_MAX_BITS\\b", + "name": "entity.name.other.preprocessor.macro.predefined._INTEGRAL_MAX_BITS.c" + }, + { + "match": "\\b__INTELLISENSE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INTELLISENSE__.c" + }, + { + "match": "\\b_ISO_VOLATILE\\b", + "name": "entity.name.other.preprocessor.macro.predefined._ISO_VOLATILE.c" + }, + { + "match": "\\b_KERNEL_MODE\\b", + "name": "entity.name.other.preprocessor.macro.predefined._KERNEL_MODE.c" + }, + { + "match": "\\b_M_AMD64\\b", + "name": "entity.name.other.preprocessor.macro.predefined._M_AMD64.c" + }, + { + "match": "\\b_M_ARM\\b", + "name": "entity.name.other.preprocessor.macro.predefined._M_ARM.c" + }, + { + "match": "\\b_M_ARM_ARMV7VE\\b", + "name": "entity.name.other.preprocessor.macro.predefined._M_ARM_ARMV7VE.c" + }, + { + "match": "\\b_M_ARM_FP\\b", + "name": "entity.name.other.preprocessor.macro.predefined._M_ARM_FP.c" + }, + { + "match": "\\b_M_ARM64\\b", + "name": "entity.name.other.preprocessor.macro.predefined._M_ARM64.c" + }, + { + "match": "\\b_M_CEE\\b", + "name": "entity.name.other.preprocessor.macro.predefined._M_CEE.c" + }, + { + "match": "\\b_M_CEE_PURE\\b", + "name": "entity.name.other.preprocessor.macro.predefined._M_CEE_PURE.c" + }, + { + "match": "\\b_M_CEE_SAFE\\b", + "name": "entity.name.other.preprocessor.macro.predefined._M_CEE_SAFE.c" + }, + { + "match": "\\b_M_FP_EXCEPT\\b", + "name": "entity.name.other.preprocessor.macro.predefined._M_FP_EXCEPT.c" + }, + { + "match": "\\b_M_FP_FAST\\b", + "name": "entity.name.other.preprocessor.macro.predefined._M_FP_FAST.c" + }, + { + "match": "\\b_M_FP_PRECISE\\b", + "name": "entity.name.other.preprocessor.macro.predefined._M_FP_PRECISE.c" + }, + { + "match": "\\b_M_FP_STRICT\\b", + "name": "entity.name.other.preprocessor.macro.predefined._M_FP_STRICT.c" + }, + { + "match": "\\b_M_IX86\\b", + "name": "entity.name.other.preprocessor.macro.predefined._M_IX86.c" + }, + { + "match": "\\b_M_IX86_FP\\b", + "name": "entity.name.other.preprocessor.macro.predefined._M_IX86_FP.c" + }, + { + "match": "\\b_M_X64\\b", + "name": "entity.name.other.preprocessor.macro.predefined._M_X64.c" + }, + { + "match": "\\b_MANAGED\\b", + "name": "entity.name.other.preprocessor.macro.predefined._MANAGED.c" + }, + { + "match": "\\b_MSC_BUILD\\b", + "name": "entity.name.other.preprocessor.macro.predefined._MSC_BUILD.c" + }, + { + "match": "\\b_MSC_EXTENSIONS\\b", + "name": "entity.name.other.preprocessor.macro.predefined._MSC_EXTENSIONS.c" + }, + { + "match": "\\b_MSC_FULL_VER\\b", + "name": "entity.name.other.preprocessor.macro.predefined._MSC_FULL_VER.c" + }, + { + "match": "\\b_MSC_VER\\b", + "name": "entity.name.other.preprocessor.macro.predefined._MSC_VER.c" + }, + { + "match": "\\b_MSVC_LANG\\b", + "name": "entity.name.other.preprocessor.macro.predefined._MSVC_LANG.c" + }, + { + "match": "\\b__MSVC_RUNTIME_CHECKS\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__MSVC_RUNTIME_CHECKS.c" + }, + { + "match": "\\b_MT\\b", + "name": "entity.name.other.preprocessor.macro.predefined._MT.c" + }, + { + "match": "\\b_NATIVE_WCHAR_T_DEFINED\\b", + "name": "entity.name.other.preprocessor.macro.predefined._NATIVE_WCHAR_T_DEFINED.c" + }, + { + "match": "\\b_OPENMP\\b", + "name": "entity.name.other.preprocessor.macro.predefined._OPENMP.c" + }, + { + "match": "\\b_PREFAST\\b", + "name": "entity.name.other.preprocessor.macro.predefined._PREFAST.c" + }, + { + "match": "\\b__TIMESTAMP__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__TIMESTAMP__.c" + }, + { + "match": "\\b_VC_NO_DEFAULTLIB\\b", + "name": "entity.name.other.preprocessor.macro.predefined._VC_NO_DEFAULTLIB.c" + }, + { + "match": "\\b_WCHAR_T_DEFINED\\b", + "name": "entity.name.other.preprocessor.macro.predefined._WCHAR_T_DEFINED.c" + }, + { + "match": "\\b_WIN32\\b", + "name": "entity.name.other.preprocessor.macro.predefined._WIN32.c" + }, + { + "match": "\\b_WIN64\\b", + "name": "entity.name.other.preprocessor.macro.predefined._WIN64.c" + }, + { + "match": "\\b_WINRT_DLL\\b", + "name": "entity.name.other.preprocessor.macro.predefined._WINRT_DLL.c" + }, + { + "match": "\\b_ATL_VER\\b", + "name": "entity.name.other.preprocessor.macro.predefined._ATL_VER.c" + }, + { + "match": "\\b_MFC_VER\\b", + "name": "entity.name.other.preprocessor.macro.predefined._MFC_VER.c" + }, + { + "match": "\\b__GFORTRAN__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GFORTRAN__.c" + }, + { + "match": "\\b__GNUC__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GNUC__.c" + }, + { + "match": "\\b__GNUC_MINOR__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GNUC_MINOR__.c" + }, + { + "match": "\\b__GNUC_PATCHLEVEL__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GNUC_PATCHLEVEL__.c" + }, + { + "match": "\\b__GNUG__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GNUG__.c" + }, + { + "match": "\\b__STRICT_ANSI__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__STRICT_ANSI__.c" + }, + { + "match": "\\b__BASE_FILE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__BASE_FILE__.c" + }, + { + "match": "\\b__INCLUDE_LEVEL__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INCLUDE_LEVEL__.c" + }, + { + "match": "\\b__ELF__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__ELF__.c" + }, + { + "match": "\\b__VERSION__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__VERSION__.c" + }, + { + "match": "\\b__OPTIMIZE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__OPTIMIZE__.c" + }, + { + "match": "\\b__OPTIMIZE_SIZE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__OPTIMIZE_SIZE__.c" + }, + { + "match": "\\b__NO_INLINE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__NO_INLINE__.c" + }, + { + "match": "\\b__GNUC_STDC_INLINE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GNUC_STDC_INLINE__.c" + }, + { + "match": "\\b__CHAR_UNSIGNED__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__CHAR_UNSIGNED__.c" + }, + { + "match": "\\b__WCHAR_UNSIGNED__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__WCHAR_UNSIGNED__.c" + }, + { + "match": "\\b__REGISTER_PREFIX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__REGISTER_PREFIX__.c" + }, + { + "match": "\\b__REGISTER_PREFIX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__REGISTER_PREFIX__.c" + }, + { + "match": "\\b__SIZE_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIZE_TYPE__.c" + }, + { + "match": "\\b__PTRDIFF_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__PTRDIFF_TYPE__.c" + }, + { + "match": "\\b__WCHAR_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__WCHAR_TYPE__.c" + }, + { + "match": "\\b__WINT_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__WINT_TYPE__.c" + }, + { + "match": "\\b__INTMAX_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INTMAX_TYPE__.c" + }, + { + "match": "\\b__UINTMAX_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINTMAX_TYPE__.c" + }, + { + "match": "\\b__SIG_ATOMIC_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIG_ATOMIC_TYPE__.c" + }, + { + "match": "\\b__INT8_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT8_TYPE__.c" + }, + { + "match": "\\b__INT16_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT16_TYPE__.c" + }, + { + "match": "\\b__INT32_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT32_TYPE__.c" + }, + { + "match": "\\b__INT64_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT64_TYPE__.c" + }, + { + "match": "\\b__UINT8_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT8_TYPE__.c" + }, + { + "match": "\\b__UINT16_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT16_TYPE__.c" + }, + { + "match": "\\b__UINT32_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT32_TYPE__.c" + }, + { + "match": "\\b__UINT64_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT64_TYPE__.c" + }, + { + "match": "\\b__INT_LEAST8_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_LEAST8_TYPE__.c" + }, + { + "match": "\\b__INT_LEAST16_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_LEAST16_TYPE__.c" + }, + { + "match": "\\b__INT_LEAST32_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_LEAST32_TYPE__.c" + }, + { + "match": "\\b__INT_LEAST64_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_LEAST64_TYPE__.c" + }, + { + "match": "\\b__UINT_LEAST8_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT_LEAST8_TYPE__.c" + }, + { + "match": "\\b__UINT_LEAST16_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT_LEAST16_TYPE__.c" + }, + { + "match": "\\b__UINT_LEAST32_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT_LEAST32_TYPE__.c" + }, + { + "match": "\\b__UINT_LEAST64_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT_LEAST64_TYPE__.c" + }, + { + "match": "\\b__INT_FAST8_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_FAST8_TYPE__.c" + }, + { + "match": "\\b__INT_FAST16_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_FAST16_TYPE__.c" + }, + { + "match": "\\b__INT_FAST32_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_FAST32_TYPE__.c" + }, + { + "match": "\\b__INT_FAST64_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_FAST64_TYPE__.c" + }, + { + "match": "\\b__UINT_FAST8_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT_FAST8_TYPE__.c" + }, + { + "match": "\\b__UINT_FAST16_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT_FAST16_TYPE__.c" + }, + { + "match": "\\b__UINT_FAST32_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT_FAST32_TYPE__.c" + }, + { + "match": "\\b__UINT_FAST64_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT_FAST64_TYPE__.c" + }, + { + "match": "\\b__INTPTR_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INTPTR_TYPE__.c" + }, + { + "match": "\\b__UINTPTR_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINTPTR_TYPE__.c" + }, + { + "match": "\\b__CHAR_BIT__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__CHAR_BIT__.c" + }, + { + "match": "\\b__SCHAR_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SCHAR_MAX__.c" + }, + { + "match": "\\b__WCHAR_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__WCHAR_MAX__.c" + }, + { + "match": "\\b__SHRT_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SHRT_MAX__.c" + }, + { + "match": "\\b__INT_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_MAX__.c" + }, + { + "match": "\\b__LONG_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__LONG_MAX__.c" + }, + { + "match": "\\b__LONG_LONG_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__LONG_LONG_MAX__.c" + }, + { + "match": "\\b__WINT_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__WINT_MAX__.c" + }, + { + "match": "\\b__SIZE_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIZE_MAX__.c" + }, + { + "match": "\\b__PTRDIFF_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__PTRDIFF_MAX__.c" + }, + { + "match": "\\b__INTMAX_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INTMAX_MAX__.c" + }, + { + "match": "\\b__UINTMAX_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINTMAX_MAX__.c" + }, + { + "match": "\\b__SIG_ATOMIC_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIG_ATOMIC_MAX__.c" + }, + { + "match": "\\b__INT8_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT8_MAX__.c" + }, + { + "match": "\\b__INT16_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT16_MAX__.c" + }, + { + "match": "\\b__INT32_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT32_MAX__.c" + }, + { + "match": "\\b__INT64_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT64_MAX__.c" + }, + { + "match": "\\b__UINT8_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT8_MAX__.c" + }, + { + "match": "\\b__UINT16_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT16_MAX__.c" + }, + { + "match": "\\b__UINT32_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT32_MAX__.c" + }, + { + "match": "\\b__UINT64_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT64_MAX__.c" + }, + { + "match": "\\b__INT_LEAST8_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_LEAST8_MAX__.c" + }, + { + "match": "\\b__INT_LEAST16_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_LEAST16_MAX__.c" + }, + { + "match": "\\b__INT_LEAST32_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_LEAST32_MAX__.c" + }, + { + "match": "\\b__INT_LEAST64_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_LEAST64_MAX__.c" + }, + { + "match": "\\b__UINT_LEAST8_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT_LEAST8_MAX__.c" + }, + { + "match": "\\b__UINT_LEAST16_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT_LEAST16_MAX__.c" + }, + { + "match": "\\b__UINT_LEAST32_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT_LEAST32_MAX__.c" + }, + { + "match": "\\b__UINT_LEAST64_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT_LEAST64_MAX__.c" + }, + { + "match": "\\b__INT_FAST8_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_FAST8_MAX__.c" + }, + { + "match": "\\b__INT_FAST16_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_FAST16_MAX__.c" + }, + { + "match": "\\b__INT_FAST32_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_FAST32_MAX__.c" + }, + { + "match": "\\b__INT_FAST64_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_FAST64_MAX__.c" + }, + { + "match": "\\b__UINT_FAST8_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT_FAST8_MAX__.c" + }, + { + "match": "\\b__UINT_FAST16_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT_FAST16_MAX__.c" + }, + { + "match": "\\b__UINT_FAST32_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT_FAST32_MAX__.c" + }, + { + "match": "\\b__UINT_FAST64_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT_FAST64_MAX__.c" + }, + { + "match": "\\b__INTPTR_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INTPTR_MAX__.c" + }, + { + "match": "\\b__UINTPTR_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINTPTR_MAX__.c" + }, + { + "match": "\\b__WCHAR_MIN__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__WCHAR_MIN__.c" + }, + { + "match": "\\b__WINT_MIN__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__WINT_MIN__.c" + }, + { + "match": "\\b__SIG_ATOMIC_MIN__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIG_ATOMIC_MIN__.c" + }, + { + "match": "\\b__SCHAR_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SCHAR_WIDTH__.c" + }, + { + "match": "\\b__SHRT_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SHRT_WIDTH__.c" + }, + { + "match": "\\b__INT_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_WIDTH__.c" + }, + { + "match": "\\b__LONG_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__LONG_WIDTH__.c" + }, + { + "match": "\\b__LONG_LONG_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__LONG_LONG_WIDTH__.c" + }, + { + "match": "\\b__PTRDIFF_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__PTRDIFF_WIDTH__.c" + }, + { + "match": "\\b__SIG_ATOMIC_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIG_ATOMIC_WIDTH__.c" + }, + { + "match": "\\b__SIZE_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIZE_WIDTH__.c" + }, + { + "match": "\\b__WCHAR_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__WCHAR_WIDTH__.c" + }, + { + "match": "\\b__WINT_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__WINT_WIDTH__.c" + }, + { + "match": "\\b__INT_LEAST8_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_LEAST8_WIDTH__.c" + }, + { + "match": "\\b__INT_LEAST16_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_LEAST16_WIDTH__.c" + }, + { + "match": "\\b__INT_LEAST32_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_LEAST32_WIDTH__.c" + }, + { + "match": "\\b__INT_LEAST64_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_LEAST64_WIDTH__.c" + }, + { + "match": "\\b__INT_FAST8_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_FAST8_WIDTH__.c" + }, + { + "match": "\\b__INT_FAST16_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_FAST16_WIDTH__.c" + }, + { + "match": "\\b__INT_FAST32_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_FAST32_WIDTH__.c" + }, + { + "match": "\\b__INT_FAST64_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_FAST64_WIDTH__.c" + }, + { + "match": "\\b__INTPTR_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INTPTR_WIDTH__.c" + }, + { + "match": "\\b__INTMAX_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INTMAX_WIDTH__.c" + }, + { + "match": "\\b__SIZEOF_INT__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIZEOF_INT__.c" + }, + { + "match": "\\b__SIZEOF_LONG__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIZEOF_LONG__.c" + }, + { + "match": "\\b__SIZEOF_LONG_LONG__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIZEOF_LONG_LONG__.c" + }, + { + "match": "\\b__SIZEOF_SHORT__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIZEOF_SHORT__.c" + }, + { + "match": "\\b__SIZEOF_POINTER__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIZEOF_POINTER__.c" + }, + { + "match": "\\b__SIZEOF_FLOAT__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIZEOF_FLOAT__.c" + }, + { + "match": "\\b__SIZEOF_DOUBLE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIZEOF_DOUBLE__.c" + }, + { + "match": "\\b__SIZEOF_LONG_DOUBLE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIZEOF_LONG_DOUBLE__.c" + }, + { + "match": "\\b__SIZEOF_SIZE_T__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIZEOF_SIZE_T__.c" + }, + { + "match": "\\b__SIZEOF_WCHAR_T__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIZEOF_WCHAR_T__.c" + }, + { + "match": "\\b__SIZEOF_WINT_T__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIZEOF_WINT_T__.c" + }, + { + "match": "\\b__SIZEOF_PTRDIFF_T__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIZEOF_PTRDIFF_T__.c" + }, + { + "match": "\\b__BYTE_ORDER__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__BYTE_ORDER__.c" + }, + { + "match": "\\b__ORDER_LITTLE_ENDIAN__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__ORDER_LITTLE_ENDIAN__.c" + }, + { + "match": "\\b__ORDER_BIG_ENDIAN__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__ORDER_BIG_ENDIAN__.c" + }, + { + "match": "\\b__ORDER_PDP_ENDIAN__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__ORDER_PDP_ENDIAN__.c" + }, + { + "match": "\\b__FLOAT_WORD_ORDER__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__FLOAT_WORD_ORDER__.c" + }, + { + "match": "\\b__DEPRECATED\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__DEPRECATED.c" + }, + { + "match": "\\b__EXCEPTIONS\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__EXCEPTIONS.c" + }, + { + "match": "\\b__GXX_RTTI\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GXX_RTTI.c" + }, + { + "match": "\\b__USING_SJLJ_EXCEPTIONS__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__USING_SJLJ_EXCEPTIONS__.c" + }, + { + "match": "\\b__GXX_EXPERIMENTAL_CXX0X__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GXX_EXPERIMENTAL_CXX0X__.c" + }, + { + "match": "\\b__GXX_WEAK__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GXX_WEAK__.c" + }, + { + "match": "\\b__NEXT_RUNTIME__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__NEXT_RUNTIME__.c" + }, + { + "match": "\\b__LP64__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__LP64__.c" + }, + { + "match": "\\b_LP64\\b", + "name": "entity.name.other.preprocessor.macro.predefined._LP64.c" + }, + { + "match": "\\b__SSP__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SSP__.c" + }, + { + "match": "\\b__SSP_ALL__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SSP_ALL__.c" + }, + { + "match": "\\b__SSP_STRONG__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SSP_STRONG__.c" + }, + { + "match": "\\b__SSP_EXPLICIT__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SSP_EXPLICIT__.c" + }, + { + "match": "\\b__SANITIZE_ADDRESS__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SANITIZE_ADDRESS__.c" + }, + { + "match": "\\b__SANITIZE_THREAD__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SANITIZE_THREAD__.c" + }, + { + "match": "\\b__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1.c" + }, + { + "match": "\\b__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2.c" + }, + { + "match": "\\b__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4.c" + }, + { + "match": "\\b__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8.c" + }, + { + "match": "\\b__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16.c" + }, + { + "match": "\\b__HAVE_SPECULATION_SAFE_VALUE\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__HAVE_SPECULATION_SAFE_VALUE.c" + }, + { + "match": "\\b__GCC_HAVE_DWARF2_CFI_ASM\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GCC_HAVE_DWARF2_CFI_ASM.c" + }, + { + "match": "\\b__FP_FAST_FMA\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__FP_FAST_FMA.c" + }, + { + "match": "\\b__FP_FAST_FMAF\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__FP_FAST_FMAF.c" + }, + { + "match": "\\b__FP_FAST_FMAL\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__FP_FAST_FMAL.c" + }, + { + "match": "\\b__FP_FAST_FMAF16\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__FP_FAST_FMAF16.c" + }, + { + "match": "\\b__FP_FAST_FMAF32\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__FP_FAST_FMAF32.c" + }, + { + "match": "\\b__FP_FAST_FMAF64\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__FP_FAST_FMAF64.c" + }, + { + "match": "\\b__FP_FAST_FMAF128\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__FP_FAST_FMAF128.c" + }, + { + "match": "\\b__FP_FAST_FMAF32X\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__FP_FAST_FMAF32X.c" + }, + { + "match": "\\b__FP_FAST_FMAF64X\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__FP_FAST_FMAF64X.c" + }, + { + "match": "\\b__FP_FAST_FMAF128X\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__FP_FAST_FMAF128X.c" + }, + { + "match": "\\b__GCC_IEC_559\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GCC_IEC_559.c" + }, + { + "match": "\\b__GCC_IEC_559_COMPLEX\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GCC_IEC_559_COMPLEX.c" + }, + { + "match": "\\b__NO_MATH_ERRNO__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__NO_MATH_ERRNO__.c" + }, + { + "match": "\\b__has_builtin\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__has_builtin.c" + }, + { + "match": "\\b__has_feature\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__has_feature.c" + }, + { + "match": "\\b__has_extension\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__has_extension.c" + }, + { + "match": "\\b__has_cpp_attribute\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__has_cpp_attribute.c" + }, + { + "match": "\\b__has_c_attribute\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__has_c_attribute.c" + }, + { + "match": "\\b__has_attribute\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__has_attribute.c" + }, + { + "match": "\\b__has_declspec_attribute\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__has_declspec_attribute.c" + }, + { + "match": "\\b__is_identifier\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__is_identifier.c" + }, + { + "match": "\\b__has_include\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__has_include.c" + }, + { + "match": "\\b__has_include_next\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__has_include_next.c" + }, + { + "match": "\\b__has_warning\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__has_warning.c" + }, + { + "match": "\\b__BASE_FILE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__BASE_FILE__.c" + }, + { + "match": "\\b__FILE_NAME__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__FILE_NAME__.c" + }, + { + "match": "\\b__clang__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__clang__.c" + }, + { + "match": "\\b__clang_major__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__clang_major__.c" + }, + { + "match": "\\b__clang_minor__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__clang_minor__.c" + }, + { + "match": "\\b__clang_patchlevel__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__clang_patchlevel__.c" + }, + { + "match": "\\b__clang_version__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__clang_version__.c" + }, + { + "match": "\\b__fp16\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__fp16.c" + }, + { + "match": "\\b_Float16\\b", + "name": "entity.name.other.preprocessor.macro.predefined._Float16.c" + }, + { + "match": "(\\b__([A-Z_])__\\b)", + "captures": { + "1": { + "name": "entity.name.other.preprocessor.macro.predefined.probably.$2.c" + } + } + } + ] + }, + "numbers": { + "begin": "(?\\]\\)]))\\s*([a-zA-Z_]\\w*)\\s*(?=(?:\\[\\]\\s*)?(?:,|\\)))", "captures": { @@ -559,10 +2273,6 @@ }, "name": "comment.block.c" }, - { - "match": "\\*/.*\\n", - "name": "invalid.illegal.stray-comment-end.c" - }, { "captures": { "1": { @@ -570,13 +2280,13 @@ } }, "match": "^// =(\\s*.*?)\\s*=\\s*$\\n?", - "name": "comment.line.banner.cpp.c" + "name": "comment.line.banner.c" }, { "begin": "(^[ \\t]+)?(?=//)", "beginCaptures": { "1": { - "name": "punctuation.whitespace.comment.leading.cpp.c" + "name": "punctuation.whitespace.comment.leading.c" } }, "end": "(?!\\G)", @@ -585,11 +2295,11 @@ "begin": "//", "beginCaptures": { "0": { - "name": "punctuation.definition.comment.cpp.c" + "name": "punctuation.definition.comment.c" } }, "end": "(?=\\n)", - "name": "comment.line.double-slash.cpp.c", + "name": "comment.line.double-slash.c", "patterns": [ { "include": "#line_continuation_character" @@ -624,14 +2334,6 @@ } ] }, - "numbers": { - "patterns": [ - { - "match": "\\b((0(x|X)[0-9a-fA-F]([0-9a-fA-F']*[0-9a-fA-F])?)|(0(b|B)[01]([01']*[01])?)|(([0-9]([0-9']*[0-9])?\\.?[0-9]*([0-9']*[0-9])?)|(\\.[0-9]([0-9']*[0-9])?))((e|E)(\\+|-)?[0-9]([0-9']*[0-9])?)?)(L|l|UL|ul|u|U|F|f|ll|LL|ull|ULL)?\\b", - "name": "constant.numeric.c" - } - ] - }, "parens": { "name": "meta.parens.c", "begin": "\\(", @@ -672,7 +2374,7 @@ }, { "match": "(?-mix:(?\\[\\]=]))", - "patterns": [ - { - "include": "#switch_conditional_parentheses" - }, - { - "name": "meta.head.switch.cpp.c", - "begin": "\\G| ", - "end": "((?:\\{|(?=;)))", - "endCaptures": { - "1": { - "name": "punctuation.section.block.begin.bracket.curly.switch.cpp.c" - } - }, - "patterns": [ - { - "include": "#switch_conditional_parentheses" - }, - { - "include": "$base" - } - ] - }, - { - "name": "meta.body.switch.cpp.c", - "begin": "(?<=\\{)", - "end": "(\\})", - "endCaptures": { - "1": { - "name": "punctuation.section.block.end.bracket.curly.switch.cpp.c" - } - }, - "patterns": [ - { - "include": "#default_statement" - }, - { - "include": "#case_statement" - }, - { - "include": "$base" - } - ] - }, - { - "name": "meta.tail.switch.cpp.c", - "begin": "(?<=})[\\s\\n]*", - "end": "[\\s\\n]*(?=;)", - "patterns": [ - { - "include": "$base" - } - ] - } - ] - }, - "switch_conditional_parentheses": { - "name": "meta.conditional.switch.c", - "begin": "(\\()", - "beginCaptures": { - "1": { - "name": "punctuation.section.parens.begin.bracket.round.conditional.switch.cpp.c" - } - }, - "end": "(\\))", - "endCaptures": { - "1": { - "name": "punctuation.section.parens.end.bracket.round.conditional.switch.cpp.c" - } - }, - "patterns": [ - { - "include": "#conditional_context" - } - ] - }, - "conditional_context": { - "patterns": [ - { - "include": "$base" - } - ] - }, - "member_access": { - "match": "((?:[a-zA-Z_]\\w*|(?<=\\]|\\)))\\s*)(?:((?:\\.\\*|\\.))|((?:->\\*|->)))((?:[a-zA-Z_]\\w*\\s*(?-mix:(?:(?:\\.\\*|\\.))|(?:(?:->\\*|->)))\\s*)*)\\s*(\\b(?!(?:void|char|short|int|signed|unsigned|long|float|double|bool|_Bool|_Complex|_Imaginary|u_char|u_short|u_int|u_long|ushort|uint|u_quad_t|quad_t|qaddr_t|caddr_t|daddr_t|div_t|dev_t|fixpt_t|blkcnt_t|blksize_t|gid_t|in_addr_t|in_port_t|ino_t|key_t|mode_t|nlink_t|id_t|pid_t|off_t|segsz_t|swblk_t|uid_t|id_t|clock_t|size_t|ssize_t|time_t|useconds_t|suseconds_t|pthread_attr_t|pthread_cond_t|pthread_condattr_t|pthread_mutex_t|pthread_mutexattr_t|pthread_once_t|pthread_rwlock_t|pthread_rwlockattr_t|pthread_t|pthread_key_t|int8_t|int16_t|int32_t|int64_t|uint8_t|uint16_t|uint32_t|uint64_t|int_least8_t|int_least16_t|int_least32_t|int_least64_t|uint_least8_t|uint_least16_t|uint_least32_t|uint_least64_t|int_fast8_t|int_fast16_t|int_fast32_t|int_fast64_t|uint_fast8_t|uint_fast16_t|uint_fast32_t|uint_fast64_t|intptr_t|uintptr_t|intmax_t|intmax_t|uintmax_t|uintmax_t|memory_order|atomic_bool|atomic_char|atomic_schar|atomic_uchar|atomic_short|atomic_ushort|atomic_int|atomic_uint|atomic_long|atomic_ulong|atomic_llong|atomic_ullong|atomic_char16_t|atomic_char32_t|atomic_wchar_t|atomic_int_least8_t|atomic_uint_least8_t|atomic_int_least16_t|atomic_uint_least16_t|atomic_int_least32_t|atomic_uint_least32_t|atomic_int_least64_t|atomic_uint_least64_t|atomic_int_fast8_t|atomic_uint_fast8_t|atomic_int_fast16_t|atomic_uint_fast16_t|atomic_int_fast32_t|atomic_uint_fast32_t|atomic_int_fast64_t|atomic_uint_fast64_t|atomic_intptr_t|atomic_uintptr_t|atomic_size_t|atomic_ptrdiff_t|atomic_intmax_t|atomic_uintmax_t))[a-zA-Z_]\\w*\\b(?!\\())", - "captures": { - "1": { - "name": "variable.other.object.access.c" - }, - "2": { - "name": "punctuation.separator.dot-access.c" - }, - "3": { - "name": "punctuation.separator.pointer-access.c" - }, - "4": { - "patterns": [ - { - "include": "#member_access" - }, - { - "include": "#method_access" - }, - { - "match": "((?:[a-zA-Z_]\\w*|(?<=\\]|\\)))\\s*)(?:((?:\\.\\*|\\.))|((?:->\\*|->)))", - "captures": { - "1": { - "name": "variable.other.object.access.c" - }, - "2": { - "name": "punctuation.separator.dot-access.c" - }, - "3": { - "name": "punctuation.separator.pointer-access.c" - } - } - } - ] - }, - "5": { - "name": "variable.other.member.c" - } - } - }, - "method_access": { - "contentName": "meta.function-call.member", - "begin": "((?:[a-zA-Z_]\\w*|(?<=\\]|\\)))\\s*)(?:((?:\\.\\*|\\.))|((?:->\\*|->)))((?:[a-zA-Z_]\\w*\\s*(?-mix:(?:(?:\\.\\*|\\.))|(?:(?:->\\*|->)))\\s*)*)\\s*([a-zA-Z_]\\w*)(\\()", - "beginCaptures": { - "1": { - "name": "variable.other.object.access.c" - }, - "2": { - "name": "punctuation.separator.dot-access.c" - }, - "3": { - "name": "punctuation.separator.pointer-access.c" - }, - "4": { - "patterns": [ - { - "include": "#member_access" - }, - { - "include": "#method_access" - }, - { - "match": "((?:[a-zA-Z_]\\w*|(?<=\\]|\\)))\\s*)(?:((?:\\.\\*|\\.))|((?:->\\*|->)))", - "captures": { - "1": { - "name": "variable.other.object.access.c" - }, - "2": { - "name": "punctuation.separator.dot-access.c" - }, - "3": { - "name": "punctuation.separator.pointer-access.c" - } - } - } - ] - }, - "5": { - "name": "entity.name.function.member.c" - }, - "6": { - "name": "punctuation.section.arguments.begin.bracket.round.function.member.c" - } - }, - "end": "(\\))", - "endCaptures": { - "1": { - "name": "punctuation.section.arguments.end.bracket.round.function.member.c" - } - }, - "patterns": [ - { - "include": "#function-call-innards" - } - ] } } } \ No newline at end of file diff --git a/extensions/cpp/syntaxes/cpp.tmLanguage.json b/extensions/cpp/syntaxes/cpp.tmLanguage.json index e9f5667cb..f7495aee6 100644 --- a/extensions/cpp/syntaxes/cpp.tmLanguage.json +++ b/extensions/cpp/syntaxes/cpp.tmLanguage.json @@ -4,267 +4,118 @@ "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/jeff-hykin/cpp-textmate-grammar/commit/3fa2a8862b6a06ca381f8e46eb782e5dd014d426", + "version": "https://github.com/jeff-hykin/cpp-textmate-grammar/commit/992c5ba8789288707f2a13778452d644677d9699", "name": "C++", "scopeName": "source.cpp", "patterns": [ { - "include": "#parameter_struct" + "include": "#ever_present_context" }, { - "include": "#struct_declare" + "include": "#constructor_root" }, { - "include": "#special_block_context" + "include": "#destructor_root" }, { - "include": "#macro_argument" - }, - { - "include": "#string_context" - }, - { - "include": "#functional_specifiers_pre_parameters" - }, - { - "include": "#qualifiers_and_specifiers_post_parameters" - }, - { - "include": "#storage_specifiers" - }, - { - "include": "#access_control_keywords" - }, - { - "include": "#exception_keywords" - }, - { - "include": "#other_keywords" - }, - { - "include": "#memory_operators" - }, - { - "include": "#the_this_keyword" - }, - { - "include": "#language_constants" - }, - { - "include": "#template_isolated_definition" - }, - { - "include": "#template_definition" - }, - { - "include": "#scope_resolution" - }, - { - "include": "#misc_storage_modifiers_1" - }, - { - "include": "#destructor" - }, - { - "include": "#destructor_prototype" + "include": "#function_definition" }, { - "include": "#lambdas" + "include": "#operator_overload" }, { - "include": "#preprocessor_context" + "include": "#using_namespace" }, { - "include": "#comments_context" + "include": "#type_alias" }, { - "include": "#switch_statement" + "include": "#using_name" }, { - "include": "#control_flow_keywords" + "include": "#namespace_alias" }, { - "include": "#storage_types" + "include": "#namespace_block" }, { - "include": "#assembly" + "include": "#extern_block" }, { - "include": "#misc_storage_modifiers_2" + "include": "#typedef_class" }, { - "include": "#operator_overload" + "include": "#typedef_struct" }, { - "include": "#number_literal" + "include": "#typedef_union" }, { - "include": "#string_context_c" + "include": "#typedef_keyword" }, { - "include": "#meta_preprocessor_macro" + "include": "#standard_declares" }, { - "include": "#meta_preprocessor_diagnostic" + "include": "#class_block" }, { - "include": "#meta_preprocessor_include" + "include": "#struct_block" }, { - "include": "#pragma_mark" + "include": "#union_block" }, { - "include": "#meta_preprocessor_line" + "include": "#enum_block" }, { - "include": "#meta_preprocessor_undef" + "include": "#template_isolated_definition" }, { - "include": "#meta_preprocessor_pragma" + "include": "#template_definition" }, { - "include": "#operators" + "include": "#access_control_keywords" }, { "include": "#block" }, { - "include": "#parentheses" - }, - { - "include": "#function_definition" - }, - { - "include": "#line_continuation_character" - }, - { - "include": "#square_brackets" + "include": "#static_assert" }, { - "include": "#empty_square_brackets" + "include": "#assembly" }, { - "include": "#semicolon" + "include": "#function_pointer" }, { - "include": "#comma" + "include": "#evaluation_context" } ], "repository": { - "sizeof_operator": { - "contentName": "meta.arguments.operator.sizeof", - "begin": "((?(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/))", + "captures": { "1": { - "name": "keyword.operator.functionlike.cpp keyword.operator.typeid.cpp" + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" }, "2": { - "name": "punctuation.section.arguments.begin.bracket.round.operator.typeid.cpp" - } - }, - "end": "(\\))", - "endCaptures": { - "1": { - "name": "punctuation.section.arguments.end.bracket.round.operator.typeid.cpp" - } - }, - "patterns": [ - { - "include": "#evaluation_context" - } - ] - }, - "decltype_specifier": { - "contentName": "meta.arguments.decltype", - "begin": "((?[#;\\/=*C~]+)(?![#;\\/=*C~]))\\s*.+\\s*\\8\\s*(?:\\n|$)))|(^\\s*((\\/\\*)\\s*?((?>[#;\\/=*C~]+)(?![#;\\/=*C~]))\\s*.+\\s*\\8\\s*\\*\\/)))", + "captures": { "1": { - "name": "meta.head.switch.cpp" + "name": "meta.toc-list.banner.double-slash.cpp" }, "2": { - "name": "keyword.control.switch.cpp" + "name": "comment.line.double-slash.cpp" + }, + "3": { + "name": "punctuation.definition.comment.cpp" + }, + "4": { + "name": "meta.banner.character.cpp" + }, + "5": { + "name": "meta.toc-list.banner.block.cpp" + }, + "6": { + "name": "comment.line.block.cpp" + }, + "7": { + "name": "punctuation.definition.comment.cpp" + }, + "8": { + "name": "meta.banner.character.cpp" } - }, - "end": "(?:(?<=\\})|(?=[;>\\[\\]=]))", + } + }, + "comments": { "patterns": [ { - "include": "#switch_conditional_parentheses" - }, - { - "name": "meta.head.switch.cpp", - "begin": "\\G| ", - "end": "((?:\\{|(?=;)))", - "endCaptures": { - "1": { - "name": "punctuation.section.block.begin.bracket.curly.switch.cpp" - } - }, - "patterns": [ - { - "include": "#switch_conditional_parentheses" - }, - { - "include": "$base" - } - ] + "include": "#emacs_file_banner" }, { - "name": "meta.body.switch.cpp", - "begin": "(?<=\\{)", - "end": "(\\})", - "endCaptures": { - "1": { - "name": "punctuation.section.block.end.bracket.curly.switch.cpp" - } - }, - "patterns": [ - { - "include": "#default_statement" - }, - { - "include": "#case_statement" - }, - { - "include": "$base" - } - ] + "include": "#block_comment" }, { - "name": "meta.tail.switch.cpp", - "begin": "(?<=})[\\s\\n]*", - "end": "[\\s\\n]*(?=;)", - "patterns": [ - { - "include": "$base" - } - ] + "include": "#line_comment" } ] }, - "attributes": { - "name": "support.other.attribute.cpp", - "begin": "((?:\\[\\[|__attribute\\(\\(|__attribute__\\(\\(|__declspec\\())", - "beginCaptures": { - "1": { - "name": "punctuation.section.attribute.begin.cpp" - } - }, - "end": "((?:\\]\\]|\\)\\)|\\)))", - "endCaptures": { - "1": { - "name": "punctuation.section.attribute.end.cpp" - } - }, + "number_literal": { + "begin": "(?:,\\w])*>\\s*", + "primitive_types": { + "match": "((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?)", - "endCaptures": { - "1": { - "name": "punctuation.section.angle-brackets.end.template.call.cpp" - } - }, - "patterns": [ - { - "include": "#template_call_context" - } - ] - }, - "template_isolated_definition": { - "match": "(?\\s*$)", - "captures": { - "1": { - "name": "storage.type.template.cpp" }, "2": { - "name": "punctuation.section.angle-brackets.start.template.definition.cpp" + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" }, "3": { - "name": "meta.template.definition.cpp", + "name": "comment.block.cpp" + }, + "4": { "patterns": [ { - "include": "#template_definition_context" + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" } ] }, - "4": { - "name": "punctuation.section.angle-brackets.end.template.definition.cpp" + "5": { + "name": "storage.type.primitive.cpp storage.type.built-in.primitive.cpp" } } }, - "template_definition": { - "name": "meta.template.definition.cpp", - "begin": "(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()", "beginCaptures": { "1": { - "name": "storage.type.template.cpp" + "name": "keyword.operator.functionlike.cpp keyword.other.decltype.cpp storage.type.decltype.cpp" }, "2": { - "name": "punctuation.section.angle-brackets.start.template.definition.cpp" + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "name": "punctuation.section.arguments.begin.bracket.round.decltype.cpp" } }, - "end": "(>)", + "end": "(\\))", "endCaptures": { "1": { - "name": "punctuation.section.angle-brackets.end.template.definition.cpp" + "name": "punctuation.section.arguments.end.bracket.round.decltype.cpp" } }, "patterns": [ { - "begin": "((?<=\\w)\\s*<)", - "beginCaptures": { - "1": { - "name": "punctuation.section.angle-brackets.begin.template.call.cpp" - } - }, - "end": "(>)", - "endCaptures": { - "1": { - "name": "punctuation.section.angle-brackets.begin.template.call.cpp" + "include": "#evaluation_context" + } + ] + }, + "decltype": { + "contentName": "meta.arguments.decltype.cpp", + "begin": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()", + "beginCaptures": { + "1": { + "name": "keyword.operator.functionlike.cpp keyword.other.decltype.cpp storage.type.decltype.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" } - }, + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { "patterns": [ { - "include": "#template_call_context" + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" } ] }, + "6": { + "name": "punctuation.section.arguments.begin.bracket.round.decltype.cpp" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.arguments.end.bracket.round.decltype.cpp" + } + }, + "patterns": [ { - "include": "#template_definition_context" + "include": "#evaluation_context" } ] }, - "template_argument_defaulted": { - "match": "(?<=<|,)\\s*((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U000[0-9a-fA-F]))(?:(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U000[0-9a-fA-F])))*\\s+)*)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U000[0-9a-fA-F]))(?:(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U000[0-9a-fA-F])))*)\\s*([=])", + "pthread_types": { + "match": "((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?|$))", + "posix_reserved_types": { + "match": "((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:,\\w])*>\\s*)))?::)*\\s*)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U000[0-9a-fA-F]))(?:(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U000[0-9a-fA-F])))*)\\s*(?:(<(?:[\\s<>:,\\w])*>\\s*))?(::)", + "using_name": { + "match": "(using)\\s+(?!namespace\\b)", + "captures": { + "1": { + "name": "keyword.other.using.directive.cpp" + } + } + }, + "functional_specifiers_pre_parameters": { + "match": "(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(((?:private|protected|public))\\s*(:))", "captures": { "1": { - "name": "storage.type.struct.parameter.cpp" + "patterns": [ + { + "include": "#inline_comment" + } + ] }, "2": { - "name": "entity.name.type.struct.parameter.cpp" + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" }, "3": { + "name": "comment.block.cpp" + }, + "4": { "patterns": [ { - "match": "\\*", - "name": "keyword.operator.dereference.cpp" + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" }, { - "match": "&", - "name": "keyword.operator.reference.cpp" + "match": "\\*", + "name": "comment.block.cpp" } ] }, - "4": { - "name": "variable.other.object.declare.cpp" - } - } - }, - "function_definition": { - "name": "meta.function.definition.parameters.cpp", - "begin": "(?:,\\w])*>\\s*)))?::)*\\s*)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U000[0-9a-fA-F]))(?:(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U000[0-9a-fA-F])))*)\\s*(?:(<(?:[\\s<>:,\\w])*>\\s*))?(\\()", - "beginCaptures": { + "exception_keywords": { + "match": "((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?>=|\\|=", - "name": "keyword.operator.assignment.compound.bitwise.cpp" - }, - { - "match": "<<|>>", - "name": "keyword.operator.bitwise.shift.cpp" - }, - { - "match": "!=|<=|>=|==|<|>", - "name": "keyword.operator.comparison.cpp" - }, - { - "match": "&&|!|\\|\\|", - "name": "keyword.operator.logical.cpp" - }, - { - "match": "&|\\||\\^|~", - "name": "keyword.operator.cpp" - }, - { - "match": "=", - "name": "keyword.operator.assignment.cpp" - }, - { - "match": "%|\\*|/|-|\\+", - "name": "keyword.operator.cpp" - }, - { - "begin": "\\?", - "beginCaptures": { - "0": { - "name": "keyword.operator.ternary.cpp" - } - }, - "end": ":", - "applyEndPatternLast": true, - "endCaptures": { - "0": { - "name": "keyword.operator.ternary.cpp" - } - }, + "4": { "patterns": [ { - "include": "#method_access" - }, - { - "include": "#member_access" - }, - { - "include": "#function_call_c" + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" }, { - "include": "$base" + "match": "\\*", + "name": "comment.block.cpp" } ] - } - ] - }, - "probably_a_parameter": { - "match": "(?:((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U000[0-9a-fA-F]))(?:(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U000[0-9a-fA-F])))*\\s*(?==))|((?<=\\w |\\*\\/|[&*>\\]\\)]|\\.\\.\\.)\\s*(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U000[0-9a-fA-F]))(?:(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U000[0-9a-fA-F])))*\\s*(?=(?:\\[\\]\\s*)?(?:,|\\)))))", - "captures": { - "1": { - "name": "variable.parameter.defaulted.cpp" }, - "2": { - "name": "variable.parameter.cpp" + "5": { + "name": "keyword.other.$5.cpp" } } }, - "operator_overload": { - "name": "meta.function.definition.parameters.operator-overload.cpp", - "begin": "(operator)((?:\\s*(?:\\+\\+|\\-\\-|\\(\\)|\\[\\]|\\->|\\+\\+|\\-\\-|\\+|\\-|!|~|\\*|&|\\->\\*|\\*|\\/|%|\\+|\\-|<<|>>|<=>|<|<=|>|>=|==|!=|&|\\^|\\||&&|\\|\\||=|\\+=|\\-=|\\*=|\\/=|%=|<<=|>>=|&=|\\^=|\\|=|,)|\\s+(?:(?:new|new\\[\\]|delete|delete\\[\\])|(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U000[0-9a-fA-F]))(?:(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U000[0-9a-fA-F])))*\\s*(?:(?-mix:(?:<(?:[\\s<>:,\\w])*>\\s*)))?::)*(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U000[0-9a-fA-F]))(?:(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U000[0-9a-fA-F])))*\\s*(?:&)?)))\\s*(\\()", - "beginCaptures": { + "the_this_keyword": { + "match": "((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\*|->)))((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U000[0-9a-fA-F]))(?:(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U000[0-9a-fA-F])))*\\s*(?-mix:(?:(?:\\.\\*|\\.))|(?:(?:->\\*|->)))\\s*)*)\\s*(\\b(?!auto[^(?-mix:\\w)]|void[^(?-mix:\\w)]|char[^(?-mix:\\w)]|short[^(?-mix:\\w)]|int[^(?-mix:\\w)]|signed[^(?-mix:\\w)]|unsigned[^(?-mix:\\w)]|long[^(?-mix:\\w)]|float[^(?-mix:\\w)]|double[^(?-mix:\\w)]|bool[^(?-mix:\\w)]|wchar_t[^(?-mix:\\w)]|u_char[^(?-mix:\\w)]|u_short[^(?-mix:\\w)]|u_int[^(?-mix:\\w)]|u_long[^(?-mix:\\w)]|ushort[^(?-mix:\\w)]|uint[^(?-mix:\\w)]|u_quad_t[^(?-mix:\\w)]|quad_t[^(?-mix:\\w)]|qaddr_t[^(?-mix:\\w)]|caddr_t[^(?-mix:\\w)]|daddr_t[^(?-mix:\\w)]|div_t[^(?-mix:\\w)]|dev_t[^(?-mix:\\w)]|fixpt_t[^(?-mix:\\w)]|blkcnt_t[^(?-mix:\\w)]|blksize_t[^(?-mix:\\w)]|gid_t[^(?-mix:\\w)]|in_addr_t[^(?-mix:\\w)]|in_port_t[^(?-mix:\\w)]|ino_t[^(?-mix:\\w)]|key_t[^(?-mix:\\w)]|mode_t[^(?-mix:\\w)]|nlink_t[^(?-mix:\\w)]|id_t[^(?-mix:\\w)]|pid_t[^(?-mix:\\w)]|off_t[^(?-mix:\\w)]|segsz_t[^(?-mix:\\w)]|swblk_t[^(?-mix:\\w)]|uid_t[^(?-mix:\\w)]|id_t[^(?-mix:\\w)]|clock_t[^(?-mix:\\w)]|size_t[^(?-mix:\\w)]|ssize_t[^(?-mix:\\w)]|time_t[^(?-mix:\\w)]|useconds_t[^(?-mix:\\w)]|suseconds_t[^(?-mix:\\w)]|int8_t[^(?-mix:\\w)]|int16_t[^(?-mix:\\w)]|int32_t[^(?-mix:\\w)]|int64_t[^(?-mix:\\w)]|uint8_t[^(?-mix:\\w)]|uint16_t[^(?-mix:\\w)]|uint32_t[^(?-mix:\\w)]|uint64_t[^(?-mix:\\w)]|int_least8_t[^(?-mix:\\w)]|int_least16_t[^(?-mix:\\w)]|int_least32_t[^(?-mix:\\w)]|int_least64_t[^(?-mix:\\w)]|uint_least8_t[^(?-mix:\\w)]|uint_least16_t[^(?-mix:\\w)]|uint_least32_t[^(?-mix:\\w)]|uint_least64_t[^(?-mix:\\w)]|int_fast8_t[^(?-mix:\\w)]|int_fast16_t[^(?-mix:\\w)]|int_fast32_t[^(?-mix:\\w)]|int_fast64_t[^(?-mix:\\w)]|uint_fast8_t[^(?-mix:\\w)]|uint_fast16_t[^(?-mix:\\w)]|uint_fast32_t[^(?-mix:\\w)]|uint_fast64_t[^(?-mix:\\w)]|intptr_t[^(?-mix:\\w)]|uintptr_t[^(?-mix:\\w)]|intmax_t[^(?-mix:\\w)]|intmax_t[^(?-mix:\\w)]|uintmax_t[^(?-mix:\\w)]|uintmax_t[^(?-mix:\\w)])(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U000[0-9a-fA-F]))(?:(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U000[0-9a-fA-F])))*\\b(?!\\())", + "type_casting_operators": { + "match": "((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?|->\\*))\\s*(?-mix:(?:(?:(?\\*|->))))", - "name": "variable.other.object.property.cpp" - }, - { - "match": "(?:((?\\*|->)))", - "captures": { - "1": { - "name": "variable.language.this.cpp" - }, - "2": { - "name": "variable.other.object.access.cpp" - }, - "3": { - "name": "punctuation.separator.dot-access.cpp" - }, - "4": { - "name": "punctuation.separator.pointer-access.cpp" - } - } - }, - { - "include": "#member_access" + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" }, { - "include": "#method_access" + "match": "\\*", + "name": "comment.block.cpp" } ] }, - "6": { - "name": "variable.other.property.cpp" + "5": { + "name": "keyword.operator.wordlike.cpp keyword.operator.cast.$5.cpp" } } }, - "method_access": { - "contentName": "meta.function-call.member", - "begin": "(?:((?\\*|->)))((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U000[0-9a-fA-F]))(?:(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U000[0-9a-fA-F])))*\\s*(?-mix:(?:(?:\\.\\*|\\.))|(?:(?:->\\*|->)))\\s*)*)\\s*((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U000[0-9a-fA-F]))(?:(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U000[0-9a-fA-F])))*)(\\()", - "beginCaptures": { + "memory_operators": { + "match": "((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?:(delete)\\s*(\\[\\])|(delete))|(new))(?!\\w))", + "captures": { "1": { - "name": "variable.language.this.cpp" + "patterns": [ + { + "include": "#inline_comment" + } + ] }, "2": { - "name": "variable.other.object.access.cpp" + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" }, "3": { - "name": "punctuation.separator.dot-access.cpp" + "name": "comment.block.cpp" }, "4": { - "name": "punctuation.separator.pointer-access.cpp" - }, - "5": { "patterns": [ { - "match": "(?<=(?:\\.\\*|\\.|->|->\\*))\\s*(?-mix:(?:(?:(?\\*|->))))", - "name": "variable.other.object.property.cpp" - }, - { - "match": "(?:((?\\*|->)))", - "captures": { - "1": { - "name": "variable.language.this.cpp" - }, - "2": { - "name": "variable.other.object.access.cpp" - }, - "3": { - "name": "punctuation.separator.dot-access.cpp" - }, - "4": { - "name": "punctuation.separator.pointer-access.cpp" - } - } - }, - { - "include": "#member_access" + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" }, { - "include": "#method_access" + "match": "\\*", + "name": "comment.block.cpp" } ] }, + "5": { + "name": "keyword.operator.wordlike.cpp" + }, "6": { - "name": "entity.name.function.member.cpp" + "name": "keyword.operator.delete.array.cpp" }, "7": { - "name": "punctuation.section.arguments.begin.bracket.round.function.member.cpp" - } - }, - "end": "(\\))", - "endCaptures": { - "1": { - "name": "punctuation.section.arguments.end.bracket.round.function.member.cpp" - } - }, - "patterns": [ - { - "include": "#function_call_context_c" + "name": "keyword.operator.delete.array.bracket.cpp" + }, + "8": { + "name": "keyword.operator.delete.cpp" + }, + "9": { + "name": "keyword.operator.new.cpp" } - ] + } }, - "using_namespace": { - "name": "meta.using-namespace.cpp", - "begin": "(?:,\\w])*>\\s*)))?::)*\\s*))?((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:,\\w])*>\\s*)))?::)*\\s*)\\s*(?:((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)", + "captures": { "1": { - "name": "meta.head.namespace.cpp" + "name": "keyword.control.goto.cpp" }, "2": { - "name": "keyword.other.namespace.definition.cpp storage.type.namespace.definition.cpp" - }, - "3": { "patterns": [ { - "include": "#attributes" + "include": "#inline_comment" } ] }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, "4": { + "name": "comment.block.cpp" + }, + "5": { "patterns": [ { - "include": "#scope_resolution" + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" } ] }, - "5": { - "name": "entity.name.type.namespace.cpp" + "6": { + "name": "entity.name.label.call.cpp" } - }, - "end": "(?:(?<=\\})|(?=[;>\\[\\]=]))", - "patterns": [ - { - "name": "meta.head.namespace.cpp", - "begin": "\\G| ", - "end": "((?:\\{|(?=;)))", - "endCaptures": { - "1": { - "name": "punctuation.section.block.begin.bracket.curly.namespace.cpp" + } + }, + "label": { + "match": "((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(:)", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" } - } + ] }, - { - "name": "meta.body.namespace.cpp", - "begin": "(?<=\\{)", - "end": "(\\})", - "endCaptures": { - "1": { - "name": "punctuation.section.block.end.bracket.curly.namespace.cpp" + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" } - }, + ] + }, + "5": { + "name": "entity.name.label.cpp" + }, + "6": { "patterns": [ { - "include": "$base" + "include": "#inline_comment" } ] }, - { - "name": "meta.tail.namespace.cpp", - "begin": "(?<=})[\\s\\n]*", - "end": "[\\s\\n]*(?=;)", + "7": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "8": { + "name": "comment.block.cpp" + }, + "9": { "patterns": [ { - "include": "$base" + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" } ] + }, + "10": { + "name": "punctuation.separator.label.cpp" } - ] - }, - "macro_argument": { - "match": "##(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U000[0-9a-fA-F]))(?:(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U000[0-9a-fA-F])))*(?!\\w)", - "name": "variable.other.macro.argument.cpp" + } }, - "lambdas": { - "begin": "((?:(?<=[^\\s]|^)(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?)(.+?(?=\\{|$))?", - "captures": { - "1": { - "name": "punctuation.definition.lambda.return-type.cpp" - }, - "2": { - "name": "storage.type.return-type.lambda.cpp" - } - } + "3": { + "name": "comment.block.cpp" }, - { - "name": "meta.function.definition.body.lambda.cpp", - "begin": "(\\{)", - "beginCaptures": { - "1": { - "name": "punctuation.section.block.begin.bracket.curly.lambda.cpp" - } - }, - "end": "(\\})", - "endCaptures": { - "1": { - "name": "punctuation.section.block.end.bracket.curly.lambda.cpp" - } - }, + "4": { "patterns": [ { - "include": "$base" + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" } ] + }, + "5": { + "name": "keyword.control.case.cpp" + } + }, + "end": "(:)", + "endCaptures": { + "1": { + "name": "punctuation.separator.colon.case.cpp" + } + }, + "patterns": [ + { + "include": "#evaluation_context" + }, + { + "include": "#c_conditional_context" } ] }, - "pthread_types": { - "match": "(?:,\\w])*>\\s*)))?::)*\\s*)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U000[0-9a-fA-F]))(?:(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U000[0-9a-fA-F])))*)\\s*(?:(<(?:[\\s<>:,\\w])*>\\s*))?(::)))?\\s*((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()", "beginCaptures": { "1": { - "name": "meta.head.enum.cpp" + "patterns": [ + { + "include": "#inline_comment" + } + ] }, "2": { - "name": "storage.type.enum.cpp" + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" }, "3": { - "name": "storage.type.enum.enum-key.$3.cpp" + "name": "comment.block.cpp" }, "4": { "patterns": [ { - "include": "#attributes" - } - ] - }, - "5": { - "patterns": [ + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, { - "include": "#attributes" + "match": "\\*", + "name": "comment.block.cpp" } ] }, - "6": { - "name": "entity.name.type.enum.cpp" - }, - "7": { - "name": "colon.cpp punctuation.separator.type-specifier.cpp" + "5": { + "name": "punctuation.section.parens.begin.bracket.round.conditional.switch.cpp" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.parens.end.bracket.round.conditional.switch.cpp" + } + }, + "patterns": [ + { + "include": "#evaluation_context" }, - "8": { - "name": "meta.scope-resolution.cpp" + { + "include": "#c_conditional_context" + } + ] + }, + "switch_statement": { + "name": "meta.block.switch.cpp", + "begin": "(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\[\\]=]))", - "endCaptures": { - "1": { - "name": "punctuation.terminator.statement.cpp" - }, - "2": { - "name": "punctuation.terminator.statement.cpp" + "6": { + "name": "keyword.control.switch.cpp" } }, + "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))", "patterns": [ { - "name": "meta.head.enum.cpp", - "begin": "\\G| ", - "end": "((?:\\{|(?=;)))", + "name": "meta.head.switch.cpp", + "begin": "\\G ?", + "end": "((?:\\{|<%|\\?\\?<|(?=;)))", "endCaptures": { "1": { - "name": "punctuation.section.block.begin.bracket.curly.enum.cpp" + "name": "punctuation.section.block.begin.bracket.curly.switch.cpp" } }, "patterns": [ + { + "include": "#switch_conditional_parentheses" + }, { "include": "$base" } ] }, { - "name": "meta.body.enum.cpp", - "begin": "(?<=\\{)", - "end": "(\\})", + "name": "meta.body.switch.cpp", + "begin": "(?<=\\{|<%|\\?\\?<)", + "end": "(\\}|%>|\\?\\?>)", "endCaptures": { "1": { - "name": "punctuation.section.block.end.bracket.curly.enum.cpp" + "name": "punctuation.section.block.end.bracket.curly.switch.cpp" } }, "patterns": [ + { + "include": "#default_statement" + }, + { + "include": "#case_statement" + }, { "include": "$base" + }, + { + "include": "#block_innards" } ] }, { - "name": "meta.tail.enum.cpp", - "begin": "(?<=})[\\s\\n]*", + "name": "meta.tail.switch.cpp", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", "end": "[\\s\\n]*(?=;)", "patterns": [ { @@ -1651,2363 +1669,17746 @@ } ] }, - "inhertance_context": { + "cpp_attributes": { + "name": "support.other.attribute.cpp", + "begin": "(\\[\\[)", + "beginCaptures": { + "1": { + "name": "punctuation.section.attribute.begin.cpp" + } + }, + "end": "(\\]\\])", + "endCaptures": { + "1": { + "name": "punctuation.section.attribute.end.cpp" + } + }, "patterns": [ { - "match": ",", - "name": "comma.cpp punctuation.separator.delimiter.inhertance.cpp" + "include": "#attributes_context" }, { - "match": "(?\\[\\]=]))", + "end": "(\\))", "endCaptures": { "1": { - "name": "punctuation.terminator.statement.cpp" - }, - "2": { - "name": "punctuation.terminator.statement.cpp" + "name": "punctuation.section.attribute.end.cpp" } }, "patterns": [ { - "name": "meta.head.class.cpp", - "begin": "\\G| ", - "end": "((?:\\{|(?=;)))", - "endCaptures": { - "1": { - "name": "punctuation.section.block.begin.bracket.curly.class.cpp" - } - }, + "include": "#attributes_context" + }, + { + "begin": "\\(", + "end": "\\)", "patterns": [ { - "include": "#preprocessor_context" - }, - { - "include": "#inhertance_context" - }, - { - "include": "#template_call_range" + "include": "#attributes_context" }, { - "include": "#comments_context" + "include": "#string_context_c" } ] }, { - "name": "meta.body.class.cpp", - "begin": "(?<=\\{)", - "end": "(\\})", - "endCaptures": { + "match": "(using)\\s+((?]*|[^>]*+<[^>]*+>)++>\\s*", + "captures": { + "0": { + "name": "meta.template.call.cpp", "patterns": [ { - "include": "#inhertance_context" + "include": "#template_call_range" } ] } + } + }, + "template_call_range": { + "name": "meta.template.call.cpp", + "begin": "(<)", + "beginCaptures": { + "1": { + "name": "punctuation.section.angle-brackets.begin.template.call.cpp" + } }, - "end": "(?:(?:(?<=})\\s*(;)|(;))|(?=[;>\\[\\]=]))", + "end": "(>)", "endCaptures": { "1": { - "name": "punctuation.terminator.statement.cpp" - }, - "2": { - "name": "punctuation.terminator.statement.cpp" + "name": "punctuation.section.angle-brackets.end.template.call.cpp" } }, "patterns": [ { - "name": "meta.head.struct.cpp", - "begin": "\\G| ", - "end": "((?:\\{|(?=;)))", - "endCaptures": { - "1": { - "name": "punctuation.section.block.begin.bracket.curly.struct.cpp" - } - }, - "patterns": [ - { - "include": "#preprocessor_context" - }, - { - "include": "#inhertance_context" - }, - { - "include": "#template_call_range" - }, + "include": "#template_call_context" + } + ] + }, + "template_isolated_definition": { + "match": "(?\\s*$)", + "captures": { + "1": { + "name": "storage.type.template.cpp" + }, + "2": { + "name": "punctuation.section.angle-brackets.start.template.definition.cpp" + }, + "3": { + "name": "meta.template.definition.cpp", + "patterns": [ { - "include": "#comments_context" + "include": "#template_definition_context" } ] }, + "4": { + "name": "punctuation.section.angle-brackets.end.template.definition.cpp" + } + } + }, + "template_definition": { + "name": "meta.template.definition.cpp", + "begin": "(?)", + "endCaptures": { + "1": { + "name": "punctuation.section.angle-brackets.end.template.definition.cpp" + } + }, + "patterns": [ { - "name": "meta.body.struct.cpp", - "begin": "(?<=\\{)", - "end": "(\\})", + "begin": "((?<=\\w)\\s*<)", + "beginCaptures": { + "1": { + "name": "punctuation.section.angle-brackets.begin.template.call.cpp" + } + }, + "end": "(>)", "endCaptures": { "1": { - "name": "punctuation.section.block.end.bracket.curly.struct.cpp" + "name": "punctuation.section.angle-brackets.begin.template.call.cpp" } }, "patterns": [ { - "include": "#constructor_context" - }, - { - "include": "$base" + "include": "#template_call_context" } ] }, { - "name": "meta.tail.struct.cpp", - "begin": "(?<=})[\\s\\n]*", - "end": "[\\s\\n]*(?=;)", - "patterns": [ - { - "include": "$base" - } - ] + "include": "#template_definition_context" } ] }, - "union_block": { - "name": "meta.block.union.cpp", - "begin": "((((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)|((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s+)+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))|((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*(\\.\\.\\.)\\s*((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*))\\s*(?:(,)|(?=>|$))", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" }, "4": { "patterns": [ { - "include": "#attributes" + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" } ] }, "5": { + "name": "storage.type.template.argument.$5.cpp" + }, + "6": { "patterns": [ { - "include": "#attributes" + "match": "(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*", + "name": "storage.type.template.argument.$0.cpp" } ] }, - "6": { - "name": "entity.name.type.$3.cpp" - }, "7": { - "name": "storage.type.modifier.final.cpp" + "name": "entity.name.type.template.cpp" }, "8": { - "name": "colon.cpp punctuation.separator.inhertance.cpp" + "name": "storage.type.template.cpp" }, "9": { + "name": "ellipses.cpp punctuation.vararg-ellipses.template.definition.cpp" + }, + "10": { + "name": "entity.name.type.template.cpp" + }, + "11": { + "name": "punctuation.separator.delimiter.comma.template.argument.cpp" + } + } + }, + "scope_resolution": { + "match": "(?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+", + "captures": { + "0": { "patterns": [ { - "include": "#inhertance_context" + "include": "#scope_resolution_inner_generated" } ] } - }, - "end": "(?:(?:(?<=})\\s*(;)|(;))|(?=[;>\\[\\]=]))", - "endCaptures": { + } + }, + "scope_resolution_inner_generated": { + "match": "((?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+((?]*|[^>]*+<[^>]*+>)++>\\s*)?(::)", + "captures": { "1": { - "name": "punctuation.terminator.statement.cpp" + "patterns": [ + { + "include": "#scope_resolution_inner_generated" + } + ] }, "2": { - "name": "punctuation.terminator.statement.cpp" - } - }, - "patterns": [ - { - "name": "meta.head.union.cpp", - "begin": "\\G| ", - "end": "((?:\\{|(?=;)))", - "endCaptures": { - "1": { - "name": "punctuation.section.block.begin.bracket.curly.union.cpp" - } - }, + "name": "entity.name.scope-resolution.cpp" + }, + "3": { + "name": "meta.template.call.cpp", "patterns": [ - { - "include": "#preprocessor_context" - }, - { - "include": "#inhertance_context" - }, { "include": "#template_call_range" - }, - { - "include": "#comments_context" } ] }, - { - "name": "meta.body.union.cpp", - "begin": "(?<=\\{)", - "end": "(\\})", - "endCaptures": { - "1": { - "name": "punctuation.section.block.end.bracket.curly.union.cpp" + "4": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp" + } + } + }, + "scope_resolution_template_call": { + "match": "(?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+", + "captures": { + "0": { + "patterns": [ + { + "include": "#scope_resolution_template_call_inner_generated" } - }, + ] + } + } + }, + "scope_resolution_template_call_inner_generated": { + "match": "((?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+((?]*|[^>]*+<[^>]*+>)++>\\s*)?(::)", + "captures": { + "1": { "patterns": [ { - "include": "#constructor_context" - }, + "include": "#scope_resolution_template_call_inner_generated" + } + ] + }, + "2": { + "name": "entity.name.scope-resolution.template.call.cpp" + }, + "3": { + "name": "meta.template.call.cpp", + "patterns": [ { - "include": "$base" + "include": "#template_call_range" } ] }, - { - "name": "meta.tail.union.cpp", - "begin": "(?<=})[\\s\\n]*", - "end": "[\\s\\n]*(?=;)", + "4": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.template.call.cpp" + } + } + }, + "scope_resolution_template_definition": { + "match": "(?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+", + "captures": { + "0": { "patterns": [ { - "include": "$base" + "include": "#scope_resolution_template_definition_inner_generated" } ] } - ] + } }, - "extern_block": { - "name": "meta.block.extern.cpp", - "begin": "((\\bextern)(?=\\s*\\\"))", - "beginCaptures": { + "scope_resolution_template_definition_inner_generated": { + "match": "((?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+((?]*|[^>]*+<[^>]*+>)++>\\s*)?(::)", + "captures": { "1": { - "name": "meta.head.extern.cpp" + "patterns": [ + { + "include": "#scope_resolution_template_definition_inner_generated" + } + ] }, "2": { - "name": "storage.type.extern.cpp" - } - }, - "end": "(?:(?:(?<=})\\s*(;)|(;))|(?=[;>\\[\\]=]))", - "endCaptures": { - "1": { - "name": "punctuation.terminator.statement.cpp" + "name": "entity.name.scope-resolution.template.definition.cpp" }, - "2": { - "name": "punctuation.terminator.statement.cpp" - } - }, - "patterns": [ - { - "name": "meta.head.extern.cpp", - "begin": "\\G| ", - "end": "((?:\\{|(?=;)))", - "endCaptures": { - "1": { - "name": "punctuation.section.block.begin.bracket.curly.extern.cpp" - } - }, + "3": { + "name": "meta.template.call.cpp", "patterns": [ { - "include": "$base" + "include": "#template_call_range" } ] }, - { - "name": "meta.body.extern.cpp", - "begin": "(?<=\\{)", - "end": "(\\})", - "endCaptures": { - "1": { - "name": "punctuation.section.block.end.bracket.curly.extern.cpp" + "4": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.template.definition.cpp" + } + } + }, + "scope_resolution_function_call": { + "match": "(?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+", + "captures": { + "0": { + "patterns": [ + { + "include": "#scope_resolution_function_call_inner_generated" } - }, + ] + } + } + }, + "scope_resolution_function_call_inner_generated": { + "match": "((?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+((?]*|[^>]*+<[^>]*+>)++>\\s*)?(::)", + "captures": { + "1": { "patterns": [ { - "include": "$base" + "include": "#scope_resolution_function_call_inner_generated" } ] }, - { - "name": "meta.tail.extern.cpp", - "begin": "(?<=})[\\s\\n]*", - "end": "[\\s\\n]*(?=;)", + "2": { + "name": "entity.name.scope-resolution.function.call.cpp" + }, + "3": { + "name": "meta.template.call.cpp", "patterns": [ { - "include": "$base" + "include": "#template_call_range" } ] }, - { - "include": "$base" + "4": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.call.cpp" } - ] + } }, - "hacky_fix_for_stray_directive": { - "match": "(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+", + "captures": { + "0": { + "patterns": [ + { + "include": "#scope_resolution_function_definition_inner_generated" + } + ] + } + } }, - "square_brackets": { - "name": "meta.bracket.square.access.cpp", - "begin": "([a-zA-Z_][a-zA-Z_0-9]*|(?<=[\\]\\)]))?(\\[)(?!\\])", - "beginCaptures": { + "scope_resolution_function_definition_inner_generated": { + "match": "((?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+((?]*|[^>]*+<[^>]*+>)++>\\s*)?(::)", + "captures": { "1": { - "name": "variable.other.object.cpp" + "patterns": [ + { + "include": "#scope_resolution_function_definition_inner_generated" + } + ] }, "2": { - "name": "punctuation.definition.begin.bracket.square.cpp" + "name": "entity.name.scope-resolution.function.definition.cpp" + }, + "3": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "4": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.cpp" } - }, - "end": "\\]", - "endCaptures": { + } + }, + "scope_resolution_namespace_alias": { + "match": "(?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+", + "captures": { "0": { - "name": "punctuation.definition.end.bracket.square.cpp" - } - }, - "patterns": [ - { - "include": "#function_call_context_c" + "patterns": [ + { + "include": "#scope_resolution_namespace_alias_inner_generated" + } + ] } - ] - }, - "empty_square_brackets": { - "name": "storage.modifier.array.bracket.square.cpp", - "match": "(?-mix:(?-mix:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+((?]*|[^>]*+<[^>]*+>)++>\\s*)?(::)", + "captures": { "1": { - "name": "entity.name.function.destructor.cpp" + "patterns": [ + { + "include": "#scope_resolution_namespace_alias_inner_generated" + } + ] }, "2": { - "name": "punctuation.definition.parameters.begin.destructor.cpp" + "name": "entity.name.scope-resolution.namespace.alias.cpp" + }, + "3": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "4": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.alias.cpp" } - }, - "end": "(?-mix:\\))", - "endCaptures": { + } + }, + "scope_resolution_namespace_using": { + "match": "(?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+", + "captures": { "0": { - "name": "punctuation.definition.parameters.end.destructor.cpp" - } - }, - "patterns": [ - { - "include": "$base" + "patterns": [ + { + "include": "#scope_resolution_namespace_using_inner_generated" + } + ] } - ] + } }, - "destructor_prototype": { - "name": "meta.function.destructor.prototype.cpp", - "begin": "(?x)\n(?:\n ^ | # beginning of line\n (?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+((?]*|[^>]*+<[^>]*+>)++>\\s*)?(::)", + "captures": { "1": { - "name": "entity.name.function.cpp" + "patterns": [ + { + "include": "#scope_resolution_namespace_using_inner_generated" + } + ] }, "2": { - "name": "punctuation.definition.parameters.begin.cpp" + "name": "entity.name.scope-resolution.namespace.using.cpp" + }, + "3": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "4": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.using.cpp" } - }, - "end": "(?-mix:\\))", - "endCaptures": { + } + }, + "scope_resolution_namespace_block": { + "match": "(?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+", + "captures": { "0": { - "name": "punctuation.definition.parameters.end.cpp" - } - }, - "patterns": [ - { - "include": "$base" + "patterns": [ + { + "include": "#scope_resolution_namespace_block_inner_generated" + } + ] } - ] + } }, - "meta_preprocessor_macro": { - "name": "meta.preprocessor.macro.cpp", - "begin": "(?x)\n^\\s* ((\\#)\\s*define) \\s+\t# define\n((?(?-mix:[a-zA-Z_$][\\w$]*)))\t # macro name\n(?:\n (\\()\n\t(\n\t \\s* \\g \\s*\t\t # first argument\n\t ((,) \\s* \\g \\s*)* # additional arguments\n\t (?:\\.\\.\\.)?\t\t\t# varargs ellipsis?\n\t)\n (\\))\n)?", - "beginCaptures": { + "scope_resolution_namespace_block_inner_generated": { + "match": "((?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+((?]*|[^>]*+<[^>]*+>)++>\\s*)?(::)", + "captures": { "1": { - "name": "keyword.control.directive.define.cpp" + "patterns": [ + { + "include": "#scope_resolution_namespace_block_inner_generated" + } + ] }, "2": { - "name": "punctuation.definition.directive.cpp" + "name": "entity.name.scope-resolution.namespace.block.cpp" }, "3": { - "name": "entity.name.function.preprocessor.cpp" - }, - "5": { - "name": "punctuation.definition.parameters.begin.cpp" - }, - "6": { - "name": "variable.parameter.preprocessor.cpp" - }, - "8": { - "name": "punctuation.separator.parameters.cpp" + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] }, - "9": { - "name": "punctuation.definition.parameters.end.cpp" + "4": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.namespace.block.cpp" } - }, - "end": "(?=(?://|/\\*))|(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+", + "captures": { + "0": { + "patterns": [ + { + "include": "#scope_resolution_parameter_inner_generated" + } + ] } - ] + } }, - "meta_preprocessor_diagnostic": { - "name": "meta.preprocessor.diagnostic.cpp", - "begin": "^\\s*((#)\\s*(error|warning))\\b\\s*", - "beginCaptures": { + "scope_resolution_parameter_inner_generated": { + "match": "((?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+((?]*|[^>]*+<[^>]*+>)++>\\s*)?(::)", + "captures": { "1": { - "name": "keyword.control.directive.diagnostic.$3.cpp" - }, - "2": { - "name": "punctuation.definition.directive.cpp" - } - }, - "end": "(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+", + "captures": { + "0": { "patterns": [ { - "include": "#line_continuation_character" - }, - { - "include": "#comments_context" + "include": "#scope_resolution_function_definition_operator_overload_inner_generated" } ] } - ] + } }, - "meta_preprocessor_include": { - "name": "meta.preprocessor.include.cpp", - "begin": "^\\s*((#)\\s*(include(?:_next)?|import))\\b\\s*", - "beginCaptures": { + "scope_resolution_function_definition_operator_overload_inner_generated": { + "match": "((?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+((?]*|[^>]*+<[^>]*+>)++>\\s*)?(::)", + "captures": { "1": { - "name": "keyword.control.directive.$3.cpp" + "patterns": [ + { + "include": "#scope_resolution_function_definition_operator_overload_inner_generated" + } + ] }, "2": { - "name": "punctuation.definition.directive.cpp" - } - }, - "end": "(?=(?://|/\\*))|(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+((?]*|[^>]*+<[^>]*+>)++>\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:not|compl|sizeof|new|delete|not_eq|bitand|xor|bitor|and|or|throw|and_eq|xor_eq|or_eq|alignof|alignas|typeid|noexcept|noexcept|static_cast|dynamic_cast|const_cast|reinterpret_cast|while|for|do|if|else|goto|switch|try|catch|return|break|case|continue|default|NULL|true|false|nullptr|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|final|override|volatile|const|noexcept|constexpr|mutable|constexpr|consteval|private|protected|public|if|elif|else|endif|ifdef|ifndef|define|undef|include|line|error|warning|pragma|_Pragma|defined|__has_include|__has_cpp_attribute|this|template|namespace|using|operator|typedef|decltype|typename|asm|__asm__|concept|requires|export|thread_local|atomic_cancel|atomic_commit|atomic_noexcept|co_await|co_return|co_yield|import|module|reflexpr|synchronized|audit|axiom|transaction_safe|transaction_safe_dynamic)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?![\\w<:.])", + "captures": { + "0": { + "name": "meta.qualified_type.cpp", + "patterns": [ + { + "match": "(?:class|struct|union|enum)", + "name": "storage.type.$0.cpp" + }, + { + "include": "#attributes_context" + }, + { + "include": "#function_type" + }, + { + "include": "#storage_types" + }, + { + "include": "#number_literal" + }, + { + "include": "#string_context_c" + }, + { + "include": "#comma" + }, + { + "include": "#scope_resolution_inner_generated" + }, + { + "include": "#template_call_range" + }, + { + "match": "(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*", + "name": "entity.name.type.cpp" + } + ] + }, + "1": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "7": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "8": { + "name": "comment.block.cpp" + }, + "9": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "11": { + "patterns": [ + { + "include": "#scope_resolution_inner_generated" + } + ] + }, + "12": { + "name": "entity.name.scope-resolution.cpp" + }, + "13": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "14": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp" + }, + "15": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "16": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "17": { + "name": "comment.block.cpp" + }, + "18": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "19": { + "name": "entity.name.type.cpp" + } + } + }, + "simple_type": { + "match": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+((?]*|[^>]*+<[^>]*+>)++>\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:not|compl|sizeof|new|delete|not_eq|bitand|xor|bitor|and|or|throw|and_eq|xor_eq|or_eq|alignof|alignas|typeid|noexcept|noexcept|static_cast|dynamic_cast|const_cast|reinterpret_cast|while|for|do|if|else|goto|switch|try|catch|return|break|case|continue|default|NULL|true|false|nullptr|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|final|override|volatile|const|noexcept|constexpr|mutable|constexpr|consteval|private|protected|public|if|elif|else|endif|ifdef|ifndef|define|undef|include|line|error|warning|pragma|_Pragma|defined|__has_include|__has_cpp_attribute|this|template|namespace|using|operator|typedef|decltype|typename|asm|__asm__|concept|requires|export|thread_local|atomic_cancel|atomic_commit|atomic_noexcept|co_await|co_return|co_yield|import|module|reflexpr|synchronized|audit|axiom|transaction_safe|transaction_safe_dynamic)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?", + "captures": { + "1": { + "name": "meta.qualified_type.cpp", + "patterns": [ + { + "match": "(?:class|struct|union|enum)", + "name": "storage.type.$0.cpp" + }, + { + "include": "#attributes_context" + }, + { + "include": "#function_type" + }, + { + "include": "#storage_types" + }, + { + "include": "#number_literal" + }, + { + "include": "#string_context_c" + }, + { + "include": "#comma" + }, + { + "include": "#scope_resolution_inner_generated" + }, + { + "include": "#template_call_range" + }, + { + "match": "(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*", + "name": "entity.name.type.cpp" + } + ] + }, + "2": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "3": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "4": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "5": { + "name": "comment.block.cpp" + }, + "6": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "7": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "8": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "9": { + "name": "comment.block.cpp" + }, + "10": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "12": { + "patterns": [ + { + "include": "#scope_resolution_inner_generated" + } + ] + }, + "13": { + "name": "entity.name.scope-resolution.cpp" + }, + "14": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "15": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp" + }, + "16": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "17": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "18": { + "name": "comment.block.cpp" + }, + "19": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "20": { + "name": "entity.name.type.cpp" + }, + "21": { + "patterns": [ + { + "match": "\\*", + "name": "storage.modifier.pointer.cpp" + }, + { + "match": "(?:\\&((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))){2,}\\&", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "name": "invalid.illegal.reference-type.cpp" + }, + { + "match": "\\&", + "name": "storage.modifier.reference.cpp" + } + ] + }, + "22": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "23": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "24": { + "name": "comment.block.cpp" + }, + "25": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "26": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "27": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "28": { + "name": "comment.block.cpp" + }, + "29": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + } + }, + "type_alias": { + "match": "(using)\\s*(?!namespace)(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+((?]*|[^>]*+<[^>]*+>)++>\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:not|compl|sizeof|new|delete|not_eq|bitand|xor|bitor|and|or|throw|and_eq|xor_eq|or_eq|alignof|alignas|typeid|noexcept|noexcept|static_cast|dynamic_cast|const_cast|reinterpret_cast|while|for|do|if|else|goto|switch|try|catch|return|break|case|continue|default|NULL|true|false|nullptr|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|final|override|volatile|const|noexcept|constexpr|mutable|constexpr|consteval|private|protected|public|if|elif|else|endif|ifdef|ifndef|define|undef|include|line|error|warning|pragma|_Pragma|defined|__has_include|__has_cpp_attribute|this|template|namespace|using|operator|typedef|decltype|typename|asm|__asm__|concept|requires|export|thread_local|atomic_cancel|atomic_commit|atomic_noexcept|co_await|co_return|co_yield|import|module|reflexpr|synchronized|audit|axiom|transaction_safe|transaction_safe_dynamic)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?![\\w<:.]))\\s*(\\=)\\s*((?:typename)?)\\s*((?:(?:(?:(?:(?>\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+((?]*|[^>]*+<[^>]*+>)++>\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:not|compl|sizeof|new|delete|not_eq|bitand|xor|bitor|and|or|throw|and_eq|xor_eq|or_eq|alignof|alignas|typeid|noexcept|noexcept|static_cast|dynamic_cast|const_cast|reinterpret_cast|while|for|do|if|else|goto|switch|try|catch|return|break|case|continue|default|NULL|true|false|nullptr|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|final|override|volatile|const|noexcept|constexpr|mutable|constexpr|consteval|private|protected|public|if|elif|else|endif|ifdef|ifndef|define|undef|include|line|error|warning|pragma|_Pragma|defined|__has_include|__has_cpp_attribute|this|template|namespace|using|operator|typedef|decltype|typename|asm|__asm__|concept|requires|export|thread_local|atomic_cancel|atomic_commit|atomic_noexcept|co_await|co_return|co_yield|import|module|reflexpr|synchronized|audit|axiom|transaction_safe|transaction_safe_dynamic)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?![\\w<:.]))|(.*(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?(?:(\\[)(\\w*)(\\])\\s*)?\\s*(?:(;)|\\n)", + "captures": { + "1": { + "name": "keyword.other.using.directive.cpp" + }, + "2": { + "name": "meta.qualified_type.cpp", + "patterns": [ + { + "match": "(?:class|struct|union|enum)", + "name": "storage.type.$0.cpp" + }, + { + "include": "#attributes_context" + }, + { + "include": "#function_type" + }, + { + "include": "#storage_types" + }, + { + "include": "#number_literal" + }, + { + "include": "#string_context_c" + }, + { + "include": "#comma" + }, + { + "include": "#scope_resolution_inner_generated" + }, + { + "include": "#template_call_range" + }, + { + "match": "(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*", + "name": "entity.name.type.cpp" + } + ] + }, + "3": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "4": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "5": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "6": { + "name": "comment.block.cpp" + }, + "7": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "8": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "9": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "10": { + "name": "comment.block.cpp" + }, + "11": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "13": { + "patterns": [ + { + "include": "#scope_resolution_inner_generated" + } + ] + }, + "14": { + "name": "entity.name.scope-resolution.cpp" + }, + "15": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "16": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp" + }, + "17": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "18": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "19": { + "name": "comment.block.cpp" + }, + "20": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "21": { + "name": "entity.name.type.cpp" + }, + "22": { + "name": "keyword.operator.assignment.cpp" + }, + "23": { + "name": "keyword.other.typename.cpp" + }, + "24": { + "patterns": [ + { + "include": "#storage_specifiers" + } + ] + }, + "25": { + "name": "meta.qualified_type.cpp", + "patterns": [ + { + "match": "(?:class|struct|union|enum)", + "name": "storage.type.$0.cpp" + }, + { + "include": "#attributes_context" + }, + { + "include": "#function_type" + }, + { + "include": "#storage_types" + }, + { + "include": "#number_literal" + }, + { + "include": "#string_context_c" + }, + { + "include": "#comma" + }, + { + "include": "#scope_resolution_inner_generated" + }, + { + "include": "#template_call_range" + }, + { + "match": "(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*", + "name": "entity.name.type.cpp" + } + ] + }, + "26": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "27": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "28": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "29": { + "name": "comment.block.cpp" + }, + "30": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "31": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "32": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "33": { + "name": "comment.block.cpp" + }, + "34": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "36": { + "patterns": [ + { + "include": "#scope_resolution_inner_generated" + } + ] + }, + "37": { + "name": "entity.name.scope-resolution.cpp" + }, + "38": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "39": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp" + }, + "40": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "41": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "42": { + "name": "comment.block.cpp" + }, + "43": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "44": { + "name": "entity.name.type.cpp" + }, + "45": { + "name": "meta.declaration.type.alias.value.unknown.cpp", + "patterns": [ + { + "include": "#evaluation_context" + } + ] + }, + "46": { + "patterns": [ + { + "match": "\\*", + "name": "storage.modifier.pointer.cpp" + }, + { + "match": "(?:\\&((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))){2,}\\&", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "name": "invalid.illegal.reference-type.cpp" + }, + { + "match": "\\&", + "name": "storage.modifier.reference.cpp" + } + ] + }, + "47": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "48": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "49": { + "name": "comment.block.cpp" + }, + "50": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "51": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "52": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "53": { + "name": "comment.block.cpp" + }, + "54": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "55": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "56": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "57": { + "name": "comment.block.cpp" + }, + "58": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "59": { + "name": "punctuation.definition.begin.bracket.square.cpp" + }, + "60": { + "patterns": [ + { + "include": "#evaluation_context" + } + ] + }, + "61": { + "name": "punctuation.definition.end.bracket.square.cpp" + }, + "62": { + "name": "punctuation.terminator.statement.cpp" + } + }, + "name": "meta.declaration.type.alias.cpp" + }, + "typename": { + "match": "(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+((?]*|[^>]*+<[^>]*+>)++>\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:not|compl|sizeof|new|delete|not_eq|bitand|xor|bitor|and|or|throw|and_eq|xor_eq|or_eq|alignof|alignas|typeid|noexcept|noexcept|static_cast|dynamic_cast|const_cast|reinterpret_cast|while|for|do|if|else|goto|switch|try|catch|return|break|case|continue|default|NULL|true|false|nullptr|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|final|override|volatile|const|noexcept|constexpr|mutable|constexpr|consteval|private|protected|public|if|elif|else|endif|ifdef|ifndef|define|undef|include|line|error|warning|pragma|_Pragma|defined|__has_include|__has_cpp_attribute|this|template|namespace|using|operator|typedef|decltype|typename|asm|__asm__|concept|requires|export|thread_local|atomic_cancel|atomic_commit|atomic_noexcept|co_await|co_return|co_yield|import|module|reflexpr|synchronized|audit|axiom|transaction_safe|transaction_safe_dynamic)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?![\\w<:.]))", + "captures": { + "1": { + "name": "storage.modifier.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "7": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "8": { + "name": "comment.block.cpp" + }, + "9": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "10": { + "name": "meta.qualified_type.cpp", + "patterns": [ + { + "match": "(?:class|struct|union|enum)", + "name": "storage.type.$0.cpp" + }, + { + "include": "#attributes_context" + }, + { + "include": "#function_type" + }, + { + "include": "#storage_types" + }, + { + "include": "#number_literal" + }, + { + "include": "#string_context_c" + }, + { + "include": "#comma" + }, + { + "include": "#scope_resolution_inner_generated" + }, + { + "include": "#template_call_range" + }, + { + "match": "(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*", + "name": "entity.name.type.cpp" + } + ] + }, + "11": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "12": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "13": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "14": { + "name": "comment.block.cpp" + }, + "15": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "16": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "17": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "18": { + "name": "comment.block.cpp" + }, + "19": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "21": { + "patterns": [ + { + "include": "#scope_resolution_inner_generated" + } + ] + }, + "22": { + "name": "entity.name.scope-resolution.cpp" + }, + "23": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "24": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp" + }, + "25": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "26": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "27": { + "name": "comment.block.cpp" + }, + "28": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "29": { + "name": "entity.name.type.cpp" + } + } + }, + "predefined_macros": { + "patterns": [ + { + "match": "\\b__cplusplus\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__cplusplus.cpp" + }, + { + "match": "\\b__DATE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__DATE__.cpp" + }, + { + "match": "\\b__FILE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__FILE__.cpp" + }, + { + "match": "\\b__LINE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__LINE__.cpp" + }, + { + "match": "\\b__STDC__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__STDC__.cpp" + }, + { + "match": "\\b__STDC_HOSTED__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__STDC_HOSTED__.cpp" + }, + { + "match": "\\b__STDC_NO_COMPLEX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__STDC_NO_COMPLEX__.cpp" + }, + { + "match": "\\b__STDC_VERSION__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__STDC_VERSION__.cpp" + }, + { + "match": "\\b__STDCPP_THREADS__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__STDCPP_THREADS__.cpp" + }, + { + "match": "\\b__TIME__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__TIME__.cpp" + }, + { + "match": "\\bNDEBUG\\b", + "name": "entity.name.other.preprocessor.macro.predefined.NDEBUG.cpp" + }, + { + "match": "\\b__OBJC__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__OBJC__.cpp" + }, + { + "match": "\\b__ASSEMBLER__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__ASSEMBLER__.cpp" + }, + { + "match": "\\b__ATOM__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__ATOM__.cpp" + }, + { + "match": "\\b__AVX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__AVX__.cpp" + }, + { + "match": "\\b__AVX2__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__AVX2__.cpp" + }, + { + "match": "\\b_CHAR_UNSIGNED\\b", + "name": "entity.name.other.preprocessor.macro.predefined._CHAR_UNSIGNED.cpp" + }, + { + "match": "\\b__CLR_VER\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__CLR_VER.cpp" + }, + { + "match": "\\b_CONTROL_FLOW_GUARD\\b", + "name": "entity.name.other.preprocessor.macro.predefined._CONTROL_FLOW_GUARD.cpp" + }, + { + "match": "\\b__COUNTER__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__COUNTER__.cpp" + }, + { + "match": "\\b__cplusplus_cli\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__cplusplus_cli.cpp" + }, + { + "match": "\\b__cplusplus_winrt\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__cplusplus_winrt.cpp" + }, + { + "match": "\\b_CPPRTTI\\b", + "name": "entity.name.other.preprocessor.macro.predefined._CPPRTTI.cpp" + }, + { + "match": "\\b_CPPUNWIND\\b", + "name": "entity.name.other.preprocessor.macro.predefined._CPPUNWIND.cpp" + }, + { + "match": "\\b_DEBUG\\b", + "name": "entity.name.other.preprocessor.macro.predefined._DEBUG.cpp" + }, + { + "match": "\\b_DLL\\b", + "name": "entity.name.other.preprocessor.macro.predefined._DLL.cpp" + }, + { + "match": "\\b__FUNCDNAME__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__FUNCDNAME__.cpp" + }, + { + "match": "\\b__FUNCSIG__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__FUNCSIG__.cpp" + }, + { + "match": "\\b__FUNCTION__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__FUNCTION__.cpp" + }, + { + "match": "\\b_INTEGRAL_MAX_BITS\\b", + "name": "entity.name.other.preprocessor.macro.predefined._INTEGRAL_MAX_BITS.cpp" + }, + { + "match": "\\b__INTELLISENSE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INTELLISENSE__.cpp" + }, + { + "match": "\\b_ISO_VOLATILE\\b", + "name": "entity.name.other.preprocessor.macro.predefined._ISO_VOLATILE.cpp" + }, + { + "match": "\\b_KERNEL_MODE\\b", + "name": "entity.name.other.preprocessor.macro.predefined._KERNEL_MODE.cpp" + }, + { + "match": "\\b_M_AMD64\\b", + "name": "entity.name.other.preprocessor.macro.predefined._M_AMD64.cpp" + }, + { + "match": "\\b_M_ARM\\b", + "name": "entity.name.other.preprocessor.macro.predefined._M_ARM.cpp" + }, + { + "match": "\\b_M_ARM_ARMV7VE\\b", + "name": "entity.name.other.preprocessor.macro.predefined._M_ARM_ARMV7VE.cpp" + }, + { + "match": "\\b_M_ARM_FP\\b", + "name": "entity.name.other.preprocessor.macro.predefined._M_ARM_FP.cpp" + }, + { + "match": "\\b_M_ARM64\\b", + "name": "entity.name.other.preprocessor.macro.predefined._M_ARM64.cpp" + }, + { + "match": "\\b_M_CEE\\b", + "name": "entity.name.other.preprocessor.macro.predefined._M_CEE.cpp" + }, + { + "match": "\\b_M_CEE_PURE\\b", + "name": "entity.name.other.preprocessor.macro.predefined._M_CEE_PURE.cpp" + }, + { + "match": "\\b_M_CEE_SAFE\\b", + "name": "entity.name.other.preprocessor.macro.predefined._M_CEE_SAFE.cpp" + }, + { + "match": "\\b_M_FP_EXCEPT\\b", + "name": "entity.name.other.preprocessor.macro.predefined._M_FP_EXCEPT.cpp" + }, + { + "match": "\\b_M_FP_FAST\\b", + "name": "entity.name.other.preprocessor.macro.predefined._M_FP_FAST.cpp" + }, + { + "match": "\\b_M_FP_PRECISE\\b", + "name": "entity.name.other.preprocessor.macro.predefined._M_FP_PRECISE.cpp" + }, + { + "match": "\\b_M_FP_STRICT\\b", + "name": "entity.name.other.preprocessor.macro.predefined._M_FP_STRICT.cpp" + }, + { + "match": "\\b_M_IX86\\b", + "name": "entity.name.other.preprocessor.macro.predefined._M_IX86.cpp" + }, + { + "match": "\\b_M_IX86_FP\\b", + "name": "entity.name.other.preprocessor.macro.predefined._M_IX86_FP.cpp" + }, + { + "match": "\\b_M_X64\\b", + "name": "entity.name.other.preprocessor.macro.predefined._M_X64.cpp" + }, + { + "match": "\\b_MANAGED\\b", + "name": "entity.name.other.preprocessor.macro.predefined._MANAGED.cpp" + }, + { + "match": "\\b_MSC_BUILD\\b", + "name": "entity.name.other.preprocessor.macro.predefined._MSC_BUILD.cpp" + }, + { + "match": "\\b_MSC_EXTENSIONS\\b", + "name": "entity.name.other.preprocessor.macro.predefined._MSC_EXTENSIONS.cpp" + }, + { + "match": "\\b_MSC_FULL_VER\\b", + "name": "entity.name.other.preprocessor.macro.predefined._MSC_FULL_VER.cpp" + }, + { + "match": "\\b_MSC_VER\\b", + "name": "entity.name.other.preprocessor.macro.predefined._MSC_VER.cpp" + }, + { + "match": "\\b_MSVC_LANG\\b", + "name": "entity.name.other.preprocessor.macro.predefined._MSVC_LANG.cpp" + }, + { + "match": "\\b__MSVC_RUNTIME_CHECKS\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__MSVC_RUNTIME_CHECKS.cpp" + }, + { + "match": "\\b_MT\\b", + "name": "entity.name.other.preprocessor.macro.predefined._MT.cpp" + }, + { + "match": "\\b_NATIVE_WCHAR_T_DEFINED\\b", + "name": "entity.name.other.preprocessor.macro.predefined._NATIVE_WCHAR_T_DEFINED.cpp" + }, + { + "match": "\\b_OPENMP\\b", + "name": "entity.name.other.preprocessor.macro.predefined._OPENMP.cpp" + }, + { + "match": "\\b_PREFAST\\b", + "name": "entity.name.other.preprocessor.macro.predefined._PREFAST.cpp" + }, + { + "match": "\\b__TIMESTAMP__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__TIMESTAMP__.cpp" + }, + { + "match": "\\b_VC_NO_DEFAULTLIB\\b", + "name": "entity.name.other.preprocessor.macro.predefined._VC_NO_DEFAULTLIB.cpp" + }, + { + "match": "\\b_WCHAR_T_DEFINED\\b", + "name": "entity.name.other.preprocessor.macro.predefined._WCHAR_T_DEFINED.cpp" + }, + { + "match": "\\b_WIN32\\b", + "name": "entity.name.other.preprocessor.macro.predefined._WIN32.cpp" + }, + { + "match": "\\b_WIN64\\b", + "name": "entity.name.other.preprocessor.macro.predefined._WIN64.cpp" + }, + { + "match": "\\b_WINRT_DLL\\b", + "name": "entity.name.other.preprocessor.macro.predefined._WINRT_DLL.cpp" + }, + { + "match": "\\b_ATL_VER\\b", + "name": "entity.name.other.preprocessor.macro.predefined._ATL_VER.cpp" + }, + { + "match": "\\b_MFC_VER\\b", + "name": "entity.name.other.preprocessor.macro.predefined._MFC_VER.cpp" + }, + { + "match": "\\b__GFORTRAN__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GFORTRAN__.cpp" + }, + { + "match": "\\b__GNUC__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GNUC__.cpp" + }, + { + "match": "\\b__GNUC_MINOR__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GNUC_MINOR__.cpp" + }, + { + "match": "\\b__GNUC_PATCHLEVEL__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GNUC_PATCHLEVEL__.cpp" + }, + { + "match": "\\b__GNUG__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GNUG__.cpp" + }, + { + "match": "\\b__STRICT_ANSI__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__STRICT_ANSI__.cpp" + }, + { + "match": "\\b__BASE_FILE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__BASE_FILE__.cpp" + }, + { + "match": "\\b__INCLUDE_LEVEL__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INCLUDE_LEVEL__.cpp" + }, + { + "match": "\\b__ELF__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__ELF__.cpp" + }, + { + "match": "\\b__VERSION__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__VERSION__.cpp" + }, + { + "match": "\\b__OPTIMIZE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__OPTIMIZE__.cpp" + }, + { + "match": "\\b__OPTIMIZE_SIZE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__OPTIMIZE_SIZE__.cpp" + }, + { + "match": "\\b__NO_INLINE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__NO_INLINE__.cpp" + }, + { + "match": "\\b__GNUC_STDC_INLINE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GNUC_STDC_INLINE__.cpp" + }, + { + "match": "\\b__CHAR_UNSIGNED__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__CHAR_UNSIGNED__.cpp" + }, + { + "match": "\\b__WCHAR_UNSIGNED__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__WCHAR_UNSIGNED__.cpp" + }, + { + "match": "\\b__REGISTER_PREFIX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__REGISTER_PREFIX__.cpp" + }, + { + "match": "\\b__REGISTER_PREFIX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__REGISTER_PREFIX__.cpp" + }, + { + "match": "\\b__SIZE_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIZE_TYPE__.cpp" + }, + { + "match": "\\b__PTRDIFF_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__PTRDIFF_TYPE__.cpp" + }, + { + "match": "\\b__WCHAR_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__WCHAR_TYPE__.cpp" + }, + { + "match": "\\b__WINT_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__WINT_TYPE__.cpp" + }, + { + "match": "\\b__INTMAX_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INTMAX_TYPE__.cpp" + }, + { + "match": "\\b__UINTMAX_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINTMAX_TYPE__.cpp" + }, + { + "match": "\\b__SIG_ATOMIC_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIG_ATOMIC_TYPE__.cpp" + }, + { + "match": "\\b__INT8_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT8_TYPE__.cpp" + }, + { + "match": "\\b__INT16_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT16_TYPE__.cpp" + }, + { + "match": "\\b__INT32_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT32_TYPE__.cpp" + }, + { + "match": "\\b__INT64_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT64_TYPE__.cpp" + }, + { + "match": "\\b__UINT8_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT8_TYPE__.cpp" + }, + { + "match": "\\b__UINT16_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT16_TYPE__.cpp" + }, + { + "match": "\\b__UINT32_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT32_TYPE__.cpp" + }, + { + "match": "\\b__UINT64_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT64_TYPE__.cpp" + }, + { + "match": "\\b__INT_LEAST8_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_LEAST8_TYPE__.cpp" + }, + { + "match": "\\b__INT_LEAST16_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_LEAST16_TYPE__.cpp" + }, + { + "match": "\\b__INT_LEAST32_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_LEAST32_TYPE__.cpp" + }, + { + "match": "\\b__INT_LEAST64_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_LEAST64_TYPE__.cpp" + }, + { + "match": "\\b__UINT_LEAST8_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT_LEAST8_TYPE__.cpp" + }, + { + "match": "\\b__UINT_LEAST16_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT_LEAST16_TYPE__.cpp" + }, + { + "match": "\\b__UINT_LEAST32_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT_LEAST32_TYPE__.cpp" + }, + { + "match": "\\b__UINT_LEAST64_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT_LEAST64_TYPE__.cpp" + }, + { + "match": "\\b__INT_FAST8_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_FAST8_TYPE__.cpp" + }, + { + "match": "\\b__INT_FAST16_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_FAST16_TYPE__.cpp" + }, + { + "match": "\\b__INT_FAST32_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_FAST32_TYPE__.cpp" + }, + { + "match": "\\b__INT_FAST64_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_FAST64_TYPE__.cpp" + }, + { + "match": "\\b__UINT_FAST8_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT_FAST8_TYPE__.cpp" + }, + { + "match": "\\b__UINT_FAST16_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT_FAST16_TYPE__.cpp" + }, + { + "match": "\\b__UINT_FAST32_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT_FAST32_TYPE__.cpp" + }, + { + "match": "\\b__UINT_FAST64_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT_FAST64_TYPE__.cpp" + }, + { + "match": "\\b__INTPTR_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INTPTR_TYPE__.cpp" + }, + { + "match": "\\b__UINTPTR_TYPE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINTPTR_TYPE__.cpp" + }, + { + "match": "\\b__CHAR_BIT__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__CHAR_BIT__.cpp" + }, + { + "match": "\\b__SCHAR_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SCHAR_MAX__.cpp" + }, + { + "match": "\\b__WCHAR_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__WCHAR_MAX__.cpp" + }, + { + "match": "\\b__SHRT_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SHRT_MAX__.cpp" + }, + { + "match": "\\b__INT_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_MAX__.cpp" + }, + { + "match": "\\b__LONG_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__LONG_MAX__.cpp" + }, + { + "match": "\\b__LONG_LONG_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__LONG_LONG_MAX__.cpp" + }, + { + "match": "\\b__WINT_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__WINT_MAX__.cpp" + }, + { + "match": "\\b__SIZE_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIZE_MAX__.cpp" + }, + { + "match": "\\b__PTRDIFF_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__PTRDIFF_MAX__.cpp" + }, + { + "match": "\\b__INTMAX_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INTMAX_MAX__.cpp" + }, + { + "match": "\\b__UINTMAX_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINTMAX_MAX__.cpp" + }, + { + "match": "\\b__SIG_ATOMIC_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIG_ATOMIC_MAX__.cpp" + }, + { + "match": "\\b__INT8_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT8_MAX__.cpp" + }, + { + "match": "\\b__INT16_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT16_MAX__.cpp" + }, + { + "match": "\\b__INT32_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT32_MAX__.cpp" + }, + { + "match": "\\b__INT64_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT64_MAX__.cpp" + }, + { + "match": "\\b__UINT8_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT8_MAX__.cpp" + }, + { + "match": "\\b__UINT16_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT16_MAX__.cpp" + }, + { + "match": "\\b__UINT32_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT32_MAX__.cpp" + }, + { + "match": "\\b__UINT64_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT64_MAX__.cpp" + }, + { + "match": "\\b__INT_LEAST8_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_LEAST8_MAX__.cpp" + }, + { + "match": "\\b__INT_LEAST16_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_LEAST16_MAX__.cpp" + }, + { + "match": "\\b__INT_LEAST32_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_LEAST32_MAX__.cpp" + }, + { + "match": "\\b__INT_LEAST64_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_LEAST64_MAX__.cpp" + }, + { + "match": "\\b__UINT_LEAST8_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT_LEAST8_MAX__.cpp" + }, + { + "match": "\\b__UINT_LEAST16_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT_LEAST16_MAX__.cpp" + }, + { + "match": "\\b__UINT_LEAST32_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT_LEAST32_MAX__.cpp" + }, + { + "match": "\\b__UINT_LEAST64_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT_LEAST64_MAX__.cpp" + }, + { + "match": "\\b__INT_FAST8_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_FAST8_MAX__.cpp" + }, + { + "match": "\\b__INT_FAST16_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_FAST16_MAX__.cpp" + }, + { + "match": "\\b__INT_FAST32_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_FAST32_MAX__.cpp" + }, + { + "match": "\\b__INT_FAST64_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_FAST64_MAX__.cpp" + }, + { + "match": "\\b__UINT_FAST8_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT_FAST8_MAX__.cpp" + }, + { + "match": "\\b__UINT_FAST16_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT_FAST16_MAX__.cpp" + }, + { + "match": "\\b__UINT_FAST32_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT_FAST32_MAX__.cpp" + }, + { + "match": "\\b__UINT_FAST64_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINT_FAST64_MAX__.cpp" + }, + { + "match": "\\b__INTPTR_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INTPTR_MAX__.cpp" + }, + { + "match": "\\b__UINTPTR_MAX__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__UINTPTR_MAX__.cpp" + }, + { + "match": "\\b__WCHAR_MIN__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__WCHAR_MIN__.cpp" + }, + { + "match": "\\b__WINT_MIN__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__WINT_MIN__.cpp" + }, + { + "match": "\\b__SIG_ATOMIC_MIN__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIG_ATOMIC_MIN__.cpp" + }, + { + "match": "\\b__SCHAR_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SCHAR_WIDTH__.cpp" + }, + { + "match": "\\b__SHRT_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SHRT_WIDTH__.cpp" + }, + { + "match": "\\b__INT_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_WIDTH__.cpp" + }, + { + "match": "\\b__LONG_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__LONG_WIDTH__.cpp" + }, + { + "match": "\\b__LONG_LONG_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__LONG_LONG_WIDTH__.cpp" + }, + { + "match": "\\b__PTRDIFF_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__PTRDIFF_WIDTH__.cpp" + }, + { + "match": "\\b__SIG_ATOMIC_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIG_ATOMIC_WIDTH__.cpp" + }, + { + "match": "\\b__SIZE_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIZE_WIDTH__.cpp" + }, + { + "match": "\\b__WCHAR_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__WCHAR_WIDTH__.cpp" + }, + { + "match": "\\b__WINT_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__WINT_WIDTH__.cpp" + }, + { + "match": "\\b__INT_LEAST8_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_LEAST8_WIDTH__.cpp" + }, + { + "match": "\\b__INT_LEAST16_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_LEAST16_WIDTH__.cpp" + }, + { + "match": "\\b__INT_LEAST32_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_LEAST32_WIDTH__.cpp" + }, + { + "match": "\\b__INT_LEAST64_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_LEAST64_WIDTH__.cpp" + }, + { + "match": "\\b__INT_FAST8_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_FAST8_WIDTH__.cpp" + }, + { + "match": "\\b__INT_FAST16_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_FAST16_WIDTH__.cpp" + }, + { + "match": "\\b__INT_FAST32_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_FAST32_WIDTH__.cpp" + }, + { + "match": "\\b__INT_FAST64_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INT_FAST64_WIDTH__.cpp" + }, + { + "match": "\\b__INTPTR_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INTPTR_WIDTH__.cpp" + }, + { + "match": "\\b__INTMAX_WIDTH__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__INTMAX_WIDTH__.cpp" + }, + { + "match": "\\b__SIZEOF_INT__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIZEOF_INT__.cpp" + }, + { + "match": "\\b__SIZEOF_LONG__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIZEOF_LONG__.cpp" + }, + { + "match": "\\b__SIZEOF_LONG_LONG__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIZEOF_LONG_LONG__.cpp" + }, + { + "match": "\\b__SIZEOF_SHORT__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIZEOF_SHORT__.cpp" + }, + { + "match": "\\b__SIZEOF_POINTER__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIZEOF_POINTER__.cpp" + }, + { + "match": "\\b__SIZEOF_FLOAT__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIZEOF_FLOAT__.cpp" + }, + { + "match": "\\b__SIZEOF_DOUBLE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIZEOF_DOUBLE__.cpp" + }, + { + "match": "\\b__SIZEOF_LONG_DOUBLE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIZEOF_LONG_DOUBLE__.cpp" + }, + { + "match": "\\b__SIZEOF_SIZE_T__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIZEOF_SIZE_T__.cpp" + }, + { + "match": "\\b__SIZEOF_WCHAR_T__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIZEOF_WCHAR_T__.cpp" + }, + { + "match": "\\b__SIZEOF_WINT_T__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIZEOF_WINT_T__.cpp" + }, + { + "match": "\\b__SIZEOF_PTRDIFF_T__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SIZEOF_PTRDIFF_T__.cpp" + }, + { + "match": "\\b__BYTE_ORDER__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__BYTE_ORDER__.cpp" + }, + { + "match": "\\b__ORDER_LITTLE_ENDIAN__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__ORDER_LITTLE_ENDIAN__.cpp" + }, + { + "match": "\\b__ORDER_BIG_ENDIAN__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__ORDER_BIG_ENDIAN__.cpp" + }, + { + "match": "\\b__ORDER_PDP_ENDIAN__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__ORDER_PDP_ENDIAN__.cpp" + }, + { + "match": "\\b__FLOAT_WORD_ORDER__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__FLOAT_WORD_ORDER__.cpp" + }, + { + "match": "\\b__DEPRECATED\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__DEPRECATED.cpp" + }, + { + "match": "\\b__EXCEPTIONS\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__EXCEPTIONS.cpp" + }, + { + "match": "\\b__GXX_RTTI\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GXX_RTTI.cpp" + }, + { + "match": "\\b__USING_SJLJ_EXCEPTIONS__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__USING_SJLJ_EXCEPTIONS__.cpp" + }, + { + "match": "\\b__GXX_EXPERIMENTAL_CXX0X__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GXX_EXPERIMENTAL_CXX0X__.cpp" + }, + { + "match": "\\b__GXX_WEAK__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GXX_WEAK__.cpp" + }, + { + "match": "\\b__NEXT_RUNTIME__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__NEXT_RUNTIME__.cpp" + }, + { + "match": "\\b__LP64__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__LP64__.cpp" + }, + { + "match": "\\b_LP64\\b", + "name": "entity.name.other.preprocessor.macro.predefined._LP64.cpp" + }, + { + "match": "\\b__SSP__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SSP__.cpp" + }, + { + "match": "\\b__SSP_ALL__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SSP_ALL__.cpp" + }, + { + "match": "\\b__SSP_STRONG__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SSP_STRONG__.cpp" + }, + { + "match": "\\b__SSP_EXPLICIT__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SSP_EXPLICIT__.cpp" + }, + { + "match": "\\b__SANITIZE_ADDRESS__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SANITIZE_ADDRESS__.cpp" + }, + { + "match": "\\b__SANITIZE_THREAD__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__SANITIZE_THREAD__.cpp" + }, + { + "match": "\\b__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1.cpp" + }, + { + "match": "\\b__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2.cpp" + }, + { + "match": "\\b__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4.cpp" + }, + { + "match": "\\b__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8.cpp" + }, + { + "match": "\\b__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16.cpp" + }, + { + "match": "\\b__HAVE_SPECULATION_SAFE_VALUE\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__HAVE_SPECULATION_SAFE_VALUE.cpp" + }, + { + "match": "\\b__GCC_HAVE_DWARF2_CFI_ASM\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GCC_HAVE_DWARF2_CFI_ASM.cpp" + }, + { + "match": "\\b__FP_FAST_FMA\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__FP_FAST_FMA.cpp" + }, + { + "match": "\\b__FP_FAST_FMAF\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__FP_FAST_FMAF.cpp" + }, + { + "match": "\\b__FP_FAST_FMAL\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__FP_FAST_FMAL.cpp" + }, + { + "match": "\\b__FP_FAST_FMAF16\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__FP_FAST_FMAF16.cpp" + }, + { + "match": "\\b__FP_FAST_FMAF32\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__FP_FAST_FMAF32.cpp" + }, + { + "match": "\\b__FP_FAST_FMAF64\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__FP_FAST_FMAF64.cpp" + }, + { + "match": "\\b__FP_FAST_FMAF128\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__FP_FAST_FMAF128.cpp" + }, + { + "match": "\\b__FP_FAST_FMAF32X\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__FP_FAST_FMAF32X.cpp" + }, + { + "match": "\\b__FP_FAST_FMAF64X\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__FP_FAST_FMAF64X.cpp" + }, + { + "match": "\\b__FP_FAST_FMAF128X\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__FP_FAST_FMAF128X.cpp" + }, + { + "match": "\\b__GCC_IEC_559\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GCC_IEC_559.cpp" + }, + { + "match": "\\b__GCC_IEC_559_COMPLEX\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__GCC_IEC_559_COMPLEX.cpp" + }, + { + "match": "\\b__NO_MATH_ERRNO__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__NO_MATH_ERRNO__.cpp" + }, + { + "match": "\\b__has_builtin\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__has_builtin.cpp" + }, + { + "match": "\\b__has_feature\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__has_feature.cpp" + }, + { + "match": "\\b__has_extension\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__has_extension.cpp" + }, + { + "match": "\\b__has_cpp_attribute\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__has_cpp_attribute.cpp" + }, + { + "match": "\\b__has_c_attribute\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__has_c_attribute.cpp" + }, + { + "match": "\\b__has_attribute\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__has_attribute.cpp" + }, + { + "match": "\\b__has_declspec_attribute\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__has_declspec_attribute.cpp" + }, + { + "match": "\\b__is_identifier\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__is_identifier.cpp" + }, + { + "match": "\\b__has_include\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__has_include.cpp" + }, + { + "match": "\\b__has_include_next\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__has_include_next.cpp" + }, + { + "match": "\\b__has_warning\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__has_warning.cpp" + }, + { + "match": "\\b__BASE_FILE__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__BASE_FILE__.cpp" + }, + { + "match": "\\b__FILE_NAME__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__FILE_NAME__.cpp" + }, + { + "match": "\\b__clang__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__clang__.cpp" + }, + { + "match": "\\b__clang_major__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__clang_major__.cpp" + }, + { + "match": "\\b__clang_minor__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__clang_minor__.cpp" + }, + { + "match": "\\b__clang_patchlevel__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__clang_patchlevel__.cpp" + }, + { + "match": "\\b__clang_version__\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__clang_version__.cpp" + }, + { + "match": "\\b__fp16\\b", + "name": "entity.name.other.preprocessor.macro.predefined.__fp16.cpp" + }, + { + "match": "\\b_Float16\\b", + "name": "entity.name.other.preprocessor.macro.predefined._Float16.cpp" + }, + { + "match": "(\\b__([A-Z_])__\\b)", + "captures": { + "1": { + "name": "entity.name.other.preprocessor.macro.predefined.probably.$2.cpp" + } + } + } + ] + }, + "function_definition": { + "name": "meta.function.definition.cpp", + "begin": "((?:(?:^|\\G|(?<=;|\\}))|(?<=>))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?(?:((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+((?]*|[^>]*+<[^>]*+>)++>\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:not|compl|sizeof|new|delete|not_eq|bitand|xor|bitor|and|or|throw|and_eq|xor_eq|or_eq|alignof|alignas|typeid|noexcept|noexcept|static_cast|dynamic_cast|const_cast|reinterpret_cast|while|for|do|if|else|goto|switch|try|catch|return|break|case|continue|default|NULL|true|false|nullptr|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|final|override|volatile|const|noexcept|constexpr|mutable|constexpr|consteval|private|protected|public|if|elif|else|endif|ifdef|ifndef|define|undef|include|line|error|warning|pragma|_Pragma|defined|__has_include|__has_cpp_attribute|this|template|namespace|using|operator|typedef|decltype|typename|asm|__asm__|concept|requires|export|thread_local|atomic_cancel|atomic_commit|atomic_noexcept|co_await|co_return|co_yield|import|module|reflexpr|synchronized|audit|axiom|transaction_safe|transaction_safe_dynamic)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\())", + "beginCaptures": { + "1": { + "name": "meta.head.function.definition.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "name": "storage.type.template.cpp" + }, + "7": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "8": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "9": { + "name": "comment.block.cpp" + }, + "10": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "11": { + "name": "storage.modifier.$11.cpp" + }, + "12": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "13": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "14": { + "name": "comment.block.cpp" + }, + "15": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "16": { + "name": "meta.qualified_type.cpp", + "patterns": [ + { + "match": "(?:class|struct|union|enum)", + "name": "storage.type.$0.cpp" + }, + { + "include": "#attributes_context" + }, + { + "include": "#function_type" + }, + { + "include": "#storage_types" + }, + { + "include": "#number_literal" + }, + { + "include": "#string_context_c" + }, + { + "include": "#comma" + }, + { + "include": "#scope_resolution_inner_generated" + }, + { + "include": "#template_call_range" + }, + { + "match": "(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*", + "name": "entity.name.type.cpp" + } + ] + }, + "17": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "18": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "19": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "20": { + "name": "comment.block.cpp" + }, + "21": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "22": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "23": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "24": { + "name": "comment.block.cpp" + }, + "25": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "27": { + "patterns": [ + { + "include": "#scope_resolution_inner_generated" + } + ] + }, + "28": { + "name": "entity.name.scope-resolution.cpp" + }, + "29": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "30": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp" + }, + "31": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "32": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "33": { + "name": "comment.block.cpp" + }, + "34": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "35": { + "name": "entity.name.type.cpp" + }, + "36": { + "patterns": [ + { + "match": "\\*", + "name": "storage.modifier.pointer.cpp" + }, + { + "match": "(?:\\&((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))){2,}\\&", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "name": "invalid.illegal.reference-type.cpp" + }, + { + "match": "\\&", + "name": "storage.modifier.reference.cpp" + } + ] + }, + "37": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "38": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "39": { + "name": "comment.block.cpp" + }, + "40": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "41": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "42": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "43": { + "name": "comment.block.cpp" + }, + "44": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "45": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "46": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "47": { + "name": "comment.block.cpp" + }, + "48": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "49": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "50": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "51": { + "name": "comment.block.cpp" + }, + "52": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "53": { + "name": "storage.type.modifier.calling-convention.cpp" + }, + "54": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "55": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "56": { + "name": "comment.block.cpp" + }, + "57": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "58": { + "patterns": [ + { + "include": "#scope_resolution_function_definition_inner_generated" + } + ] + }, + "59": { + "name": "entity.name.function.definition.cpp" + }, + "60": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "61": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "62": { + "name": "comment.block.cpp" + }, + "63": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))", + "patterns": [ + { + "name": "meta.head.function.definition.cpp", + "begin": "\\G ?", + "end": "((?:\\{|<%|\\?\\?<|(?=;)))", + "endCaptures": { + "1": { + "name": "punctuation.section.block.begin.bracket.curly.function.definition.cpp" + } + }, + "patterns": [ + { + "include": "#ever_present_context" + }, + { + "contentName": "meta.function.definition.parameters.cpp", + "begin": "(\\()", + "beginCaptures": { + "1": { + "name": "punctuation.section.parameters.begin.bracket.round.cpp" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.parameters.end.bracket.round.cpp" + } + }, + "patterns": [ + { + "include": "#ever_present_context" + }, + { + "include": "#parameter_or_maybe_value" + }, + { + "include": "#comma" + }, + { + "include": "#evaluation_context" + } + ] + }, + { + "include": "$base" + } + ] + }, + { + "name": "meta.body.function.definition.cpp", + "begin": "(?<=\\{|<%|\\?\\?<)", + "end": "(\\}|%>|\\?\\?>)", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.function.definition.cpp" + } + }, + "patterns": [ + { + "include": "#function_body_context" + } + ] + }, + { + "name": "meta.tail.function.definition.cpp", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "include": "$base" + } + ] + } + ] + }, + "operator_overload": { + "name": "meta.function.definition.special.operator-overload.cpp", + "begin": "((?:(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+((?]*|[^>]*+<[^>]*+>)++>\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:not|compl|sizeof|new|delete|not_eq|bitand|xor|bitor|and|or|throw|and_eq|xor_eq|or_eq|alignof|alignas|typeid|noexcept|noexcept|static_cast|dynamic_cast|const_cast|reinterpret_cast|while|for|do|if|else|goto|switch|try|catch|return|break|case|continue|default|NULL|true|false|nullptr|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|final|override|volatile|const|noexcept|constexpr|mutable|constexpr|consteval|private|protected|public|if|elif|else|endif|ifdef|ifndef|define|undef|include|line|error|warning|pragma|_Pragma|defined|__has_include|__has_cpp_attribute|this|template|namespace|using|operator|typedef|decltype|typename|asm|__asm__|concept|requires|export|thread_local|atomic_cancel|atomic_commit|atomic_noexcept|co_await|co_return|co_yield|import|module|reflexpr|synchronized|audit|axiom|transaction_safe|transaction_safe_dynamic)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*)(operator)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*)(?:(?:((?:\\+\\+|\\-\\-|\\(\\)|\\[\\]|\\->|\\+\\+|\\-\\-|\\+|\\-|!|~|\\*|&|new|new\\[\\]|delete|delete\\[\\]|\\->\\*|\\*|\\/|%|\\+|\\-|<<|>>|<=>|<|<=|>|>=|==|!=|&|\\^|\\||&&|\\|\\||=|\\+=|\\-=|\\*=|\\/=|%=|<<=|>>=|&=|\\^=|\\|=|,))|((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:\\[\\])?)))|(\"\")((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\<|\\())", + "beginCaptures": { + "1": { + "name": "meta.head.function.definition.special.operator-overload.cpp" + }, + "2": { + "name": "meta.qualified_type.cpp", + "patterns": [ + { + "match": "(?:class|struct|union|enum)", + "name": "storage.type.$0.cpp" + }, + { + "include": "#attributes_context" + }, + { + "include": "#function_type" + }, + { + "include": "#storage_types" + }, + { + "include": "#number_literal" + }, + { + "include": "#string_context_c" + }, + { + "include": "#comma" + }, + { + "include": "#scope_resolution_inner_generated" + }, + { + "include": "#template_call_range" + }, + { + "match": "(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*", + "name": "entity.name.type.cpp" + } + ] + }, + "3": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "4": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "5": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "6": { + "name": "comment.block.cpp" + }, + "7": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "8": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "9": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "10": { + "name": "comment.block.cpp" + }, + "11": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "13": { + "patterns": [ + { + "include": "#scope_resolution_inner_generated" + } + ] + }, + "14": { + "name": "entity.name.scope-resolution.cpp" + }, + "15": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "16": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp" + }, + "17": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "18": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "19": { + "name": "comment.block.cpp" + }, + "20": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "21": { + "name": "entity.name.type.cpp" + }, + "22": { + "patterns": [ + { + "match": "\\*", + "name": "storage.modifier.pointer.cpp" + }, + { + "match": "(?:\\&((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))){2,}\\&", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "name": "invalid.illegal.reference-type.cpp" + }, + { + "match": "\\&", + "name": "storage.modifier.reference.cpp" + } + ] + }, + "23": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "24": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "25": { + "name": "comment.block.cpp" + }, + "26": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "27": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "28": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "29": { + "name": "comment.block.cpp" + }, + "30": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "31": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "32": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "33": { + "name": "comment.block.cpp" + }, + "34": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "35": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "36": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "37": { + "name": "comment.block.cpp" + }, + "38": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "39": { + "name": "storage.type.modifier.calling-convention.cpp" + }, + "40": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "41": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "42": { + "name": "comment.block.cpp" + }, + "43": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "44": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "45": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "46": { + "name": "comment.block.cpp" + }, + "47": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "48": { + "patterns": [ + { + "match": "::", + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.operator.cpp" + }, + { + "match": "(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))){2,}\\&", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "name": "invalid.illegal.reference-type.cpp" + }, + { + "match": "\\&", + "name": "entity.name.operator.type.reference.cpp" + } + ] + }, + "58": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "59": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "60": { + "name": "comment.block.cpp" + }, + "61": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "62": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "63": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "64": { + "name": "comment.block.cpp" + }, + "65": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "66": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "67": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "68": { + "name": "comment.block.cpp" + }, + "69": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "70": { + "name": "entity.name.operator.type.array.cpp" + }, + "71": { + "name": "entity.name.operator.custom-literal.cpp" + }, + "72": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "73": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "74": { + "name": "comment.block.cpp" + }, + "75": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "76": { + "name": "entity.name.operator.custom-literal.cpp" + }, + "77": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "78": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "79": { + "name": "comment.block.cpp" + }, + "80": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))", + "patterns": [ + { + "name": "meta.head.function.definition.special.operator-overload.cpp", + "begin": "\\G ?", + "end": "((?:\\{|<%|\\?\\?<|(?=;)))", + "endCaptures": { + "1": { + "name": "punctuation.section.block.begin.bracket.curly.function.definition.special.operator-overload.cpp" + } + }, + "patterns": [ + { + "include": "#ever_present_context" + }, + { + "include": "#template_call_range" + }, + { + "contentName": "meta.function.definition.parameters.special.operator-overload.cpp", + "begin": "(\\()", + "beginCaptures": { + "1": { + "name": "punctuation.section.parameters.begin.bracket.round.special.operator-overload.cpp" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.parameters.end.bracket.round.special.operator-overload.cpp" + } + }, + "patterns": [ + { + "include": "#function_parameter_context" + }, + { + "include": "#evaluation_context" + } + ] + }, + { + "include": "$base" + } + ] + }, + { + "name": "meta.body.function.definition.special.operator-overload.cpp", + "begin": "(?<=\\{|<%|\\?\\?<)", + "end": "(\\}|%>|\\?\\?>)", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.function.definition.special.operator-overload.cpp" + } + }, + "patterns": [ + { + "include": "#function_body_context" + } + ] + }, + { + "name": "meta.tail.function.definition.special.operator-overload.cpp", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "include": "$base" + } + ] + } + ] + }, + "static_assert": { + "begin": "((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()", + "beginCaptures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "5": { + "name": "keyword.other.static_assert.cpp" + }, + "6": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "7": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "8": { + "name": "comment.block.cpp" + }, + "9": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "10": { + "name": "punctuation.section.arguments.begin.bracket.round.static_assert.cpp" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.arguments.end.bracket.round.static_assert.cpp" + } + }, + "patterns": [ + { + "name": "meta.static_assert.message.cpp", + "begin": "(,)\\s*(?=(?:L|u8|u|U\\s*\\\")?)", + "beginCaptures": { + "1": { + "name": "punctuation.separator.delimiter.comma.cpp" + } + }, + "end": "(?=\\))", + "patterns": [ + { + "include": "#string_context" + }, + { + "include": "#string_context_c" + } + ] + }, + { + "include": "#evaluation_context" + } + ] + }, + "function_call": { + "begin": "((?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?]*|[^>]*+<[^>]*+>)++>\\s*)?(\\()", + "beginCaptures": { + "1": { + "patterns": [ + { + "include": "#scope_resolution_function_call_inner_generated" + } + ] + }, + "2": { + "name": "entity.name.function.call.cpp" + }, + "3": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "4": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "5": { + "name": "comment.block.cpp" + }, + "6": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "7": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "8": { + "name": "punctuation.section.arguments.begin.bracket.round.function.call.cpp" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.arguments.end.bracket.round.function.call.cpp" + } + }, + "patterns": [ + { + "include": "#evaluation_context" + } + ] + }, + "curly_initializer": { + "name": "meta.initialization.cpp", + "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+((?]*|[^>]*+<[^>]*+>)++>\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:not|compl|sizeof|new|delete|not_eq|bitand|xor|bitor|and|or|throw|and_eq|xor_eq|or_eq|alignof|alignas|typeid|noexcept|noexcept|static_cast|dynamic_cast|const_cast|reinterpret_cast|while|for|do|if|else|goto|switch|try|catch|return|break|case|continue|default|NULL|true|false|nullptr|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|final|override|volatile|const|noexcept|constexpr|mutable|constexpr|consteval|private|protected|public|if|elif|else|endif|ifdef|ifndef|define|undef|include|line|error|warning|pragma|_Pragma|defined|__has_include|__has_cpp_attribute|this|template|namespace|using|operator|typedef|decltype|typename|asm|__asm__|concept|requires|export|thread_local|atomic_cancel|atomic_commit|atomic_noexcept|co_await|co_return|co_yield|import|module|reflexpr|synchronized|audit|axiom|transaction_safe|transaction_safe_dynamic)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?![\\w<:.]))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\{)", + "beginCaptures": { + "1": { + "name": "meta.qualified_type.cpp", + "patterns": [ + { + "match": "(?:class|struct|union|enum)", + "name": "storage.type.$0.cpp" + }, + { + "include": "#attributes_context" + }, + { + "include": "#function_type" + }, + { + "include": "#storage_types" + }, + { + "include": "#number_literal" + }, + { + "include": "#string_context_c" + }, + { + "include": "#comma" + }, + { + "include": "#scope_resolution_inner_generated" + }, + { + "include": "#template_call_range" + }, + { + "match": "(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*", + "name": "entity.name.type.cpp" + } + ] + }, + "2": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "3": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "4": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "5": { + "name": "comment.block.cpp" + }, + "6": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "7": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "8": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "9": { + "name": "comment.block.cpp" + }, + "10": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "12": { + "patterns": [ + { + "include": "#scope_resolution_inner_generated" + } + ] + }, + "13": { + "name": "entity.name.scope-resolution.cpp" + }, + "14": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "15": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp" + }, + "16": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "17": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "18": { + "name": "comment.block.cpp" + }, + "19": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "20": { + "name": "entity.name.type.cpp" + }, + "21": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "22": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "23": { + "name": "comment.block.cpp" + }, + "24": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "25": { + "name": "punctuation.section.arguments.begin.bracket.curly.initializer.cpp" + } + }, + "end": "(\\})", + "endCaptures": { + "1": { + "name": "punctuation.section.arguments.end.bracket.curly.initializer.cpp" + } + }, + "patterns": [ + { + "include": "#evaluation_context" + }, + { + "include": "#comma" + } + ] + }, + "builtin_storage_type_initilizer": { + "begin": "((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()", + "beginCaptures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "5": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "6": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "7": { + "name": "comment.block.cpp" + }, + "8": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "9": { + "name": "storage.type.primitive.cpp storage.type.built-in.primitive.cpp" + }, + "10": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "11": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "12": { + "name": "comment.block.cpp" + }, + "13": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "14": { + "name": "storage.type.cpp storage.type.built-in.cpp" + }, + "15": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "16": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "17": { + "name": "comment.block.cpp" + }, + "18": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "19": { + "name": "support.type.posix-reserved.pthread.cpp support.type.built-in.posix-reserved.pthread.cpp" + }, + "20": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "21": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "22": { + "name": "comment.block.cpp" + }, + "23": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "24": { + "name": "support.type.posix-reserved.cpp support.type.built-in.posix-reserved.cpp" + }, + "25": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "26": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "27": { + "name": "comment.block.cpp" + }, + "28": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "29": { + "name": "punctuation.section.arguments.begin.bracket.round.initializer.cpp" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.arguments.end.bracket.round.initializer.cpp" + } + }, + "patterns": [ + { + "include": "#evaluation_context" + } + ] + }, + "constructor_inline": { + "name": "meta.function.definition.special.constructor.cpp", + "begin": "(^((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?:inline|constexpr|mutable|friend|explicit|virtual)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?|\\?\\?>)|(?=[;>\\[\\]=]))", + "patterns": [ + { + "name": "meta.head.function.definition.special.constructor.cpp", + "begin": "\\G ?", + "end": "((?:\\{|<%|\\?\\?<|(?=;)))", + "endCaptures": { + "1": { + "name": "punctuation.section.block.begin.bracket.curly.function.definition.special.constructor.cpp" + } + }, + "patterns": [ + { + "include": "#ever_present_context" + }, + { + "patterns": [ + { + "match": "(\\=)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(default)|(delete))", + "captures": { + "1": { + "name": "keyword.operator.assignment.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "name": "keyword.other.default.constructor.cpp" + }, + "7": { + "name": "keyword.other.delete.constructor.cpp" + } + } + } + ] + }, + { + "include": "#functional_specifiers_pre_parameters" + }, + { + "begin": "(:)", + "beginCaptures": { + "1": { + "name": "punctuation.separator.initializers.cpp" + } + }, + "end": "(?=\\{)", + "patterns": [ + { + "contentName": "meta.parameter.initialization.cpp", + "begin": "((?|\\?\\?>)", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.function.definition.special.constructor.cpp" + } + }, + "patterns": [ + { + "include": "#function_body_context" + } + ] + }, + { + "name": "meta.tail.function.definition.special.constructor.cpp", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "include": "$base" + } + ] + } + ] + }, + "constructor_root": { + "name": "meta.function.definition.special.constructor.cpp", + "begin": "(\\s*+((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*)(((?>(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))::((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\13((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\()))", + "beginCaptures": { + "1": { + "name": "meta.head.function.definition.special.constructor.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "name": "storage.type.modifier.calling-convention.cpp" + }, + "7": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "8": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "9": { + "name": "comment.block.cpp" + }, + "10": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "11": { + "patterns": [ + { + "match": "::", + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.constructor.cpp" + }, + { + "match": "(?|\\?\\?>)|(?=[;>\\[\\]=]))", + "patterns": [ + { + "name": "meta.head.function.definition.special.constructor.cpp", + "begin": "\\G ?", + "end": "((?:\\{|<%|\\?\\?<|(?=;)))", + "endCaptures": { + "1": { + "name": "punctuation.section.block.begin.bracket.curly.function.definition.special.constructor.cpp" + } + }, + "patterns": [ + { + "include": "#ever_present_context" + }, + { + "patterns": [ + { + "match": "(\\=)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(default)|(delete))", + "captures": { + "1": { + "name": "keyword.operator.assignment.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "name": "keyword.other.default.constructor.cpp" + }, + "7": { + "name": "keyword.other.delete.constructor.cpp" + } + } + } + ] + }, + { + "include": "#functional_specifiers_pre_parameters" + }, + { + "begin": "(:)", + "beginCaptures": { + "1": { + "name": "punctuation.separator.initializers.cpp" + } + }, + "end": "(?=\\{)", + "patterns": [ + { + "contentName": "meta.parameter.initialization.cpp", + "begin": "((?|\\?\\?>)", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.function.definition.special.constructor.cpp" + } + }, + "patterns": [ + { + "include": "#function_body_context" + } + ] + }, + { + "name": "meta.tail.function.definition.special.constructor.cpp", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "include": "$base" + } + ] + } + ] + }, + "destructor_inline": { + "name": "meta.function.definition.special.member.destructor.cpp", + "begin": "(^((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?:inline|constexpr|mutable|friend|explicit|virtual)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*)(~(?|\\?\\?>)|(?=[;>\\[\\]=]))", + "patterns": [ + { + "name": "meta.head.function.definition.special.member.destructor.cpp", + "begin": "\\G ?", + "end": "((?:\\{|<%|\\?\\?<|(?=;)))", + "endCaptures": { + "1": { + "name": "punctuation.section.block.begin.bracket.curly.function.definition.special.member.destructor.cpp" + } + }, + "patterns": [ + { + "include": "#ever_present_context" + }, + { + "patterns": [ + { + "match": "(\\=)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(default)|(delete))", + "captures": { + "1": { + "name": "keyword.operator.assignment.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "name": "keyword.other.default.constructor.cpp" + }, + "7": { + "name": "keyword.other.delete.constructor.cpp" + } + } + } + ] + }, + { + "contentName": "meta.function.definition.parameters.special.member.destructor.cpp", + "begin": "(\\()", + "beginCaptures": { + "1": { + "name": "punctuation.section.parameters.begin.bracket.round.special.member.destructor.cpp" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.parameters.end.bracket.round.special.member.destructor.cpp" + } + } + }, + { + "include": "$base" + } + ] + }, + { + "name": "meta.body.function.definition.special.member.destructor.cpp", + "begin": "(?<=\\{|<%|\\?\\?<)", + "end": "(\\}|%>|\\?\\?>)", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.function.definition.special.member.destructor.cpp" + } + }, + "patterns": [ + { + "include": "#function_body_context" + } + ] + }, + { + "name": "meta.tail.function.definition.special.member.destructor.cpp", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "include": "$base" + } + ] + } + ] + }, + "destructor_root": { + "name": "meta.function.definition.special.member.destructor.cpp", + "begin": "(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*)(((?>(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))::((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))~\\13((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\()))", + "beginCaptures": { + "1": { + "name": "meta.head.function.definition.special.member.destructor.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "name": "storage.type.modifier.calling-convention.cpp" + }, + "7": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "8": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "9": { + "name": "comment.block.cpp" + }, + "10": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "11": { + "patterns": [ + { + "match": "::", + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.destructor.cpp" + }, + { + "match": "(?|\\?\\?>)|(?=[;>\\[\\]=]))", + "patterns": [ + { + "name": "meta.head.function.definition.special.member.destructor.cpp", + "begin": "\\G ?", + "end": "((?:\\{|<%|\\?\\?<|(?=;)))", + "endCaptures": { + "1": { + "name": "punctuation.section.block.begin.bracket.curly.function.definition.special.member.destructor.cpp" + } + }, + "patterns": [ + { + "include": "#ever_present_context" + }, + { + "patterns": [ + { + "match": "(\\=)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(default)|(delete))", + "captures": { + "1": { + "name": "keyword.operator.assignment.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "name": "keyword.other.default.constructor.cpp" + }, + "7": { + "name": "keyword.other.delete.constructor.cpp" + } + } + } + ] + }, + { + "contentName": "meta.function.definition.parameters.special.member.destructor.cpp", + "begin": "(\\()", + "beginCaptures": { + "1": { + "name": "punctuation.section.parameters.begin.bracket.round.special.member.destructor.cpp" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.parameters.end.bracket.round.special.member.destructor.cpp" + } + } + }, + { + "include": "$base" + } + ] + }, + { + "name": "meta.body.function.definition.special.member.destructor.cpp", + "begin": "(?<=\\{|<%|\\?\\?<)", + "end": "(\\}|%>|\\?\\?>)", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.function.definition.special.member.destructor.cpp" + } + }, + "patterns": [ + { + "include": "#function_body_context" + } + ] + }, + { + "name": "meta.tail.function.definition.special.member.destructor.cpp", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "include": "$base" + } + ] + } + ] + }, + "operators": { + "patterns": [ + { + "include": "#sizeof_operator" + }, + { + "include": "#alignof_operator" + }, + { + "include": "#alignas_operator" + }, + { + "include": "#typeid_operator" + }, + { + "include": "#noexcept_operator" + }, + { + "match": "--", + "name": "keyword.operator.decrement.cpp" + }, + { + "match": "\\+\\+", + "name": "keyword.operator.increment.cpp" + }, + { + "match": "%=|\\+=|-=|\\*=|(?>=|\\|=", + "name": "keyword.operator.assignment.compound.bitwise.cpp" + }, + { + "match": "<<|>>", + "name": "keyword.operator.bitwise.shift.cpp" + }, + { + "match": "!=|<=|>=|==|<|>", + "name": "keyword.operator.comparison.cpp" + }, + { + "match": "&&|!|\\|\\|", + "name": "keyword.operator.logical.cpp" + }, + { + "match": "&|\\||\\^|~", + "name": "keyword.operator.cpp" + }, + { + "include": "#assignment_operator" + }, + { + "match": "%|\\*|\\/|-|\\+", + "name": "keyword.operator.cpp" + }, + { + "include": "#ternary_operator" + } + ] + }, + "wordlike_operators": { + "match": "(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()", + "beginCaptures": { + "1": { + "name": "keyword.operator.functionlike.cpp keyword.operator.sizeof.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "name": "punctuation.section.arguments.begin.bracket.round.operator.sizeof.cpp" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.arguments.end.bracket.round.operator.sizeof.cpp" + } + }, + "patterns": [ + { + "include": "#evaluation_context" + } + ] + }, + "alignof_operator": { + "contentName": "meta.arguments.operator.alignof.cpp", + "begin": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()", + "beginCaptures": { + "1": { + "name": "keyword.operator.functionlike.cpp keyword.operator.alignof.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "name": "punctuation.section.arguments.begin.bracket.round.operator.alignof.cpp" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.arguments.end.bracket.round.operator.alignof.cpp" + } + }, + "patterns": [ + { + "include": "#evaluation_context" + } + ] + }, + "alignas_operator": { + "contentName": "meta.arguments.operator.alignas.cpp", + "begin": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()", + "beginCaptures": { + "1": { + "name": "keyword.operator.functionlike.cpp keyword.operator.alignas.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "name": "punctuation.section.arguments.begin.bracket.round.operator.alignas.cpp" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.arguments.end.bracket.round.operator.alignas.cpp" + } + }, + "patterns": [ + { + "include": "#evaluation_context" + } + ] + }, + "typeid_operator": { + "contentName": "meta.arguments.operator.typeid.cpp", + "begin": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()", + "beginCaptures": { + "1": { + "name": "keyword.operator.functionlike.cpp keyword.operator.typeid.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "name": "punctuation.section.arguments.begin.bracket.round.operator.typeid.cpp" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.arguments.end.bracket.round.operator.typeid.cpp" + } + }, + "patterns": [ + { + "include": "#evaluation_context" + } + ] + }, + "noexcept_operator": { + "contentName": "meta.arguments.operator.noexcept.cpp", + "begin": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()", + "beginCaptures": { + "1": { + "name": "keyword.operator.functionlike.cpp keyword.operator.noexcept.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "name": "punctuation.section.arguments.begin.bracket.round.operator.noexcept.cpp" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.arguments.end.bracket.round.operator.noexcept.cpp" + } + }, + "patterns": [ + { + "include": "#evaluation_context" + } + ] + }, + "ternary_operator": { + "applyEndPatternLast": true, + "begin": "(\\?)", + "beginCaptures": { + "1": { + "name": "keyword.operator.ternary.cpp" + } + }, + "end": "(:)", + "endCaptures": { + "1": { + "name": "keyword.operator.ternary.cpp" + } + }, + "patterns": [ + { + "include": "#ever_present_context" + }, + { + "include": "#string_context" + }, + { + "include": "#number_literal" + }, + { + "include": "#string_context_c" + }, + { + "include": "#method_access" + }, + { + "include": "#member_access" + }, + { + "include": "#predefined_macros" + }, + { + "include": "#operators" + }, + { + "include": "#memory_operators" + }, + { + "include": "#wordlike_operators" + }, + { + "include": "#type_casting_operators" + }, + { + "include": "#control_flow_keywords" + }, + { + "include": "#exception_keywords" + }, + { + "include": "#the_this_keyword" + }, + { + "include": "#language_constants" + }, + { + "include": "#builtin_storage_type_initilizer" + }, + { + "include": "#qualifiers_and_specifiers_post_parameters" + }, + { + "include": "#functional_specifiers_pre_parameters" + }, + { + "include": "#storage_types" + }, + { + "include": "#misc_storage_modifiers" + }, + { + "include": "#lambdas" + }, + { + "include": "#attributes_context" + }, + { + "include": "#parentheses" + }, + { + "include": "#function_call" + }, + { + "include": "#scope_resolution_inner_generated" + }, + { + "include": "#square_brackets" + }, + { + "include": "#empty_square_brackets" + }, + { + "include": "#semicolon" + }, + { + "include": "#comma" + } + ] + }, + "function_pointer": { + "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+((?]*|[^>]*+<[^>]*+>)++>\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:not|compl|sizeof|new|delete|not_eq|bitand|xor|bitor|and|or|throw|and_eq|xor_eq|or_eq|alignof|alignas|typeid|noexcept|noexcept|static_cast|dynamic_cast|const_cast|reinterpret_cast|while|for|do|if|else|goto|switch|try|catch|return|break|case|continue|default|NULL|true|false|nullptr|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|final|override|volatile|const|noexcept|constexpr|mutable|constexpr|consteval|private|protected|public|if|elif|else|endif|ifdef|ifndef|define|undef|include|line|error|warning|pragma|_Pragma|defined|__has_include|__has_cpp_attribute|this|template|namespace|using|operator|typedef|decltype|typename|asm|__asm__|concept|requires|export|thread_local|atomic_cancel|atomic_commit|atomic_noexcept|co_await|co_return|co_yield|import|module|reflexpr|synchronized|audit|axiom|transaction_safe|transaction_safe_dynamic)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()(\\*)\\s*((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)?)\\s*(?:(\\[)(\\w*)(\\])\\s*)*(\\))\\s*(\\()", + "beginCaptures": { + "1": { + "name": "meta.qualified_type.cpp", + "patterns": [ + { + "match": "(?:class|struct|union|enum)", + "name": "storage.type.$0.cpp" + }, + { + "include": "#attributes_context" + }, + { + "include": "#function_type" + }, + { + "include": "#storage_types" + }, + { + "include": "#number_literal" + }, + { + "include": "#string_context_c" + }, + { + "include": "#comma" + }, + { + "include": "#scope_resolution_inner_generated" + }, + { + "include": "#template_call_range" + }, + { + "match": "(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*", + "name": "entity.name.type.cpp" + } + ] + }, + "2": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "3": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "4": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "5": { + "name": "comment.block.cpp" + }, + "6": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "7": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "8": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "9": { + "name": "comment.block.cpp" + }, + "10": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "12": { + "patterns": [ + { + "include": "#scope_resolution_inner_generated" + } + ] + }, + "13": { + "name": "entity.name.scope-resolution.cpp" + }, + "14": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "15": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp" + }, + "16": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "17": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "18": { + "name": "comment.block.cpp" + }, + "19": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "20": { + "name": "entity.name.type.cpp" + }, + "21": { + "patterns": [ + { + "match": "\\*", + "name": "storage.modifier.pointer.cpp" + }, + { + "match": "(?:\\&((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))){2,}\\&", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "name": "invalid.illegal.reference-type.cpp" + }, + { + "match": "\\&", + "name": "storage.modifier.reference.cpp" + } + ] + }, + "22": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "23": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "24": { + "name": "comment.block.cpp" + }, + "25": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "26": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "27": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "28": { + "name": "comment.block.cpp" + }, + "29": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "30": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "31": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "32": { + "name": "comment.block.cpp" + }, + "33": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "34": { + "name": "punctuation.section.parens.begin.bracket.round.function.pointer.cpp" + }, + "35": { + "name": "punctuation.definition.function.pointer.dereference.cpp" + }, + "36": { + "name": "variable.other.definition.pointer.function.cpp" + }, + "37": { + "name": "punctuation.definition.begin.bracket.square.cpp" + }, + "38": { + "patterns": [ + { + "include": "#evaluation_context" + } + ] + }, + "39": { + "name": "punctuation.definition.end.bracket.square.cpp" + }, + "40": { + "name": "punctuation.section.parens.end.bracket.round.function.pointer.cpp" + }, + "41": { + "name": "punctuation.section.parameters.begin.bracket.round.function.pointer.cpp" + } + }, + "end": "(\\))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=[{=,);]|\\n)(?!\\()", + "endCaptures": { + "1": { + "name": "punctuation.section.parameters.end.bracket.round.function.pointer.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "patterns": [ + { + "include": "#function_parameter_context" + } + ] + }, + "function_pointer_parameter": { + "begin": "(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+((?]*|[^>]*+<[^>]*+>)++>\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:not|compl|sizeof|new|delete|not_eq|bitand|xor|bitor|and|or|throw|and_eq|xor_eq|or_eq|alignof|alignas|typeid|noexcept|noexcept|static_cast|dynamic_cast|const_cast|reinterpret_cast|while|for|do|if|else|goto|switch|try|catch|return|break|case|continue|default|NULL|true|false|nullptr|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|final|override|volatile|const|noexcept|constexpr|mutable|constexpr|consteval|private|protected|public|if|elif|else|endif|ifdef|ifndef|define|undef|include|line|error|warning|pragma|_Pragma|defined|__has_include|__has_cpp_attribute|this|template|namespace|using|operator|typedef|decltype|typename|asm|__asm__|concept|requires|export|thread_local|atomic_cancel|atomic_commit|atomic_noexcept|co_await|co_return|co_yield|import|module|reflexpr|synchronized|audit|axiom|transaction_safe|transaction_safe_dynamic)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()(\\*)\\s*((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)?)\\s*(?:(\\[)(\\w*)(\\])\\s*)*(\\))\\s*(\\()", + "beginCaptures": { + "1": { + "name": "meta.qualified_type.cpp", + "patterns": [ + { + "match": "(?:class|struct|union|enum)", + "name": "storage.type.$0.cpp" + }, + { + "include": "#attributes_context" + }, + { + "include": "#function_type" + }, + { + "include": "#storage_types" + }, + { + "include": "#number_literal" + }, + { + "include": "#string_context_c" + }, + { + "include": "#comma" + }, + { + "include": "#scope_resolution_inner_generated" + }, + { + "include": "#template_call_range" + }, + { + "match": "(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*", + "name": "entity.name.type.cpp" + } + ] + }, + "2": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "3": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "4": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "5": { + "name": "comment.block.cpp" + }, + "6": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "7": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "8": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "9": { + "name": "comment.block.cpp" + }, + "10": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "12": { + "patterns": [ + { + "include": "#scope_resolution_inner_generated" + } + ] + }, + "13": { + "name": "entity.name.scope-resolution.cpp" + }, + "14": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "15": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp" + }, + "16": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "17": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "18": { + "name": "comment.block.cpp" + }, + "19": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "20": { + "name": "entity.name.type.cpp" + }, + "21": { + "patterns": [ + { + "match": "\\*", + "name": "storage.modifier.pointer.cpp" + }, + { + "match": "(?:\\&((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))){2,}\\&", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "name": "invalid.illegal.reference-type.cpp" + }, + { + "match": "\\&", + "name": "storage.modifier.reference.cpp" + } + ] + }, + "22": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "23": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "24": { + "name": "comment.block.cpp" + }, + "25": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "26": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "27": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "28": { + "name": "comment.block.cpp" + }, + "29": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "30": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "31": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "32": { + "name": "comment.block.cpp" + }, + "33": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "34": { + "name": "punctuation.section.parens.begin.bracket.round.function.pointer.cpp" + }, + "35": { + "name": "punctuation.definition.function.pointer.dereference.cpp" + }, + "36": { + "name": "variable.parameter.pointer.function.cpp" + }, + "37": { + "name": "punctuation.definition.begin.bracket.square.cpp" + }, + "38": { + "patterns": [ + { + "include": "#evaluation_context" + } + ] + }, + "39": { + "name": "punctuation.definition.end.bracket.square.cpp" + }, + "40": { + "name": "punctuation.section.parens.end.bracket.round.function.pointer.cpp" + }, + "41": { + "name": "punctuation.section.parameters.begin.bracket.round.function.pointer.cpp" + } + }, + "end": "(\\))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=[{=,);]|\\n)(?!\\()", + "endCaptures": { + "1": { + "name": "punctuation.section.parameters.end.bracket.round.function.pointer.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "patterns": [ + { + "include": "#function_parameter_context" + } + ] + }, + "parameter_or_maybe_value": { + "name": "meta.parameter.cpp", + "begin": "((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\w)", + "beginCaptures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "end": "(?:(?=\\))|(,))", + "endCaptures": { + "1": { + "name": "punctuation.separator.delimiter.comma.cpp" + } + }, + "patterns": [ + { + "include": "#ever_present_context" + }, + { + "include": "#memory_operators" + }, + { + "include": "#builtin_storage_type_initilizer" + }, + { + "include": "#curly_initializer" + }, + { + "include": "#function_pointer_parameter" + }, + { + "include": "#decltype" + }, + { + "include": "#vararg_ellipses" + }, + { + "match": "((?:((?:const|static|volatile|register|restrict|extern))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))+)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=,|\\)|=)", + "captures": { + "1": { + "patterns": [ + { + "include": "#storage_types" + } + ] + }, + "2": { + "name": "storage.modifier.specifier.parameter.cpp" + }, + "3": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "4": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "5": { + "name": "comment.block.cpp" + }, + "6": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "7": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "8": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "9": { + "name": "comment.block.cpp" + }, + "10": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "11": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "12": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "13": { + "name": "comment.block.cpp" + }, + "14": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "15": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "16": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "17": { + "name": "comment.block.cpp" + }, + "18": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "19": { + "name": "storage.type.primitive.cpp storage.type.built-in.primitive.cpp" + }, + "20": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "21": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "22": { + "name": "comment.block.cpp" + }, + "23": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "24": { + "name": "storage.type.cpp storage.type.built-in.cpp" + }, + "25": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "26": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "27": { + "name": "comment.block.cpp" + }, + "28": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "29": { + "name": "support.type.posix-reserved.pthread.cpp support.type.built-in.posix-reserved.pthread.cpp" + }, + "30": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "31": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "32": { + "name": "comment.block.cpp" + }, + "33": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "34": { + "name": "support.type.posix-reserved.cpp support.type.built-in.posix-reserved.cpp" + }, + "35": { + "name": "entity.name.type.parameter.cpp" + }, + "36": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "37": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "38": { + "name": "comment.block.cpp" + }, + "39": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + } + }, + { + "include": "#storage_types" + }, + { + "include": "#function_call" + }, + { + "include": "#scope_resolution_parameter_inner_generated" + }, + { + "match": "(?:class|struct|union|enum)", + "name": "storage.type.$0.cpp" + }, + { + "begin": "(?<==)", + "end": "(?:(?=\\))|(,))", + "endCaptures": { + "1": { + "name": "punctuation.separator.delimiter.comma.cpp" + } + }, + "patterns": [ + { + "include": "#evaluation_context" + } + ] + }, + { + "match": "(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\)|,|\\[|=|\\n)", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "5": { + "name": "variable.parameter.cpp" + }, + "6": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "7": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "8": { + "name": "comment.block.cpp" + }, + "9": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + } + }, + { + "include": "#attributes_context" + }, + { + "name": "meta.bracket.square.array.cpp", + "begin": "(\\[)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.begin.bracket.square.array.type.cpp" + } + }, + "end": "(\\])", + "endCaptures": { + "1": { + "name": "punctuation.definition.end.bracket.square.array.type.cpp" + } + }, + "patterns": [ + { + "include": "#evaluation_context" + } + ] + }, + { + "match": "(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*)", + "captures": { + "0": { + "patterns": [ + { + "match": "\\*", + "name": "storage.modifier.pointer.cpp" + }, + { + "match": "(?:\\&((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))){2,}\\&", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "name": "invalid.illegal.reference-type.cpp" + }, + { + "match": "\\&", + "name": "storage.modifier.reference.cpp" + } + ] + }, + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "5": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "6": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "7": { + "name": "comment.block.cpp" + }, + "8": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + } + }, + { + "include": "#evaluation_context" + } + ] + }, + "parameter": { + "name": "meta.parameter.cpp", + "begin": "((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\w)", + "beginCaptures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "end": "(?:(?=\\))|(,))", + "endCaptures": { + "1": { + "name": "punctuation.separator.delimiter.comma.cpp" + } + }, + "patterns": [ + { + "include": "#ever_present_context" + }, + { + "include": "#function_pointer_parameter" + }, + { + "include": "#decltype" + }, + { + "include": "#vararg_ellipses" + }, + { + "match": "((?:((?:const|static|volatile|register|restrict|extern))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))+)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=,|\\)|=)", + "captures": { + "1": { + "patterns": [ + { + "include": "#storage_types" + } + ] + }, + "2": { + "name": "storage.modifier.specifier.parameter.cpp" + }, + "3": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "4": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "5": { + "name": "comment.block.cpp" + }, + "6": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "7": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "8": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "9": { + "name": "comment.block.cpp" + }, + "10": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "11": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "12": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "13": { + "name": "comment.block.cpp" + }, + "14": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "15": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "16": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "17": { + "name": "comment.block.cpp" + }, + "18": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "19": { + "name": "storage.type.primitive.cpp storage.type.built-in.primitive.cpp" + }, + "20": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "21": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "22": { + "name": "comment.block.cpp" + }, + "23": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "24": { + "name": "storage.type.cpp storage.type.built-in.cpp" + }, + "25": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "26": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "27": { + "name": "comment.block.cpp" + }, + "28": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "29": { + "name": "support.type.posix-reserved.pthread.cpp support.type.built-in.posix-reserved.pthread.cpp" + }, + "30": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "31": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "32": { + "name": "comment.block.cpp" + }, + "33": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "34": { + "name": "support.type.posix-reserved.cpp support.type.built-in.posix-reserved.cpp" + }, + "35": { + "name": "entity.name.type.parameter.cpp" + }, + "36": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "37": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "38": { + "name": "comment.block.cpp" + }, + "39": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + } + }, + { + "include": "#storage_types" + }, + { + "include": "#scope_resolution_parameter_inner_generated" + }, + { + "match": "(?:class|struct|union|enum)", + "name": "storage.type.$0.cpp" + }, + { + "begin": "(?<==)", + "end": "(?:(?=\\))|(,))", + "endCaptures": { + "1": { + "name": "punctuation.separator.delimiter.comma.cpp" + } + }, + "patterns": [ + { + "include": "#evaluation_context" + } + ] + }, + { + "include": "#assignment_operator" + }, + { + "match": "(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\)|,|\\[|=|\\n)", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "5": { + "name": "variable.parameter.cpp" + }, + "6": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "7": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "8": { + "name": "comment.block.cpp" + }, + "9": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + } + }, + { + "include": "#attributes_context" + }, + { + "name": "meta.bracket.square.array.cpp", + "begin": "(\\[)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.begin.bracket.square.array.type.cpp" + } + }, + "end": "(\\])", + "endCaptures": { + "1": { + "name": "punctuation.definition.end.bracket.square.array.type.cpp" + } + }, + "patterns": [ + { + "include": "#evaluation_context" + } + ] + }, + { + "match": "(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*)", + "captures": { + "0": { + "patterns": [ + { + "match": "\\*", + "name": "storage.modifier.pointer.cpp" + }, + { + "match": "(?:\\&((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))){2,}\\&", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "name": "invalid.illegal.reference-type.cpp" + }, + { + "match": "\\&", + "name": "storage.modifier.reference.cpp" + } + ] + }, + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "5": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "6": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "7": { + "name": "comment.block.cpp" + }, + "8": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + } + } + ] + }, + "member_access": { + "match": "(?:((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\*|->)))((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*(?:(?:(?:\\.\\*|\\.))|(?:(?:->\\*|->)))\\s*)*)\\s*(\\b(?!auto[^(?-mix:\\w)]|void[^(?-mix:\\w)]|char[^(?-mix:\\w)]|short[^(?-mix:\\w)]|int[^(?-mix:\\w)]|signed[^(?-mix:\\w)]|unsigned[^(?-mix:\\w)]|long[^(?-mix:\\w)]|float[^(?-mix:\\w)]|double[^(?-mix:\\w)]|bool[^(?-mix:\\w)]|wchar_t[^(?-mix:\\w)]|u_char[^(?-mix:\\w)]|u_short[^(?-mix:\\w)]|u_int[^(?-mix:\\w)]|u_long[^(?-mix:\\w)]|ushort[^(?-mix:\\w)]|uint[^(?-mix:\\w)]|u_quad_t[^(?-mix:\\w)]|quad_t[^(?-mix:\\w)]|qaddr_t[^(?-mix:\\w)]|caddr_t[^(?-mix:\\w)]|daddr_t[^(?-mix:\\w)]|div_t[^(?-mix:\\w)]|dev_t[^(?-mix:\\w)]|fixpt_t[^(?-mix:\\w)]|blkcnt_t[^(?-mix:\\w)]|blksize_t[^(?-mix:\\w)]|gid_t[^(?-mix:\\w)]|in_addr_t[^(?-mix:\\w)]|in_port_t[^(?-mix:\\w)]|ino_t[^(?-mix:\\w)]|key_t[^(?-mix:\\w)]|mode_t[^(?-mix:\\w)]|nlink_t[^(?-mix:\\w)]|id_t[^(?-mix:\\w)]|pid_t[^(?-mix:\\w)]|off_t[^(?-mix:\\w)]|segsz_t[^(?-mix:\\w)]|swblk_t[^(?-mix:\\w)]|uid_t[^(?-mix:\\w)]|id_t[^(?-mix:\\w)]|clock_t[^(?-mix:\\w)]|size_t[^(?-mix:\\w)]|ssize_t[^(?-mix:\\w)]|time_t[^(?-mix:\\w)]|useconds_t[^(?-mix:\\w)]|suseconds_t[^(?-mix:\\w)]|int8_t[^(?-mix:\\w)]|int16_t[^(?-mix:\\w)]|int32_t[^(?-mix:\\w)]|int64_t[^(?-mix:\\w)]|uint8_t[^(?-mix:\\w)]|uint16_t[^(?-mix:\\w)]|uint32_t[^(?-mix:\\w)]|uint64_t[^(?-mix:\\w)]|int_least8_t[^(?-mix:\\w)]|int_least16_t[^(?-mix:\\w)]|int_least32_t[^(?-mix:\\w)]|int_least64_t[^(?-mix:\\w)]|uint_least8_t[^(?-mix:\\w)]|uint_least16_t[^(?-mix:\\w)]|uint_least32_t[^(?-mix:\\w)]|uint_least64_t[^(?-mix:\\w)]|int_fast8_t[^(?-mix:\\w)]|int_fast16_t[^(?-mix:\\w)]|int_fast32_t[^(?-mix:\\w)]|int_fast64_t[^(?-mix:\\w)]|uint_fast8_t[^(?-mix:\\w)]|uint_fast16_t[^(?-mix:\\w)]|uint_fast32_t[^(?-mix:\\w)]|uint_fast64_t[^(?-mix:\\w)]|intptr_t[^(?-mix:\\w)]|uintptr_t[^(?-mix:\\w)]|intmax_t[^(?-mix:\\w)]|intmax_t[^(?-mix:\\w)]|uintmax_t[^(?-mix:\\w)]|uintmax_t[^(?-mix:\\w)])(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\b(?!\\())", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "5": { + "name": "variable.language.this.cpp" + }, + "6": { + "name": "variable.other.object.access.cpp" + }, + "7": { + "name": "punctuation.separator.dot-access.cpp" + }, + "8": { + "name": "punctuation.separator.pointer-access.cpp" + }, + "9": { + "patterns": [ + { + "match": "(?<=(?:\\.\\*|\\.|->|->\\*))\\s*(?:((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\*|->)))", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "5": { + "name": "variable.language.this.cpp" + }, + "6": { + "name": "variable.other.object.property.cpp" + }, + "7": { + "name": "punctuation.separator.dot-access.cpp" + }, + "8": { + "name": "punctuation.separator.pointer-access.cpp" + } + } + }, + { + "match": "(?:((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\*|->)))", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "5": { + "name": "variable.language.this.cpp" + }, + "6": { + "name": "variable.other.object.access.cpp" + }, + "7": { + "name": "punctuation.separator.dot-access.cpp" + }, + "8": { + "name": "punctuation.separator.pointer-access.cpp" + } + } + }, + { + "include": "#member_access" + }, + { + "include": "#method_access" + } + ] + }, + "10": { + "name": "variable.other.property.cpp" + } + } + }, + "method_access": { + "begin": "(?:((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\*|->)))((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*(?:(?:(?:\\.\\*|\\.))|(?:(?:->\\*|->)))\\s*)*)\\s*(~?(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*(\\()", + "beginCaptures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "5": { + "name": "variable.language.this.cpp" + }, + "6": { + "name": "variable.other.object.access.cpp" + }, + "7": { + "name": "punctuation.separator.dot-access.cpp" + }, + "8": { + "name": "punctuation.separator.pointer-access.cpp" + }, + "9": { + "patterns": [ + { + "match": "(?<=(?:\\.\\*|\\.|->|->\\*))\\s*(?:((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\*|->)))", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "5": { + "name": "variable.language.this.cpp" + }, + "6": { + "name": "variable.other.object.property.cpp" + }, + "7": { + "name": "punctuation.separator.dot-access.cpp" + }, + "8": { + "name": "punctuation.separator.pointer-access.cpp" + } + } + }, + { + "match": "(?:((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\*|->)))", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "5": { + "name": "variable.language.this.cpp" + }, + "6": { + "name": "variable.other.object.access.cpp" + }, + "7": { + "name": "punctuation.separator.dot-access.cpp" + }, + "8": { + "name": "punctuation.separator.pointer-access.cpp" + } + } + }, + { + "include": "#member_access" + }, + { + "include": "#method_access" + } + ] + }, + "10": { + "name": "entity.name.function.member.cpp" + }, + "11": { + "name": "punctuation.section.arguments.begin.bracket.round.function.member.cpp" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.arguments.end.bracket.round.function.member.cpp" + } + }, + "patterns": [ + { + "include": "#evaluation_context" + } + ] + }, + "using_namespace": { + "name": "meta.using-namespace.cpp", + "begin": "(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)?((?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)\\s*((?|\\?\\?>)|(?=[;>\\[\\]=]))", + "patterns": [ + { + "name": "meta.head.namespace.cpp", + "begin": "\\G ?", + "end": "((?:\\{|<%|\\?\\?<|(?=;)))", + "endCaptures": { + "1": { + "name": "punctuation.section.block.begin.bracket.curly.namespace.cpp" + } + }, + "patterns": [ + { + "include": "#ever_present_context" + }, + { + "include": "#attributes_context" + }, + { + "match": "((?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)\\s*((?|\\?\\?>)", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.namespace.cpp" + } + }, + "patterns": [ + { + "include": "$base" + } + ] + }, + { + "name": "meta.tail.namespace.cpp", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "include": "$base" + } + ] + } + ] + }, + "macro_argument": { + "match": "##?(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*(?!\\w)", + "name": "variable.other.macro.argument.cpp" + }, + "lambdas": { + "begin": "((?:(?<=[^\\s]|^)(?])|(?<=\\Wreturn|^return))\\s*(\\[(?!\\[))((?:[^\\]\\[]*\\[.*?\\](?!\\s*\\[)[^\\]\\[]*?)*[^\\]\\[]*?)(\\](?!\\[)))", + "beginCaptures": { + "2": { + "name": "punctuation.definition.capture.begin.lambda.cpp" + }, + "3": { + "name": "meta.lambda.capture.cpp", + "patterns": [ + { + "include": "#the_this_keyword" + }, + { + "match": "((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?=\\]|\\z|$)|(,))|(\\=))", + "captures": { + "1": { + "name": "variable.parameter.capture.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "name": "punctuation.separator.delimiter.comma.cpp" + }, + "7": { + "name": "keyword.operator.assignment.cpp" + } + } + }, + { + "include": "#evaluation_context" + } + ] + }, + "4": { + "name": "punctuation.definition.capture.end.lambda.cpp" + } + }, + "end": "(?<=})", + "patterns": [ + { + "name": "meta.function.definition.parameters.lambda.cpp", + "begin": "(\\()", + "beginCaptures": { + "1": { + "name": "punctuation.definition.parameters.begin.lambda.cpp" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.definition.parameters.end.lambda.cpp" + } + }, + "patterns": [ + { + "include": "#function_parameter_context" + } + ] + }, + { + "match": "(?)((?:.+?(?=\\{|$))?)", + "captures": { + "1": { + "name": "punctuation.definition.lambda.return-type.cpp" + }, + "2": { + "name": "storage.type.return-type.lambda.cpp" + } + } + }, + { + "name": "meta.function.definition.body.lambda.cpp", + "begin": "(\\{)", + "beginCaptures": { + "1": { + "name": "punctuation.section.block.begin.bracket.curly.lambda.cpp" + } + }, + "end": "(\\})", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.lambda.cpp" + } + }, + "patterns": [ + { + "include": "$base" + } + ] + } + ] + }, + "enumerator_list": { + "match": "((?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+((?]*|[^>]*+<[^>]*+>)++>\\s*)?(::))?\\s*((?|\\?\\?>)\\s*(;)|(;))|(?=[;>\\[\\]=]))", + "endCaptures": { + "1": { + "name": "punctuation.terminator.statement.cpp" + }, + "2": { + "name": "punctuation.terminator.statement.cpp" + } + }, + "patterns": [ + { + "name": "meta.head.enum.cpp", + "begin": "\\G ?", + "end": "((?:\\{|<%|\\?\\?<|(?=;)))", + "endCaptures": { + "1": { + "name": "punctuation.section.block.begin.bracket.curly.enum.cpp" + } + }, + "patterns": [ + { + "include": "$base" + } + ] + }, + { + "name": "meta.body.enum.cpp", + "begin": "(?<=\\{|<%|\\?\\?<)", + "end": "(\\}|%>|\\?\\?>)", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.enum.cpp" + } + }, + "patterns": [ + { + "include": "#enumerator_list" + }, + { + "include": "#comments" + }, + { + "include": "#comma" + }, + { + "include": "#semicolon" + } + ] + }, + { + "name": "meta.tail.enum.cpp", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "include": "$base" + } + ] + } + ] + }, + "inheritance_context": { + "patterns": [ + { + "match": ",", + "name": "punctuation.separator.delimiter.comma.inheritance.cpp" + }, + { + "match": "(?\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))(?:(?:(?:(?>\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:(?:(?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?:::))?(?:(?:(?:(?>\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:not|compl|sizeof|new|delete|not_eq|bitand|xor|bitor|and|or|throw|and_eq|xor_eq|or_eq|alignof|alignas|typeid|noexcept|noexcept|static_cast|dynamic_cast|const_cast|reinterpret_cast|while|for|do|if|else|goto|switch|try|catch|return|break|case|continue|default|NULL|true|false|nullptr|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|final|override|volatile|const|noexcept|constexpr|mutable|constexpr|consteval|private|protected|public|if|elif|else|endif|ifdef|ifndef|define|undef|include|line|error|warning|pragma|_Pragma|defined|__has_include|__has_cpp_attribute|this|template|namespace|using|operator|typedef|decltype|typename|asm|__asm__|concept|requires|export|thread_local|atomic_cancel|atomic_commit|atomic_noexcept|co_await|co_return|co_yield|import|module|reflexpr|synchronized|audit|axiom|transaction_safe|transaction_safe_dynamic)\\b)(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?![\\w<:.])))", + "captures": { + "1": { + "name": "entity.name.type.inherited.cpp" + } + } + } + ] + }, + "class_block": { + "name": "meta.block.class.cpp", + "begin": "((((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(DLLEXPORT)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?\\s*((?:(?\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))(?:(?:(?:(?>\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:(?:(?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?:::))?(?:(?:(?:(?>\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:not|compl|sizeof|new|delete|not_eq|bitand|xor|bitor|and|or|throw|and_eq|xor_eq|or_eq|alignof|alignas|typeid|noexcept|noexcept|static_cast|dynamic_cast|const_cast|reinterpret_cast|while|for|do|if|else|goto|switch|try|catch|return|break|case|continue|default|NULL|true|false|nullptr|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|final|override|volatile|const|noexcept|constexpr|mutable|constexpr|consteval|private|protected|public|if|elif|else|endif|ifdef|ifndef|define|undef|include|line|error|warning|pragma|_Pragma|defined|__has_include|__has_cpp_attribute|this|template|namespace|using|operator|typedef|decltype|typename|asm|__asm__|concept|requires|export|thread_local|atomic_cancel|atomic_commit|atomic_noexcept|co_await|co_return|co_yield|import|module|reflexpr|synchronized|audit|axiom|transaction_safe|transaction_safe_dynamic)\\b)(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?![\\w<:.])))+)*))?))", + "beginCaptures": { + "1": { + "name": "meta.head.class.cpp" + }, + "3": { + "name": "storage.type.$3.cpp" + }, + "4": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "5": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "6": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "7": { + "name": "comment.block.cpp" + }, + "8": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "9": { + "name": "entity.name.other.preprocessor.macro.predefined.DLLEXPORT.cpp" + }, + "10": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "11": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "12": { + "name": "comment.block.cpp" + }, + "13": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "14": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "15": { + "name": "entity.name.type.$3.cpp" + }, + "16": { + "name": "storage.type.modifier.final.cpp" + }, + "17": { + "name": "punctuation.separator.colon.inheritance.cpp" + }, + "18": { + "patterns": [ + { + "include": "#inheritance_context" + } + ] + } + }, + "end": "(?:(?:(?<=\\}|%>|\\?\\?>)\\s*(;)|(;))|(?=[;>\\[\\]=]))", + "endCaptures": { + "1": { + "name": "punctuation.terminator.statement.cpp" + }, + "2": { + "name": "punctuation.terminator.statement.cpp" + } + }, + "patterns": [ + { + "name": "meta.head.class.cpp", + "begin": "\\G ?", + "end": "((?:\\{|<%|\\?\\?<|(?=;)))", + "endCaptures": { + "1": { + "name": "punctuation.section.block.begin.bracket.curly.class.cpp" + } + }, + "patterns": [ + { + "include": "#ever_present_context" + }, + { + "include": "#inheritance_context" + }, + { + "include": "#template_call_range" + } + ] + }, + { + "name": "meta.body.class.cpp", + "begin": "(?<=\\{|<%|\\?\\?<)", + "end": "(\\}|%>|\\?\\?>)", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.class.cpp" + } + }, + "patterns": [ + { + "include": "#function_pointer" + }, + { + "include": "#static_assert" + }, + { + "include": "#constructor_inline" + }, + { + "include": "#destructor_inline" + }, + { + "include": "$base" + } + ] + }, + { + "name": "meta.tail.class.cpp", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "include": "$base" + } + ] + } + ] + }, + "struct_block": { + "name": "meta.block.struct.cpp", + "begin": "((((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(DLLEXPORT)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?\\s*((?:(?\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))(?:(?:(?:(?>\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:(?:(?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?:::))?(?:(?:(?:(?>\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:not|compl|sizeof|new|delete|not_eq|bitand|xor|bitor|and|or|throw|and_eq|xor_eq|or_eq|alignof|alignas|typeid|noexcept|noexcept|static_cast|dynamic_cast|const_cast|reinterpret_cast|while|for|do|if|else|goto|switch|try|catch|return|break|case|continue|default|NULL|true|false|nullptr|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|final|override|volatile|const|noexcept|constexpr|mutable|constexpr|consteval|private|protected|public|if|elif|else|endif|ifdef|ifndef|define|undef|include|line|error|warning|pragma|_Pragma|defined|__has_include|__has_cpp_attribute|this|template|namespace|using|operator|typedef|decltype|typename|asm|__asm__|concept|requires|export|thread_local|atomic_cancel|atomic_commit|atomic_noexcept|co_await|co_return|co_yield|import|module|reflexpr|synchronized|audit|axiom|transaction_safe|transaction_safe_dynamic)\\b)(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?![\\w<:.])))+)*))?))", + "beginCaptures": { + "1": { + "name": "meta.head.struct.cpp" + }, + "3": { + "name": "storage.type.$3.cpp" + }, + "4": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "5": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "6": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "7": { + "name": "comment.block.cpp" + }, + "8": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "9": { + "name": "entity.name.other.preprocessor.macro.predefined.DLLEXPORT.cpp" + }, + "10": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "11": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "12": { + "name": "comment.block.cpp" + }, + "13": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "14": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "15": { + "name": "entity.name.type.$3.cpp" + }, + "16": { + "name": "storage.type.modifier.final.cpp" + }, + "17": { + "name": "punctuation.separator.colon.inheritance.cpp" + }, + "18": { + "patterns": [ + { + "include": "#inheritance_context" + } + ] + } + }, + "end": "(?:(?:(?<=\\}|%>|\\?\\?>)\\s*(;)|(;))|(?=[;>\\[\\]=]))", + "endCaptures": { + "1": { + "name": "punctuation.terminator.statement.cpp" + }, + "2": { + "name": "punctuation.terminator.statement.cpp" + } + }, + "patterns": [ + { + "name": "meta.head.struct.cpp", + "begin": "\\G ?", + "end": "((?:\\{|<%|\\?\\?<|(?=;)))", + "endCaptures": { + "1": { + "name": "punctuation.section.block.begin.bracket.curly.struct.cpp" + } + }, + "patterns": [ + { + "include": "#ever_present_context" + }, + { + "include": "#inheritance_context" + }, + { + "include": "#template_call_range" + } + ] + }, + { + "name": "meta.body.struct.cpp", + "begin": "(?<=\\{|<%|\\?\\?<)", + "end": "(\\}|%>|\\?\\?>)", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.struct.cpp" + } + }, + "patterns": [ + { + "include": "#function_pointer" + }, + { + "include": "#static_assert" + }, + { + "include": "#constructor_inline" + }, + { + "include": "#destructor_inline" + }, + { + "include": "$base" + } + ] + }, + { + "name": "meta.tail.struct.cpp", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "include": "$base" + } + ] + } + ] + }, + "union_block": { + "name": "meta.block.union.cpp", + "begin": "((((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(DLLEXPORT)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?\\s*((?:(?\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))(?:(?:(?:(?>\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:(?:(?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?:::))?(?:(?:(?:(?>\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:not|compl|sizeof|new|delete|not_eq|bitand|xor|bitor|and|or|throw|and_eq|xor_eq|or_eq|alignof|alignas|typeid|noexcept|noexcept|static_cast|dynamic_cast|const_cast|reinterpret_cast|while|for|do|if|else|goto|switch|try|catch|return|break|case|continue|default|NULL|true|false|nullptr|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|final|override|volatile|const|noexcept|constexpr|mutable|constexpr|consteval|private|protected|public|if|elif|else|endif|ifdef|ifndef|define|undef|include|line|error|warning|pragma|_Pragma|defined|__has_include|__has_cpp_attribute|this|template|namespace|using|operator|typedef|decltype|typename|asm|__asm__|concept|requires|export|thread_local|atomic_cancel|atomic_commit|atomic_noexcept|co_await|co_return|co_yield|import|module|reflexpr|synchronized|audit|axiom|transaction_safe|transaction_safe_dynamic)\\b)(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?![\\w<:.])))+)*))?))", + "beginCaptures": { + "1": { + "name": "meta.head.union.cpp" + }, + "3": { + "name": "storage.type.$3.cpp" + }, + "4": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "5": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "6": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "7": { + "name": "comment.block.cpp" + }, + "8": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "9": { + "name": "entity.name.other.preprocessor.macro.predefined.DLLEXPORT.cpp" + }, + "10": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "11": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "12": { + "name": "comment.block.cpp" + }, + "13": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "14": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "15": { + "name": "entity.name.type.$3.cpp" + }, + "16": { + "name": "storage.type.modifier.final.cpp" + }, + "17": { + "name": "punctuation.separator.colon.inheritance.cpp" + }, + "18": { + "patterns": [ + { + "include": "#inheritance_context" + } + ] + } + }, + "end": "(?:(?:(?<=\\}|%>|\\?\\?>)\\s*(;)|(;))|(?=[;>\\[\\]=]))", + "endCaptures": { + "1": { + "name": "punctuation.terminator.statement.cpp" + }, + "2": { + "name": "punctuation.terminator.statement.cpp" + } + }, + "patterns": [ + { + "name": "meta.head.union.cpp", + "begin": "\\G ?", + "end": "((?:\\{|<%|\\?\\?<|(?=;)))", + "endCaptures": { + "1": { + "name": "punctuation.section.block.begin.bracket.curly.union.cpp" + } + }, + "patterns": [ + { + "include": "#ever_present_context" + }, + { + "include": "#inheritance_context" + }, + { + "include": "#template_call_range" + } + ] + }, + { + "name": "meta.body.union.cpp", + "begin": "(?<=\\{|<%|\\?\\?<)", + "end": "(\\}|%>|\\?\\?>)", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.union.cpp" + } + }, + "patterns": [ + { + "include": "#function_pointer" + }, + { + "include": "#static_assert" + }, + { + "include": "#constructor_inline" + }, + { + "include": "#destructor_inline" + }, + { + "include": "$base" + } + ] + }, + { + "name": "meta.tail.union.cpp", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "include": "$base" + } + ] + } + ] + }, + "extern_block": { + "name": "meta.block.extern.cpp", + "begin": "(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(extern)(?=\\s*\\\"))", + "beginCaptures": { + "1": { + "name": "meta.head.extern.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "name": "storage.type.extern.cpp" + } + }, + "end": "(?:(?:(?<=\\}|%>|\\?\\?>)\\s*(;)|(;))|(?=[;>\\[\\]=]))", + "endCaptures": { + "1": { + "name": "punctuation.terminator.statement.cpp" + }, + "2": { + "name": "punctuation.terminator.statement.cpp" + } + }, + "patterns": [ + { + "name": "meta.head.extern.cpp", + "begin": "\\G ?", + "end": "((?:\\{|<%|\\?\\?<|(?=;)))", + "endCaptures": { + "1": { + "name": "punctuation.section.block.begin.bracket.curly.extern.cpp" + } + }, + "patterns": [ + { + "include": "$base" + } + ] + }, + { + "name": "meta.body.extern.cpp", + "begin": "(?<=\\{|<%|\\?\\?<)", + "end": "(\\}|%>|\\?\\?>)", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.extern.cpp" + } + }, + "patterns": [ + { + "include": "$base" + } + ] + }, + { + "name": "meta.tail.extern.cpp", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "include": "$base" + } + ] + }, + { + "include": "$base" + } + ] + }, + "typedef_class": { + "begin": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(DLLEXPORT)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?\\s*((?:(?\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))(?:(?:(?:(?>\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:(?:(?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?:::))?(?:(?:(?:(?>\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:not|compl|sizeof|new|delete|not_eq|bitand|xor|bitor|and|or|throw|and_eq|xor_eq|or_eq|alignof|alignas|typeid|noexcept|noexcept|static_cast|dynamic_cast|const_cast|reinterpret_cast|while|for|do|if|else|goto|switch|try|catch|return|break|case|continue|default|NULL|true|false|nullptr|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|final|override|volatile|const|noexcept|constexpr|mutable|constexpr|consteval|private|protected|public|if|elif|else|endif|ifdef|ifndef|define|undef|include|line|error|warning|pragma|_Pragma|defined|__has_include|__has_cpp_attribute|this|template|namespace|using|operator|typedef|decltype|typename|asm|__asm__|concept|requires|export|thread_local|atomic_cancel|atomic_commit|atomic_noexcept|co_await|co_return|co_yield|import|module|reflexpr|synchronized|audit|axiom|transaction_safe|transaction_safe_dynamic)\\b)(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?![\\w<:.])))+)*))?))", + "beginCaptures": { + "1": { + "name": "meta.head.class.cpp" + }, + "3": { + "name": "storage.type.$3.cpp" + }, + "4": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "5": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "6": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "7": { + "name": "comment.block.cpp" + }, + "8": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "9": { + "name": "entity.name.other.preprocessor.macro.predefined.DLLEXPORT.cpp" + }, + "10": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "11": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "12": { + "name": "comment.block.cpp" + }, + "13": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "14": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "15": { + "name": "entity.name.type.$3.cpp" + }, + "16": { + "name": "storage.type.modifier.final.cpp" + }, + "17": { + "name": "punctuation.separator.colon.inheritance.cpp" + }, + "18": { + "patterns": [ + { + "include": "#inheritance_context" + } + ] + } + }, + "end": "(?:(?:(?<=\\}|%>|\\?\\?>)\\s*(;)|(;))|(?=[;>\\[\\]=]))", + "endCaptures": { + "1": { + "name": "punctuation.terminator.statement.cpp" + }, + "2": { + "name": "punctuation.terminator.statement.cpp" + } + }, + "patterns": [ + { + "name": "meta.head.class.cpp", + "begin": "\\G ?", + "end": "((?:\\{|<%|\\?\\?<|(?=;)))", + "endCaptures": { + "1": { + "name": "punctuation.section.block.begin.bracket.curly.class.cpp" + } + }, + "patterns": [ + { + "include": "#ever_present_context" + }, + { + "include": "#inheritance_context" + }, + { + "include": "#template_call_range" + } + ] + }, + { + "name": "meta.body.class.cpp", + "begin": "(?<=\\{|<%|\\?\\?<)", + "end": "(\\}|%>|\\?\\?>)", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.class.cpp" + } + }, + "patterns": [ + { + "include": "#function_pointer" + }, + { + "include": "#static_assert" + }, + { + "include": "#constructor_inline" + }, + { + "include": "#destructor_inline" + }, + { + "include": "$base" + } + ] + }, + { + "name": "meta.tail.class.cpp", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "match": "(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))){2,}\\&", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "name": "invalid.illegal.reference-type.cpp" + }, + { + "match": "\\&", + "name": "storage.modifier.reference.cpp" + } + ] + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "7": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "8": { + "name": "comment.block.cpp" + }, + "9": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "10": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "11": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "12": { + "name": "comment.block.cpp" + }, + "13": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "14": { + "name": "entity.name.type.alias.cpp" + } + } + }, + { + "match": "," + } + ] + } + ] + } + ] + }, + "typedef_struct": { + "begin": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(DLLEXPORT)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?\\s*((?:(?\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))(?:(?:(?:(?>\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:(?:(?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?:::))?(?:(?:(?:(?>\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:not|compl|sizeof|new|delete|not_eq|bitand|xor|bitor|and|or|throw|and_eq|xor_eq|or_eq|alignof|alignas|typeid|noexcept|noexcept|static_cast|dynamic_cast|const_cast|reinterpret_cast|while|for|do|if|else|goto|switch|try|catch|return|break|case|continue|default|NULL|true|false|nullptr|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|final|override|volatile|const|noexcept|constexpr|mutable|constexpr|consteval|private|protected|public|if|elif|else|endif|ifdef|ifndef|define|undef|include|line|error|warning|pragma|_Pragma|defined|__has_include|__has_cpp_attribute|this|template|namespace|using|operator|typedef|decltype|typename|asm|__asm__|concept|requires|export|thread_local|atomic_cancel|atomic_commit|atomic_noexcept|co_await|co_return|co_yield|import|module|reflexpr|synchronized|audit|axiom|transaction_safe|transaction_safe_dynamic)\\b)(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?![\\w<:.])))+)*))?))", + "beginCaptures": { + "1": { + "name": "meta.head.struct.cpp" + }, + "3": { + "name": "storage.type.$3.cpp" + }, + "4": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "5": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "6": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "7": { + "name": "comment.block.cpp" + }, + "8": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "9": { + "name": "entity.name.other.preprocessor.macro.predefined.DLLEXPORT.cpp" + }, + "10": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "11": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "12": { + "name": "comment.block.cpp" + }, + "13": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "14": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "15": { + "name": "entity.name.type.$3.cpp" + }, + "16": { + "name": "storage.type.modifier.final.cpp" + }, + "17": { + "name": "punctuation.separator.colon.inheritance.cpp" + }, + "18": { + "patterns": [ + { + "include": "#inheritance_context" + } + ] + } + }, + "end": "(?:(?:(?<=\\}|%>|\\?\\?>)\\s*(;)|(;))|(?=[;>\\[\\]=]))", + "endCaptures": { + "1": { + "name": "punctuation.terminator.statement.cpp" + }, + "2": { + "name": "punctuation.terminator.statement.cpp" + } + }, + "patterns": [ + { + "name": "meta.head.struct.cpp", + "begin": "\\G ?", + "end": "((?:\\{|<%|\\?\\?<|(?=;)))", + "endCaptures": { + "1": { + "name": "punctuation.section.block.begin.bracket.curly.struct.cpp" + } + }, + "patterns": [ + { + "include": "#ever_present_context" + }, + { + "include": "#inheritance_context" + }, + { + "include": "#template_call_range" + } + ] + }, + { + "name": "meta.body.struct.cpp", + "begin": "(?<=\\{|<%|\\?\\?<)", + "end": "(\\}|%>|\\?\\?>)", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.struct.cpp" + } + }, + "patterns": [ + { + "include": "#function_pointer" + }, + { + "include": "#static_assert" + }, + { + "include": "#constructor_inline" + }, + { + "include": "#destructor_inline" + }, + { + "include": "$base" + } + ] + }, + { + "name": "meta.tail.struct.cpp", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "match": "(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))){2,}\\&", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "name": "invalid.illegal.reference-type.cpp" + }, + { + "match": "\\&", + "name": "storage.modifier.reference.cpp" + } + ] + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "7": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "8": { + "name": "comment.block.cpp" + }, + "9": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "10": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "11": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "12": { + "name": "comment.block.cpp" + }, + "13": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "14": { + "name": "entity.name.type.alias.cpp" + } + } + }, + { + "match": "," + } + ] + } + ] + } + ] + }, + "typedef_union": { + "begin": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(DLLEXPORT)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?\\s*((?:(?\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))(?:(?:(?:(?>\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:(?:(?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?:::))?(?:(?:(?:(?>\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:not|compl|sizeof|new|delete|not_eq|bitand|xor|bitor|and|or|throw|and_eq|xor_eq|or_eq|alignof|alignas|typeid|noexcept|noexcept|static_cast|dynamic_cast|const_cast|reinterpret_cast|while|for|do|if|else|goto|switch|try|catch|return|break|case|continue|default|NULL|true|false|nullptr|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|final|override|volatile|const|noexcept|constexpr|mutable|constexpr|consteval|private|protected|public|if|elif|else|endif|ifdef|ifndef|define|undef|include|line|error|warning|pragma|_Pragma|defined|__has_include|__has_cpp_attribute|this|template|namespace|using|operator|typedef|decltype|typename|asm|__asm__|concept|requires|export|thread_local|atomic_cancel|atomic_commit|atomic_noexcept|co_await|co_return|co_yield|import|module|reflexpr|synchronized|audit|axiom|transaction_safe|transaction_safe_dynamic)\\b)(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?![\\w<:.])))+)*))?))", + "beginCaptures": { + "1": { + "name": "meta.head.union.cpp" + }, + "3": { + "name": "storage.type.$3.cpp" + }, + "4": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "5": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "6": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "7": { + "name": "comment.block.cpp" + }, + "8": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "9": { + "name": "entity.name.other.preprocessor.macro.predefined.DLLEXPORT.cpp" + }, + "10": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "11": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "12": { + "name": "comment.block.cpp" + }, + "13": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "14": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "15": { + "name": "entity.name.type.$3.cpp" + }, + "16": { + "name": "storage.type.modifier.final.cpp" + }, + "17": { + "name": "punctuation.separator.colon.inheritance.cpp" + }, + "18": { + "patterns": [ + { + "include": "#inheritance_context" + } + ] + } + }, + "end": "(?:(?:(?<=\\}|%>|\\?\\?>)\\s*(;)|(;))|(?=[;>\\[\\]=]))", + "endCaptures": { + "1": { + "name": "punctuation.terminator.statement.cpp" + }, + "2": { + "name": "punctuation.terminator.statement.cpp" + } + }, + "patterns": [ + { + "name": "meta.head.union.cpp", + "begin": "\\G ?", + "end": "((?:\\{|<%|\\?\\?<|(?=;)))", + "endCaptures": { + "1": { + "name": "punctuation.section.block.begin.bracket.curly.union.cpp" + } + }, + "patterns": [ + { + "include": "#ever_present_context" + }, + { + "include": "#inheritance_context" + }, + { + "include": "#template_call_range" + } + ] + }, + { + "name": "meta.body.union.cpp", + "begin": "(?<=\\{|<%|\\?\\?<)", + "end": "(\\}|%>|\\?\\?>)", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.union.cpp" + } + }, + "patterns": [ + { + "include": "#function_pointer" + }, + { + "include": "#static_assert" + }, + { + "include": "#constructor_inline" + }, + { + "include": "#destructor_inline" + }, + { + "include": "$base" + } + ] + }, + { + "name": "meta.tail.union.cpp", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "match": "(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))){2,}\\&", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "name": "invalid.illegal.reference-type.cpp" + }, + { + "match": "\\&", + "name": "storage.modifier.reference.cpp" + } + ] + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "7": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "8": { + "name": "comment.block.cpp" + }, + "9": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "10": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "11": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "12": { + "name": "comment.block.cpp" + }, + "13": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "14": { + "name": "entity.name.type.alias.cpp" + } + } + }, + { + "match": "," + } + ] + } + ] + } + ] + }, + "struct_declare": { + "match": "(struct)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!final\\W|final\\$|override\\W|override\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?!:)", + "captures": { + "1": { + "name": "storage.type.struct.declare.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "name": "entity.name.type.struct.cpp" + }, + "7": { + "patterns": [ + { + "match": "\\*", + "name": "storage.modifier.pointer.cpp" + }, + { + "match": "(?:\\&((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))){2,}\\&", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "name": "invalid.illegal.reference-type.cpp" + }, + { + "match": "\\&", + "name": "storage.modifier.reference.cpp" + } + ] + }, + "8": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "9": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "10": { + "name": "comment.block.cpp" + }, + "11": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "12": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "13": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "14": { + "name": "comment.block.cpp" + }, + "15": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "16": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "17": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "18": { + "name": "comment.block.cpp" + }, + "19": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "20": { + "name": "variable.other.object.declare.cpp" + }, + "21": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "22": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "23": { + "name": "comment.block.cpp" + }, + "24": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + } + }, + "union_declare": { + "match": "(union)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!final\\W|final\\$|override\\W|override\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?!:)", + "captures": { + "1": { + "name": "storage.type.union.declare.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "name": "entity.name.type.union.cpp" + }, + "7": { + "patterns": [ + { + "match": "\\*", + "name": "storage.modifier.pointer.cpp" + }, + { + "match": "(?:\\&((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))){2,}\\&", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "name": "invalid.illegal.reference-type.cpp" + }, + { + "match": "\\&", + "name": "storage.modifier.reference.cpp" + } + ] + }, + "8": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "9": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "10": { + "name": "comment.block.cpp" + }, + "11": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "12": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "13": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "14": { + "name": "comment.block.cpp" + }, + "15": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "16": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "17": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "18": { + "name": "comment.block.cpp" + }, + "19": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "20": { + "name": "variable.other.object.declare.cpp" + }, + "21": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "22": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "23": { + "name": "comment.block.cpp" + }, + "24": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + } + }, + "enum_declare": { + "match": "(enum)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!final\\W|final\\$|override\\W|override\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?!:)", + "captures": { + "1": { + "name": "storage.type.enum.declare.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "name": "entity.name.type.enum.cpp" + }, + "7": { + "patterns": [ + { + "match": "\\*", + "name": "storage.modifier.pointer.cpp" + }, + { + "match": "(?:\\&((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))){2,}\\&", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "name": "invalid.illegal.reference-type.cpp" + }, + { + "match": "\\&", + "name": "storage.modifier.reference.cpp" + } + ] + }, + "8": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "9": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "10": { + "name": "comment.block.cpp" + }, + "11": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "12": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "13": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "14": { + "name": "comment.block.cpp" + }, + "15": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "16": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "17": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "18": { + "name": "comment.block.cpp" + }, + "19": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "20": { + "name": "variable.other.object.declare.cpp" + }, + "21": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "22": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "23": { + "name": "comment.block.cpp" + }, + "24": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + } + }, + "class_declare": { + "match": "(class)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\b(?!final\\W|final\\$|override\\W|override\\$)((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\S)(?!:)", + "captures": { + "1": { + "name": "storage.type.class.declare.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "name": "entity.name.type.class.cpp" + }, + "7": { + "patterns": [ + { + "match": "\\*", + "name": "storage.modifier.pointer.cpp" + }, + { + "match": "(?:\\&((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))){2,}\\&", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "name": "invalid.illegal.reference-type.cpp" + }, + { + "match": "\\&", + "name": "storage.modifier.reference.cpp" + } + ] + }, + "8": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "9": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "10": { + "name": "comment.block.cpp" + }, + "11": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "12": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "13": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "14": { + "name": "comment.block.cpp" + }, + "15": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "16": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "17": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "18": { + "name": "comment.block.cpp" + }, + "19": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "20": { + "name": "variable.other.object.declare.cpp" + }, + "21": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "22": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "23": { + "name": "comment.block.cpp" + }, + "24": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + } + }, + "standard_declares": { + "patterns": [ + { + "include": "#struct_declare" + }, + { + "include": "#union_declare" + }, + { + "include": "#enum_declare" + }, + { + "include": "#class_declare" + } + ] + }, + "parameter_struct": { + "match": "(struct)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:\\[((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\]((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?(?=,|\\)|\\n)", + "captures": { + "1": { + "name": "storage.type.struct.parameter.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "name": "entity.name.type.struct.parameter.cpp" + }, + "7": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "8": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "9": { + "name": "comment.block.cpp" + }, + "10": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "11": { + "patterns": [ + { + "match": "\\*", + "name": "storage.modifier.pointer.cpp" + }, + { + "match": "(?:\\&((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))){2,}\\&", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "name": "invalid.illegal.reference-type.cpp" + }, + { + "match": "\\&", + "name": "storage.modifier.reference.cpp" + } + ] + }, + "12": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "13": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "14": { + "name": "comment.block.cpp" + }, + "15": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "16": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "17": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "18": { + "name": "comment.block.cpp" + }, + "19": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "20": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "21": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "22": { + "name": "comment.block.cpp" + }, + "23": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "24": { + "name": "variable.other.object.declare.cpp" + }, + "25": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "26": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "27": { + "name": "comment.block.cpp" + }, + "28": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "29": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "30": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "31": { + "name": "comment.block.cpp" + }, + "32": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "33": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "34": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "35": { + "name": "comment.block.cpp" + }, + "36": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + } + }, + "parameter_enum": { + "match": "(enum)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:\\[((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\]((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?(?=,|\\)|\\n)", + "captures": { + "1": { + "name": "storage.type.enum.parameter.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "name": "entity.name.type.enum.parameter.cpp" + }, + "7": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "8": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "9": { + "name": "comment.block.cpp" + }, + "10": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "11": { + "patterns": [ + { + "match": "\\*", + "name": "storage.modifier.pointer.cpp" + }, + { + "match": "(?:\\&((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))){2,}\\&", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "name": "invalid.illegal.reference-type.cpp" + }, + { + "match": "\\&", + "name": "storage.modifier.reference.cpp" + } + ] + }, + "12": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "13": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "14": { + "name": "comment.block.cpp" + }, + "15": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "16": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "17": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "18": { + "name": "comment.block.cpp" + }, + "19": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "20": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "21": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "22": { + "name": "comment.block.cpp" + }, + "23": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "24": { + "name": "variable.other.object.declare.cpp" + }, + "25": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "26": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "27": { + "name": "comment.block.cpp" + }, + "28": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "29": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "30": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "31": { + "name": "comment.block.cpp" + }, + "32": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "33": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "34": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "35": { + "name": "comment.block.cpp" + }, + "36": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + } + }, + "parameter_union": { + "match": "(union)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:\\[((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\]((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?(?=,|\\)|\\n)", + "captures": { + "1": { + "name": "storage.type.union.parameter.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "name": "entity.name.type.union.parameter.cpp" + }, + "7": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "8": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "9": { + "name": "comment.block.cpp" + }, + "10": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "11": { + "patterns": [ + { + "match": "\\*", + "name": "storage.modifier.pointer.cpp" + }, + { + "match": "(?:\\&((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))){2,}\\&", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "name": "invalid.illegal.reference-type.cpp" + }, + { + "match": "\\&", + "name": "storage.modifier.reference.cpp" + } + ] + }, + "12": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "13": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "14": { + "name": "comment.block.cpp" + }, + "15": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "16": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "17": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "18": { + "name": "comment.block.cpp" + }, + "19": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "20": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "21": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "22": { + "name": "comment.block.cpp" + }, + "23": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "24": { + "name": "variable.other.object.declare.cpp" + }, + "25": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "26": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "27": { + "name": "comment.block.cpp" + }, + "28": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "29": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "30": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "31": { + "name": "comment.block.cpp" + }, + "32": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "33": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "34": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "35": { + "name": "comment.block.cpp" + }, + "36": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + } + }, + "parameter_class": { + "match": "(class)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:\\[((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\]((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?(?=,|\\)|\\n)", + "captures": { + "1": { + "name": "storage.type.class.parameter.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "name": "entity.name.type.class.parameter.cpp" + }, + "7": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "8": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "9": { + "name": "comment.block.cpp" + }, + "10": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "11": { + "patterns": [ + { + "match": "\\*", + "name": "storage.modifier.pointer.cpp" + }, + { + "match": "(?:\\&((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))){2,}\\&", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "name": "invalid.illegal.reference-type.cpp" + }, + { + "match": "\\&", + "name": "storage.modifier.reference.cpp" + } + ] + }, + "12": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "13": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "14": { + "name": "comment.block.cpp" + }, + "15": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "16": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "17": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "18": { + "name": "comment.block.cpp" + }, + "19": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "20": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "21": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "22": { + "name": "comment.block.cpp" + }, + "23": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "24": { + "name": "variable.other.object.declare.cpp" + }, + "25": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "26": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "27": { + "name": "comment.block.cpp" + }, + "28": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "29": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "30": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "31": { + "name": "comment.block.cpp" + }, + "32": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "33": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "34": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "35": { + "name": "comment.block.cpp" + }, + "36": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + } + }, + "over_qualified_types": { + "patterns": [ + { + "include": "#parameter_struct" + }, + { + "include": "#parameter_enum" + }, + { + "include": "#parameter_union" + }, + { + "include": "#parameter_class" + } + ] + }, + "hacky_fix_for_stray_directive": { + "match": "(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))#define.*(?(?-mix:[a-zA-Z_$][\\w$]*)))\t # macro name\n(?:\n (\\()\n\t(\n\t \\s* \\g \\s*\t\t # first argument\n\t ((,) \\s* \\g \\s*)* # additional arguments\n\t (?:\\.\\.\\.)?\t\t\t# varargs ellipsis?\n\t)\n (\\))\n)?", + "beginCaptures": { + "1": { + "name": "keyword.control.directive.define.cpp" + }, + "2": { + "name": "punctuation.definition.directive.cpp" + }, + "3": { + "name": "entity.name.function.preprocessor.cpp" + }, + "5": { + "name": "punctuation.definition.parameters.begin.cpp" + }, + "6": { + "name": "variable.parameter.preprocessor.cpp" + }, + "8": { + "name": "punctuation.separator.parameters.cpp" + }, + "9": { + "name": "punctuation.definition.parameters.end.cpp" + } + }, + "end": "(?=(?://|/\\*))|(?", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.cpp" + } + }, + "name": "string.quoted.other.lt-gt.include.cpp" + } + ] + }, + "meta_preprocessor_line": { + "name": "meta.preprocessor.cpp", + "begin": "^\\s*((#)\\s*line)\\b", + "beginCaptures": { + "1": { + "name": "keyword.control.directive.line.cpp" + }, + "2": { + "name": "punctuation.definition.directive.cpp" + } + }, + "end": "(?=(?://|/\\*))|(?=+!]+|\\(\\)|\\[\\]))\\s*\\(\n)", + "end": "(?<=\\))(?!\\w)|(?=+!]+|\\(\\)|\\[\\]))\n)\n\\s*(\\()", + "beginCaptures": { + "1": { + "name": "entity.name.function.cpp" + }, + "2": { + "name": "punctuation.section.arguments.begin.bracket.round.cpp" + } + }, + "end": "(\\))|(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*)(((?>(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))::((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))\\13((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\()))", + "beginCaptures": { + "1": { + "name": "meta.head.function.definition.special.constructor.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "name": "storage.type.modifier.calling-convention.cpp" + }, + "7": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "8": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "9": { + "name": "comment.block.cpp" + }, + "10": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "11": { + "patterns": [ + { + "match": "::", + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.constructor.cpp" + }, + { + "match": "(?|\\?\\?>)|(?=[;>\\[\\]=]))|(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(default)|(delete))", + "captures": { + "1": { + "name": "keyword.operator.assignment.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "name": "keyword.other.default.constructor.cpp" + }, + "7": { + "name": "keyword.other.delete.constructor.cpp" + } + } + } + ] + }, + { + "include": "#functional_specifiers_pre_parameters" + }, + { + "begin": "(:)", + "beginCaptures": { + "1": { + "name": "punctuation.separator.initializers.cpp" + } + }, + "end": "(?=\\{)", + "patterns": [ + { + "contentName": "meta.parameter.initialization.cpp", + "begin": "((?|\\?\\?>)", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.function.definition.special.constructor.cpp" + } + }, + "patterns": [ + { + "include": "#function_body_context" + } + ] + }, + { + "name": "meta.tail.function.definition.special.constructor.cpp", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "include": "$base" + } + ] + } + ] + }, + "macro_safe_destructor_root": { + "name": "meta.function.definition.special.member.destructor.cpp", + "begin": "(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*)(((?>(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))::((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))~\\13((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\()))", + "beginCaptures": { + "1": { + "name": "meta.head.function.definition.special.member.destructor.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "name": "storage.type.modifier.calling-convention.cpp" + }, + "7": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "8": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "9": { + "name": "comment.block.cpp" + }, + "10": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "11": { + "patterns": [ + { + "match": "::", + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.destructor.cpp" + }, + { + "match": "(?|\\?\\?>)|(?=[;>\\[\\]=]))|(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(default)|(delete))", + "captures": { + "1": { + "name": "keyword.operator.assignment.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "name": "keyword.other.default.constructor.cpp" + }, + "7": { + "name": "keyword.other.delete.constructor.cpp" + } + } + } + ] + }, + { + "contentName": "meta.function.definition.parameters.special.member.destructor.cpp", + "begin": "(\\()", + "beginCaptures": { + "1": { + "name": "punctuation.section.parameters.begin.bracket.round.special.member.destructor.cpp" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.parameters.end.bracket.round.special.member.destructor.cpp" + } + } + }, + { + "include": "$base" + } + ] + }, + { + "name": "meta.body.function.definition.special.member.destructor.cpp", + "begin": "(?<=\\{|<%|\\?\\?<)", + "end": "(\\}|%>|\\?\\?>)", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.function.definition.special.member.destructor.cpp" + } + }, + "patterns": [ + { + "include": "#function_body_context" + } + ] + }, + { + "name": "meta.tail.function.definition.special.member.destructor.cpp", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "include": "$base" + } + ] + } + ] + }, + "macro_safe_function_definition": { + "name": "meta.function.definition.cpp", + "begin": "((?:(?:^|\\G|(?<=;|\\}))|(?<=>))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?(?:((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+((?]*|[^>]*+<[^>]*+>)++>\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:not|compl|sizeof|new|delete|not_eq|bitand|xor|bitor|and|or|throw|and_eq|xor_eq|or_eq|alignof|alignas|typeid|noexcept|noexcept|static_cast|dynamic_cast|const_cast|reinterpret_cast|while|for|do|if|else|goto|switch|try|catch|return|break|case|continue|default|NULL|true|false|nullptr|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|final|override|volatile|const|noexcept|constexpr|mutable|constexpr|consteval|private|protected|public|if|elif|else|endif|ifdef|ifndef|define|undef|include|line|error|warning|pragma|_Pragma|defined|__has_include|__has_cpp_attribute|this|template|namespace|using|operator|typedef|decltype|typename|asm|__asm__|concept|requires|export|thread_local|atomic_cancel|atomic_commit|atomic_noexcept|co_await|co_return|co_yield|import|module|reflexpr|synchronized|audit|axiom|transaction_safe|transaction_safe_dynamic)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\())", + "beginCaptures": { + "1": { + "name": "meta.head.function.definition.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "name": "storage.type.template.cpp" + }, + "7": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "8": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "9": { + "name": "comment.block.cpp" + }, + "10": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "11": { + "name": "storage.modifier.$11.cpp" + }, + "12": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "13": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "14": { + "name": "comment.block.cpp" + }, + "15": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "16": { + "name": "meta.qualified_type.cpp", + "patterns": [ + { + "match": "(?:class|struct|union|enum)", + "name": "storage.type.$0.cpp" + }, + { + "include": "#attributes_context" + }, + { + "include": "#function_type" + }, + { + "include": "#storage_types" + }, + { + "include": "#number_literal" + }, + { + "include": "#string_context_c" + }, + { + "include": "#comma" + }, + { + "include": "#scope_resolution_inner_generated" + }, + { + "include": "#template_call_range" + }, + { + "match": "(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*", + "name": "entity.name.type.cpp" + } + ] + }, + "17": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "18": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "19": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "20": { + "name": "comment.block.cpp" + }, + "21": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "22": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "23": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "24": { + "name": "comment.block.cpp" + }, + "25": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "27": { + "patterns": [ + { + "include": "#scope_resolution_inner_generated" + } + ] + }, + "28": { + "name": "entity.name.scope-resolution.cpp" + }, + "29": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "30": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp" + }, + "31": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "32": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "33": { + "name": "comment.block.cpp" + }, + "34": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "35": { + "name": "entity.name.type.cpp" + }, + "36": { + "patterns": [ + { + "match": "\\*", + "name": "storage.modifier.pointer.cpp" + }, + { + "match": "(?:\\&((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))){2,}\\&", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "name": "invalid.illegal.reference-type.cpp" + }, + { + "match": "\\&", + "name": "storage.modifier.reference.cpp" + } + ] + }, + "37": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "38": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "39": { + "name": "comment.block.cpp" + }, + "40": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "41": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "42": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "43": { + "name": "comment.block.cpp" + }, + "44": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "45": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "46": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "47": { + "name": "comment.block.cpp" + }, + "48": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "49": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "50": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "51": { + "name": "comment.block.cpp" + }, + "52": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "53": { + "name": "storage.type.modifier.calling-convention.cpp" + }, + "54": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "55": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "56": { + "name": "comment.block.cpp" + }, + "57": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "58": { + "patterns": [ + { + "include": "#scope_resolution_function_definition_inner_generated" + } + ] + }, + "59": { + "name": "entity.name.function.definition.cpp" + }, + "60": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "61": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "62": { + "name": "comment.block.cpp" + }, + "63": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))|(?|\\?\\?>)", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.function.definition.cpp" + } + }, + "patterns": [ + { + "include": "#function_body_context" + } + ] + }, + { + "name": "meta.tail.function.definition.cpp", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "include": "$base" + } + ] + } + ] + }, + "macro_safe_operator_overload": { + "name": "meta.function.definition.special.operator-overload.cpp", + "begin": "((?:(\\s*+((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+((?]*|[^>]*+<[^>]*+>)++>\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:not|compl|sizeof|new|delete|not_eq|bitand|xor|bitor|and|or|throw|and_eq|xor_eq|or_eq|alignof|alignas|typeid|noexcept|noexcept|static_cast|dynamic_cast|const_cast|reinterpret_cast|while|for|do|if|else|goto|switch|try|catch|return|break|case|continue|default|NULL|true|false|nullptr|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|final|override|volatile|const|noexcept|constexpr|mutable|constexpr|consteval|private|protected|public|if|elif|else|endif|ifdef|ifndef|define|undef|include|line|error|warning|pragma|_Pragma|defined|__has_include|__has_cpp_attribute|this|template|namespace|using|operator|typedef|decltype|typename|asm|__asm__|concept|requires|export|thread_local|atomic_cancel|atomic_commit|atomic_noexcept|co_await|co_return|co_yield|import|module|reflexpr|synchronized|audit|axiom|transaction_safe|transaction_safe_dynamic)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:__cdecl|__clrcall|__stdcall|__fastcall|__thiscall|__vectorcall)?)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*)(operator)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*)(?:(?:((?:\\+\\+|\\-\\-|\\(\\)|\\[\\]|\\->|\\+\\+|\\-\\-|\\+|\\-|!|~|\\*|&|new|new\\[\\]|delete|delete\\[\\]|\\->\\*|\\*|\\/|%|\\+|\\-|<<|>>|<=>|<|<=|>|>=|==|!=|&|\\^|\\||&&|\\|\\||=|\\+=|\\-=|\\*=|\\/=|%=|<<=|>>=|&=|\\^=|\\|=|,))|((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?:\\[\\])?)))|(\"\")((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=\\<|\\())", + "beginCaptures": { + "1": { + "name": "meta.head.function.definition.special.operator-overload.cpp" + }, + "2": { + "name": "meta.qualified_type.cpp", + "patterns": [ + { + "match": "(?:class|struct|union|enum)", + "name": "storage.type.$0.cpp" + }, + { + "include": "#attributes_context" + }, + { + "include": "#function_type" + }, + { + "include": "#storage_types" + }, + { + "include": "#number_literal" + }, + { + "include": "#string_context_c" + }, + { + "include": "#comma" + }, + { + "include": "#scope_resolution_inner_generated" + }, + { + "include": "#template_call_range" + }, + { + "match": "(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*", + "name": "entity.name.type.cpp" + } + ] + }, + "3": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "4": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "5": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "6": { + "name": "comment.block.cpp" + }, + "7": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "8": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "9": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "10": { + "name": "comment.block.cpp" + }, + "11": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "13": { + "patterns": [ + { + "include": "#scope_resolution_inner_generated" + } + ] + }, + "14": { + "name": "entity.name.scope-resolution.cpp" + }, + "15": { + "name": "meta.template.call.cpp", + "patterns": [ + { + "include": "#template_call_range" + } + ] + }, + "16": { + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp" + }, + "17": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "18": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "19": { + "name": "comment.block.cpp" + }, + "20": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "21": { + "name": "entity.name.type.cpp" + }, + "22": { + "patterns": [ + { + "match": "\\*", + "name": "storage.modifier.pointer.cpp" + }, + { + "match": "(?:\\&((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))){2,}\\&", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "name": "invalid.illegal.reference-type.cpp" + }, + { + "match": "\\&", + "name": "storage.modifier.reference.cpp" + } + ] + }, + "23": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "24": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "25": { + "name": "comment.block.cpp" + }, + "26": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "27": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "28": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "29": { + "name": "comment.block.cpp" + }, + "30": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "31": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "32": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "33": { + "name": "comment.block.cpp" + }, + "34": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "35": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "36": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "37": { + "name": "comment.block.cpp" + }, + "38": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "39": { + "name": "storage.type.modifier.calling-convention.cpp" + }, + "40": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "41": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "42": { + "name": "comment.block.cpp" + }, + "43": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "44": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "45": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "46": { + "name": "comment.block.cpp" + }, + "47": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "48": { + "patterns": [ + { + "match": "::", + "name": "punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.operator.cpp" + }, + { + "match": "(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))){2,}\\&", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "name": "invalid.illegal.reference-type.cpp" + }, + { + "match": "\\&", + "name": "entity.name.operator.type.reference.cpp" + } + ] + }, + "58": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "59": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "60": { + "name": "comment.block.cpp" + }, + "61": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "62": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "63": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "64": { + "name": "comment.block.cpp" + }, + "65": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "66": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "67": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "68": { + "name": "comment.block.cpp" + }, + "69": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "70": { + "name": "entity.name.operator.type.array.cpp" + }, + "71": { + "name": "entity.name.operator.custom-literal.cpp" + }, + "72": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "73": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "74": { + "name": "comment.block.cpp" + }, + "75": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "76": { + "name": "entity.name.operator.custom-literal.cpp" + }, + "77": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "78": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "79": { + "name": "comment.block.cpp" + }, + "80": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "end": "(?:(?<=\\}|%>|\\?\\?>)|(?=[;>\\[\\]=]))|(?|\\?\\?>)", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.function.definition.special.operator-overload.cpp" + } + }, + "patterns": [ + { + "include": "#function_body_context" + } + ] + }, + { + "name": "meta.tail.function.definition.special.operator-overload.cpp", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "include": "$base" + } + ] + } + ] + }, + "macro_safe_using_namespace": { + "name": "meta.using-namespace.cpp", + "begin": "(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)?((?|\\?\\?>)|(?=[;>\\[\\]=]))|(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)\\s*((?|\\?\\?>)", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.namespace.cpp" + } + }, + "patterns": [ + { + "include": "$base" + } + ] + }, + { + "name": "meta.tail.namespace.cpp", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "include": "$base" + } + ] + } + ] + }, + "macro_safe_extern_block": { + "name": "meta.block.extern.cpp", + "begin": "(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(extern)(?=\\s*\\\"))", + "beginCaptures": { + "1": { + "name": "meta.head.extern.cpp" + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "name": "storage.type.extern.cpp" + } + }, + "end": "(?:(?:(?<=\\}|%>|\\?\\?>)\\s*(;)|(;))|(?=[;>\\[\\]=]))|(?|\\?\\?>)", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.extern.cpp" + } + }, + "patterns": [ + { + "include": "$base" + } + ] + }, + { + "name": "meta.tail.extern.cpp", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "include": "$base" + } + ] + }, + { + "include": "$base" + } + ] + }, + "macro_safe_typedef_class": { + "begin": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(DLLEXPORT)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?\\s*((?:(?\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))(?:(?:(?:(?>\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:(?:(?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?:::))?(?:(?:(?:(?>\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:not|compl|sizeof|new|delete|not_eq|bitand|xor|bitor|and|or|throw|and_eq|xor_eq|or_eq|alignof|alignas|typeid|noexcept|noexcept|static_cast|dynamic_cast|const_cast|reinterpret_cast|while|for|do|if|else|goto|switch|try|catch|return|break|case|continue|default|NULL|true|false|nullptr|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|final|override|volatile|const|noexcept|constexpr|mutable|constexpr|consteval|private|protected|public|if|elif|else|endif|ifdef|ifndef|define|undef|include|line|error|warning|pragma|_Pragma|defined|__has_include|__has_cpp_attribute|this|template|namespace|using|operator|typedef|decltype|typename|asm|__asm__|concept|requires|export|thread_local|atomic_cancel|atomic_commit|atomic_noexcept|co_await|co_return|co_yield|import|module|reflexpr|synchronized|audit|axiom|transaction_safe|transaction_safe_dynamic)\\b)(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?![\\w<:.])))+)*))?))", "beginCaptures": { - "0": { - "name": "punctuation.definition.string.begin.cpp" + "1": { + "name": "meta.head.class.cpp" + }, + "3": { + "name": "storage.type.$3.cpp" + }, + "4": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "5": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "6": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "7": { + "name": "comment.block.cpp" + }, + "8": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "9": { + "name": "entity.name.other.preprocessor.macro.predefined.DLLEXPORT.cpp" + }, + "10": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "11": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "12": { + "name": "comment.block.cpp" + }, + "13": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "14": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "15": { + "name": "entity.name.type.$3.cpp" + }, + "16": { + "name": "storage.type.modifier.final.cpp" + }, + "17": { + "name": "punctuation.separator.colon.inheritance.cpp" + }, + "18": { + "patterns": [ + { + "include": "#inheritance_context" + } + ] } }, - "end": ">", + "end": "(?:(?:(?<=\\}|%>|\\?\\?>)\\s*(;)|(;))|(?=[;>\\[\\]=]))", "endCaptures": { - "0": { - "name": "punctuation.definition.string.end.cpp" + "1": { + "name": "punctuation.terminator.statement.cpp" + }, + "2": { + "name": "punctuation.terminator.statement.cpp" + } + }, + "patterns": [ + { + "name": "meta.head.class.cpp", + "begin": "\\G ?", + "end": "((?:\\{|<%|\\?\\?<|(?=;)))", + "endCaptures": { + "1": { + "name": "punctuation.section.block.begin.bracket.curly.class.cpp" + } + }, + "patterns": [ + { + "include": "#ever_present_context" + }, + { + "include": "#inheritance_context" + }, + { + "include": "#template_call_range" + } + ] + }, + { + "name": "meta.body.class.cpp", + "begin": "(?<=\\{|<%|\\?\\?<)", + "end": "(\\}|%>|\\?\\?>)", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.class.cpp" + } + }, + "patterns": [ + { + "include": "#function_pointer" + }, + { + "include": "#static_assert" + }, + { + "include": "#constructor_inline" + }, + { + "include": "#destructor_inline" + }, + { + "include": "$base" + } + ] + }, + { + "name": "meta.tail.class.cpp", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "match": "(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))){2,}\\&", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "name": "invalid.illegal.reference-type.cpp" + }, + { + "match": "\\&", + "name": "storage.modifier.reference.cpp" + } + ] + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "7": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "8": { + "name": "comment.block.cpp" + }, + "9": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "10": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "11": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "12": { + "name": "comment.block.cpp" + }, + "13": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "14": { + "name": "entity.name.type.alias.cpp" + } + } + }, + { + "match": "," + } + ] + } + ] + } + ] + }, + "macro_safe_typedef_struct": { + "begin": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(DLLEXPORT)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?\\s*((?:(?\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))(?:(?:(?:(?>\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:(?:(?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?:::))?(?:(?:(?:(?>\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:not|compl|sizeof|new|delete|not_eq|bitand|xor|bitor|and|or|throw|and_eq|xor_eq|or_eq|alignof|alignas|typeid|noexcept|noexcept|static_cast|dynamic_cast|const_cast|reinterpret_cast|while|for|do|if|else|goto|switch|try|catch|return|break|case|continue|default|NULL|true|false|nullptr|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|final|override|volatile|const|noexcept|constexpr|mutable|constexpr|consteval|private|protected|public|if|elif|else|endif|ifdef|ifndef|define|undef|include|line|error|warning|pragma|_Pragma|defined|__has_include|__has_cpp_attribute|this|template|namespace|using|operator|typedef|decltype|typename|asm|__asm__|concept|requires|export|thread_local|atomic_cancel|atomic_commit|atomic_noexcept|co_await|co_return|co_yield|import|module|reflexpr|synchronized|audit|axiom|transaction_safe|transaction_safe_dynamic)\\b)(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?![\\w<:.])))+)*))?))", + "beginCaptures": { + "1": { + "name": "meta.head.struct.cpp" + }, + "3": { + "name": "storage.type.$3.cpp" + }, + "4": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "5": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "6": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "7": { + "name": "comment.block.cpp" + }, + "8": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "9": { + "name": "entity.name.other.preprocessor.macro.predefined.DLLEXPORT.cpp" + }, + "10": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "11": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "12": { + "name": "comment.block.cpp" + }, + "13": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "14": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "15": { + "name": "entity.name.type.$3.cpp" + }, + "16": { + "name": "storage.type.modifier.final.cpp" + }, + "17": { + "name": "punctuation.separator.colon.inheritance.cpp" + }, + "18": { + "patterns": [ + { + "include": "#inheritance_context" + } + ] + } + }, + "end": "(?:(?:(?<=\\}|%>|\\?\\?>)\\s*(;)|(;))|(?=[;>\\[\\]=]))", + "endCaptures": { + "1": { + "name": "punctuation.terminator.statement.cpp" + }, + "2": { + "name": "punctuation.terminator.statement.cpp" + } + }, + "patterns": [ + { + "name": "meta.head.struct.cpp", + "begin": "\\G ?", + "end": "((?:\\{|<%|\\?\\?<|(?=;)))", + "endCaptures": { + "1": { + "name": "punctuation.section.block.begin.bracket.curly.struct.cpp" + } + }, + "patterns": [ + { + "include": "#ever_present_context" + }, + { + "include": "#inheritance_context" + }, + { + "include": "#template_call_range" + } + ] + }, + { + "name": "meta.body.struct.cpp", + "begin": "(?<=\\{|<%|\\?\\?<)", + "end": "(\\}|%>|\\?\\?>)", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.struct.cpp" + } + }, + "patterns": [ + { + "include": "#function_pointer" + }, + { + "include": "#static_assert" + }, + { + "include": "#constructor_inline" + }, + { + "include": "#destructor_inline" + }, + { + "include": "$base" + } + ] + }, + { + "name": "meta.tail.struct.cpp", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "match": "(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))){2,}\\&", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "name": "invalid.illegal.reference-type.cpp" + }, + { + "match": "\\&", + "name": "storage.modifier.reference.cpp" + } + ] + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "7": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "8": { + "name": "comment.block.cpp" + }, + "9": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "10": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "11": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "12": { + "name": "comment.block.cpp" + }, + "13": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "14": { + "name": "entity.name.type.alias.cpp" + } + } + }, + { + "match": "," + } + ] } - }, - "name": "string.quoted.other.lt-gt.include.cpp" + ] } ] }, - "meta_preprocessor_line": { - "name": "meta.preprocessor.cpp", - "begin": "^\\s*((#)\\s*line)\\b", + "macro_safe_typedef_union": { + "begin": "((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(DLLEXPORT)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?\\s*((?:(?\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))(?:(?:(?:(?>\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:(?:(?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?:::))?(?:(?:(?:(?>\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:not|compl|sizeof|new|delete|not_eq|bitand|xor|bitor|and|or|throw|and_eq|xor_eq|or_eq|alignof|alignas|typeid|noexcept|noexcept|static_cast|dynamic_cast|const_cast|reinterpret_cast|while|for|do|if|else|goto|switch|try|catch|return|break|case|continue|default|NULL|true|false|nullptr|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|final|override|volatile|const|noexcept|constexpr|mutable|constexpr|consteval|private|protected|public|if|elif|else|endif|ifdef|ifndef|define|undef|include|line|error|warning|pragma|_Pragma|defined|__has_include|__has_cpp_attribute|this|template|namespace|using|operator|typedef|decltype|typename|asm|__asm__|concept|requires|export|thread_local|atomic_cancel|atomic_commit|atomic_noexcept|co_await|co_return|co_yield|import|module|reflexpr|synchronized|audit|axiom|transaction_safe|transaction_safe_dynamic)\\b)(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?![\\w<:.])))+)*))?))", + "beginCaptures": { + "1": { + "name": "meta.head.union.cpp" + }, + "3": { + "name": "storage.type.$3.cpp" + }, + "4": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "5": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "6": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "7": { + "name": "comment.block.cpp" + }, + "8": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "9": { + "name": "entity.name.other.preprocessor.macro.predefined.DLLEXPORT.cpp" + }, + "10": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "11": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "12": { + "name": "comment.block.cpp" + }, + "13": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "14": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] + }, + "15": { + "name": "entity.name.type.$3.cpp" + }, + "16": { + "name": "storage.type.modifier.final.cpp" + }, + "17": { + "name": "punctuation.separator.colon.inheritance.cpp" + }, + "18": { + "patterns": [ + { + "include": "#inheritance_context" + } + ] + } + }, + "end": "(?:(?:(?<=\\}|%>|\\?\\?>)\\s*(;)|(;))|(?=[;>\\[\\]=]))", + "endCaptures": { + "1": { + "name": "punctuation.terminator.statement.cpp" + }, + "2": { + "name": "punctuation.terminator.statement.cpp" + } + }, + "patterns": [ + { + "name": "meta.head.union.cpp", + "begin": "\\G ?", + "end": "((?:\\{|<%|\\?\\?<|(?=;)))", + "endCaptures": { + "1": { + "name": "punctuation.section.block.begin.bracket.curly.union.cpp" + } + }, + "patterns": [ + { + "include": "#ever_present_context" + }, + { + "include": "#inheritance_context" + }, + { + "include": "#template_call_range" + } + ] + }, + { + "name": "meta.body.union.cpp", + "begin": "(?<=\\{|<%|\\?\\?<)", + "end": "(\\}|%>|\\?\\?>)", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.union.cpp" + } + }, + "patterns": [ + { + "include": "#function_pointer" + }, + { + "include": "#static_assert" + }, + { + "include": "#constructor_inline" + }, + { + "include": "#destructor_inline" + }, + { + "include": "$base" + } + ] + }, + { + "name": "meta.tail.union.cpp", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "match": "(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))){2,}\\&", + "captures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + } + }, + "name": "invalid.illegal.reference-type.cpp" + }, + { + "match": "\\&", + "name": "storage.modifier.reference.cpp" + } + ] + }, + "2": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "3": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "4": { + "name": "comment.block.cpp" + }, + "5": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "6": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "7": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "8": { + "name": "comment.block.cpp" + }, + "9": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "10": { + "patterns": [ + { + "include": "#inline_comment" + } + ] + }, + "11": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "12": { + "name": "comment.block.cpp" + }, + "13": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] + }, + "14": { + "name": "entity.name.type.alias.cpp" + } + } + }, + { + "match": "," + } + ] + } + ] } ] }, - "meta_preprocessor_undef": { - "name": "meta.preprocessor.cpp", - "begin": "^\\s*(?:((#)\\s*undef))\\b", + "macro_safe_class_block": { + "name": "meta.block.class.cpp", + "begin": "((((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(DLLEXPORT)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?\\s*((?:(?\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))(?:(?:(?:(?>\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:(?:(?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?:::))?(?:(?:(?:(?>\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:not|compl|sizeof|new|delete|not_eq|bitand|xor|bitor|and|or|throw|and_eq|xor_eq|or_eq|alignof|alignas|typeid|noexcept|noexcept|static_cast|dynamic_cast|const_cast|reinterpret_cast|while|for|do|if|else|goto|switch|try|catch|return|break|case|continue|default|NULL|true|false|nullptr|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|final|override|volatile|const|noexcept|constexpr|mutable|constexpr|consteval|private|protected|public|if|elif|else|endif|ifdef|ifndef|define|undef|include|line|error|warning|pragma|_Pragma|defined|__has_include|__has_cpp_attribute|this|template|namespace|using|operator|typedef|decltype|typename|asm|__asm__|concept|requires|export|thread_local|atomic_cancel|atomic_commit|atomic_noexcept|co_await|co_return|co_yield|import|module|reflexpr|synchronized|audit|axiom|transaction_safe|transaction_safe_dynamic)\\b)(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?![\\w<:.])))+)*))?))", "beginCaptures": { "1": { - "name": "keyword.control.directive.undef.cpp" + "name": "meta.head.class.cpp" }, - "2": { - "name": "punctuation.definition.directive.cpp" - } - }, - "end": "(?=(?://|/\\*))|(?|\\?\\?>)\\s*(;)|(;))|(?=[;>\\[\\]=]))|(?|\\?\\?>)", "endCaptures": { - "0": { - "name": "punctuation.definition.string.end.cpp" + "1": { + "name": "punctuation.section.block.end.bracket.curly.class.cpp" } }, - "name": "string.quoted.double.cpp", "patterns": [ { - "match": "\\\\u\\h{4}|\\\\U\\h{8}", - "name": "constant.character.escape.cpp" + "include": "#function_pointer" }, { - "match": "\\\\['\"?\\\\abfnrtv]", - "name": "constant.character.escape.cpp" + "include": "#static_assert" }, { - "match": "\\\\[0-7]{1,3}", - "name": "constant.character.escape.cpp" + "include": "#constructor_inline" }, { - "match": "\\\\x\\h+", - "name": "constant.character.escape.cpp" + "include": "#destructor_inline" }, { - "include": "#string_escapes_context_c" + "include": "$base" } ] }, { - "begin": "(u|u8|U|L)?R\"(?:([^ ()\\\\\\t]{0,16})|([^ ()\\\\\\t]*))\\(", - "beginCaptures": { - "0": { - "name": "punctuation.definition.string.begin.cpp" - }, - "1": { - "name": "meta.encoding.cpp" - }, - "3": { - "name": "invalid.illegal.delimiter-too-long.cpp" - } - }, - "end": "\\)\\2(\\3)\"", - "endCaptures": { - "0": { - "name": "punctuation.definition.string.end.cpp" - }, - "1": { - "name": "invalid.illegal.delimiter-too-long.cpp" + "name": "meta.tail.class.cpp", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "include": "$base" } - }, - "name": "string.quoted.double.raw.cpp" + ] } ] }, - "block": { - "begin": "{", + "macro_safe_struct_block": { + "name": "meta.block.struct.cpp", + "begin": "((((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(DLLEXPORT)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?\\s*((?:(?\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))(?:(?:(?:(?>\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:(?:(?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?:::))?(?:(?:(?:(?>\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:not|compl|sizeof|new|delete|not_eq|bitand|xor|bitor|and|or|throw|and_eq|xor_eq|or_eq|alignof|alignas|typeid|noexcept|noexcept|static_cast|dynamic_cast|const_cast|reinterpret_cast|while|for|do|if|else|goto|switch|try|catch|return|break|case|continue|default|NULL|true|false|nullptr|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|final|override|volatile|const|noexcept|constexpr|mutable|constexpr|consteval|private|protected|public|if|elif|else|endif|ifdef|ifndef|define|undef|include|line|error|warning|pragma|_Pragma|defined|__has_include|__has_cpp_attribute|this|template|namespace|using|operator|typedef|decltype|typename|asm|__asm__|concept|requires|export|thread_local|atomic_cancel|atomic_commit|atomic_noexcept|co_await|co_return|co_yield|import|module|reflexpr|synchronized|audit|axiom|transaction_safe|transaction_safe_dynamic)\\b)(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?![\\w<:.])))+)*))?))", "beginCaptures": { - "0": { - "name": "punctuation.section.block.begin.bracket.curly.cpp" - } - }, - "end": "}|(?=\\s*#\\s*(?:elif|else|endif)\\b)", - "endCaptures": { - "0": { - "name": "punctuation.section.block.end.bracket.curly.cpp" - } - }, - "name": "meta.block.cpp", - "patterns": [ - { - "include": "#block_context" - } - ] - }, - "block_context": { - "patterns": [ - { - "include": "#preprocessor_rule_enabled_block" - }, - { - "include": "#preprocessor_rule_disabled_block" - }, - { - "include": "#preprocessor_rule_conditional_block" - }, - { - "include": "#method_access" - }, - { - "include": "#member_access" + "1": { + "name": "meta.head.struct.cpp" }, - { - "include": "#function_call_c" + "3": { + "name": "storage.type.$3.cpp" }, - { - "name": "meta.initialization.cpp", - "begin": "(?x)\n(?:\n (?:\n\t(?=\\s)(?=+!]+ | \\(\\) | \\[\\]))\n)\n\\s*(\\() # opening bracket", - "beginCaptures": { - "1": { - "name": "variable.other.cpp" - }, - "2": { - "name": "punctuation.section.parens.begin.bracket.round.initialization.cpp" - } - }, - "end": "\\)", - "endCaptures": { - "0": { - "name": "punctuation.section.parens.end.bracket.round.initialization.cpp" - } - }, + "4": { "patterns": [ { - "include": "#function_call_context_c" + "include": "#attributes_context" + }, + { + "include": "#number_literal" } ] }, - { - "begin": "{", - "beginCaptures": { - "0": { - "name": "punctuation.section.block.begin.bracket.curly.cpp" - } - }, - "end": "}|(?=\\s*#\\s*(?:elif|else|endif)\\b)", - "endCaptures": { - "0": { - "name": "punctuation.section.block.end.bracket.curly.cpp" - } - }, + "5": { "patterns": [ { - "include": "#block_context" + "include": "#inline_comment" } ] }, - { - "include": "#parentheses_block" + "6": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" }, - { - "include": "$base" - } - ] - }, - "function_call_c": { - "begin": "(?x)\n(?!(?:while|for|do|if|else|switch|catch|return|typeid|alignof|alignas|sizeof|and|and_eq|bitand|bitor|compl|not|not_eq|or|or_eq|typeid|xor|xor_eq|alignof|alignas|constexpr|volatile|operator|(?:::)?new|(?:::)?delete)\\s*\\()\n(?=\n(?:[A-Za-z_][A-Za-z0-9_]*+|::)++\\s*(?-mix:(?:(?-mix:(?:<(?:[\\s<>:,\\w])*>\\s*)))?)\\( # actual name\n|\n(?:(?<=operator)(?:[-*&<>=+!]+|\\(\\)|\\[\\]))\\s*\\(\n)", - "end": "(?<=\\))(?!\\w)", - "name": "meta.function-call.cpp", - "patterns": [ - { - "include": "#function_call_context_c" - } - ] - }, - "comments_context": { - "patterns": [ - { - "captures": { - "1": { - "name": "meta.toc-list.banner.block.cpp" - } - }, - "match": "^/\\* =(\\s*.*?)\\s*= \\*/$\\n?", + "7": { "name": "comment.block.cpp" }, - { - "begin": "/\\*", - "beginCaptures": { - "0": { - "name": "punctuation.definition.comment.begin.cpp" + "8": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" } - }, - "end": "\\*/", - "endCaptures": { - "0": { - "name": "punctuation.definition.comment.end.cpp" + ] + }, + "9": { + "name": "entity.name.other.preprocessor.macro.predefined.DLLEXPORT.cpp" + }, + "10": { + "patterns": [ + { + "include": "#inline_comment" } - }, + ] + }, + "11": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "12": { "name": "comment.block.cpp" }, - { - "captures": { - "1": { - "name": "meta.toc-list.banner.line.cpp" + "13": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" } - }, - "match": "^// =(\\s*.*?)\\s*=\\s*$\\n?", - "name": "comment.line.banner.cpp" + ] }, - { - "begin": "(^[ \\t]+)?(?=//)", - "beginCaptures": { - "1": { - "name": "punctuation.whitespace.comment.leading.cpp" - } - }, - "end": "(?!\\G)", + "14": { "patterns": [ { - "begin": "//", - "beginCaptures": { - "0": { - "name": "punctuation.definition.comment.cpp" - } - }, - "end": "(?=\\n)", - "name": "comment.line.double-slash.cpp", - "patterns": [ - { - "include": "#line_continuation_character" - } - ] + "include": "#attributes_context" + }, + { + "include": "#number_literal" } ] - } - ] - }, - "disabled": { - "begin": "^\\s*#\\s*if(n?def)?\\b.*$", - "end": "^\\s*#\\s*endif\\b", - "patterns": [ - { - "include": "#disabled" }, - { - "include": "#pragma_mark" - } - ] - }, - "line_continuation_character": { - "match": "(\\\\)\\n", - "captures": { - "1": { - "name": "constant.character.escape.line-continuation.cpp" - } - } - }, - "parentheses": { - "name": "meta.parens.cpp", - "begin": "\\(", - "beginCaptures": { - "0": { - "name": "punctuation.section.parens.begin.bracket.round.cpp" - } - }, - "end": "\\)", - "endCaptures": { - "0": { - "name": "punctuation.section.parens.end.bracket.round.cpp" - } - }, - "patterns": [ - { - "include": "$base" - } - ] - }, - "parentheses_block": { - "name": "meta.parens.block.cpp", - "begin": "\\(", - "beginCaptures": { - "0": { - "name": "punctuation.section.parens.begin.bracket.round.cpp" + "15": { + "name": "entity.name.type.$3.cpp" + }, + "16": { + "name": "storage.type.modifier.final.cpp" + }, + "17": { + "name": "punctuation.separator.colon.inheritance.cpp" + }, + "18": { + "patterns": [ + { + "include": "#inheritance_context" + } + ] } }, - "end": "\\)", + "end": "(?:(?:(?<=\\}|%>|\\?\\?>)\\s*(;)|(;))|(?=[;>\\[\\]=]))|(?|\\?\\?>)", "endCaptures": { - "0": { - "name": "punctuation.definition.string.end.cpp" + "1": { + "name": "punctuation.section.block.end.bracket.curly.struct.cpp" } }, - "name": "string.quoted.single.cpp", "patterns": [ { - "include": "#string_escapes_context_c" + "include": "#function_pointer" }, { - "include": "#line_continuation_character" + "include": "#static_assert" + }, + { + "include": "#constructor_inline" + }, + { + "include": "#destructor_inline" + }, + { + "include": "$base" } ] - } - ] - }, - "string_escapes_context_c": { - "patterns": [ - { - "match": "(?x)\\\\ (\n\\\\\t\t\t |\n[abefnprtv'\"?] |\n[0-3]\\d{,2}\t |\n[4-7]\\d?\t\t|\nx[a-fA-F0-9]{,2} |\nu[a-fA-F0-9]{,4} |\nU[a-fA-F0-9]{,8} )", - "name": "constant.character.escape.cpp" - }, - { - "match": "\\\\.", - "name": "invalid.illegal.unknown-escape.cpp" }, { - "match": "(?x) %\n(\\d+\\$)?\t\t\t\t\t\t # field (argument #)\n[#0\\- +']*\t\t\t\t\t\t # flags\n[,;:_]?\t\t\t\t\t\t\t # separator character (AltiVec)\n((-?\\d+)|\\*(-?\\d+\\$)?)?\t\t # minimum field width\n(\\.((-?\\d+)|\\*(-?\\d+\\$)?)?)?\t# precision\n(hh|h|ll|l|j|t|z|q|L|vh|vl|v|hv|hl)? # length modifier\n[diouxXDOUeEfFgGaACcSspn%]\t\t # conversion type", - "name": "constant.other.placeholder.cpp" + "name": "meta.tail.struct.cpp", + "begin": "(?<=\\}|%>|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "include": "$base" + } + ] } ] }, - "vararg_ellipses": { - "match": "(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(DLLEXPORT)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))?((?:(?:(?:\\[\\[.*?\\]\\]|__attribute(?:__)?\\(\\(.*?\\)\\))|__declspec\\(.*?\\))|alignas\\(.*?\\))(?!\\)))?\\s*((?:(?\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))(?:(?:(?:(?>\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:(?:(?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?:::))?(?:(?:(?:(?>\\s+)|(?:\\/\\*)(?:(?>(?:[^\\*]|(?>\\*+)[^\\/])*)(?:(?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:not|compl|sizeof|new|delete|not_eq|bitand|xor|bitor|and|or|throw|and_eq|xor_eq|or_eq|alignof|alignas|typeid|noexcept|noexcept|static_cast|dynamic_cast|const_cast|reinterpret_cast|while|for|do|if|else|goto|switch|try|catch|return|break|case|continue|default|NULL|true|false|nullptr|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|final|override|volatile|const|noexcept|constexpr|mutable|constexpr|consteval|private|protected|public|if|elif|else|endif|ifdef|ifndef|define|undef|include|line|error|warning|pragma|_Pragma|defined|__has_include|__has_cpp_attribute|this|template|namespace|using|operator|typedef|decltype|typename|asm|__asm__|concept|requires|export|thread_local|atomic_cancel|atomic_commit|atomic_noexcept|co_await|co_return|co_yield|import|module|reflexpr|synchronized|audit|axiom|transaction_safe|transaction_safe_dynamic)\\b)(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?![\\w<:.])))+)*))?))", "beginCaptures": { - "0": { - "name": "meta.preprocessor.cpp" - }, "1": { - "name": "keyword.control.directive.conditional.cpp" + "name": "meta.head.union.cpp" }, - "2": { - "name": "punctuation.definition.directive.cpp" - } - }, - "end": "^\\s*((#)\\s*endif\\b)", - "endCaptures": { - "0": { - "name": "meta.preprocessor.cpp" + "3": { + "name": "storage.type.$3.cpp" }, - "1": { - "name": "keyword.control.directive.conditional.cpp" + "4": { + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] }, - "2": { - "name": "punctuation.definition.directive.cpp" - } - }, - "patterns": [ - { - "begin": "\\G(?=.)(?!//|/\\*(?!.*\\\\\\s*\\n))", - "end": "(?=//)|(?=/\\*(?!.*\\\\\\s*\\n))|(?|\\?\\?>)\\s*(;)|(;))|(?=[;>\\[\\]=]))|(?|\\?\\?>)", + "endCaptures": { "1": { - "name": "keyword.control.directive.conditional.cpp" - }, - "2": { - "name": "punctuation.definition.directive.cpp" + "name": "punctuation.section.block.end.bracket.curly.union.cpp" } }, - "end": "(?=//)|(?=/\\*(?!.*\\\\\\s*\\n))|(?|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "include": "$base" + } + ] } ] }, - "preprocessor_rule_conditional_line_context": { - "patterns": [ - { - "match": "(?:\\bdefined\\b\\s*$)|(?:\\bdefined\\b(?=\\s*\\(*\\s*(?:(?!defined\\b)[a-zA-Z_$][\\w$]*\\b)\\s*\\)*\\s*(?:\\n|//|/\\*|\\?|\\:|&&|\\|\\||\\\\\\s*\\n)))", - "name": "keyword.control.directive.conditional.cpp" - }, - { - "match": "\\bdefined\\b", - "name": "invalid.illegal.macro-name.cpp" - }, - { - "include": "#comments_context" + "macro_safe_enum_block": { + "name": "meta.block.enum.cpp", + "begin": "(((?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+((?]*|[^>]*+<[^>]*+>)++>\\s*)?(::))?\\s*((?|\\?\\?>)\\s*(;)|(;))|(?=[;>\\[\\]=]))|(?|\\?\\?>)", + "endCaptures": { "1": { - "name": "keyword.control.directive.conditional.cpp" - }, - "2": { - "name": "punctuation.definition.directive.cpp" + "name": "punctuation.section.block.end.bracket.curly.enum.cpp" } }, - "end": "(?=^\\s*((#)\\s*(?:elif|else|endif)\\b))", "patterns": [ { - "begin": "\\G(?=.)(?!//|/\\*(?!.*\\\\\\s*\\n))", - "end": "(?=//)|(?=/\\*(?!.*\\\\\\s*\\n))|(?|\\?\\?>)[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", "patterns": [ { - "include": "#disabled" - }, - { - "include": "#pragma_mark" + "include": "$base" } ] } ] }, - "preprocessor_rule_disabled_block": { - "begin": "^\\s*((#)\\s*if\\b)(?=\\s*\\(*\\b0+\\b\\)*\\s*(?:$|//|/\\*))", + "macro_safe_template_definition": { + "name": "meta.template.definition.cpp", + "begin": "(?)|(?)", + "endCaptures": { + "1": { + "name": "punctuation.section.angle-brackets.begin.template.call.cpp" + } + }, "patterns": [ { - "include": "#preprocessor_rule_conditional_line_context" + "include": "#template_call_context" } ] }, { - "include": "#comments_context" - }, - { - "include": "#preprocessor_rule_enabled_elif_block" - }, + "include": "#template_definition_context" + } + ] + }, + "macro_safe_block": { + "name": "meta.block.cpp", + "begin": "({)", + "beginCaptures": { + "1": { + "name": "punctuation.section.block.begin.bracket.curly.cpp" + } + }, + "end": "(}|(?=\\s*#\\s*(?:elif|else|endif)\\b))|(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))((?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()", + "beginCaptures": { + "1": { + "patterns": [ + { + "include": "#inline_comment" + } + ] }, - { - "include": "#preprocessor_rule_disabled_elif" + "2": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" }, - { - "begin": "^\\s*((#)\\s*elif\\b)", - "beginCaptures": { - "0": { - "name": "meta.preprocessor.cpp" - }, - "1": { - "name": "keyword.control.directive.conditional.cpp" - }, - "2": { - "name": "punctuation.definition.directive.cpp" - } - }, - "end": "(?=^\\s*((#)\\s*(?:elif|else|endif)\\b))", + "3": { + "name": "comment.block.cpp" + }, + "4": { "patterns": [ { - "begin": "\\G(?=.)(?!//|/\\*(?!.*\\\\\\s*\\n))", - "end": "(?=//)|(?=/\\*(?!.*\\\\\\s*\\n))|(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?:(?:(?:short|signed|unsigned|long)|(?:class|struct|union|enum))((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(((?:::)?(?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*\\s*+(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?::)*\\s*+)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\s*+((?]*|[^>]*+<[^>]*+>)++>\\s*)?(::))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?!(?:not|compl|sizeof|new|delete|not_eq|bitand|xor|bitor|and|or|throw|and_eq|xor_eq|or_eq|alignof|alignas|typeid|noexcept|noexcept|static_cast|dynamic_cast|const_cast|reinterpret_cast|while|for|do|if|else|goto|switch|try|catch|return|break|case|continue|default|NULL|true|false|nullptr|const|static|volatile|register|restrict|extern|inline|constexpr|mutable|friend|explicit|virtual|final|override|volatile|const|noexcept|constexpr|mutable|constexpr|consteval|private|protected|public|if|elif|else|endif|ifdef|ifndef|define|undef|include|line|error|warning|pragma|_Pragma|defined|__has_include|__has_cpp_attribute|this|template|namespace|using|operator|typedef|decltype|typename|asm|__asm__|concept|requires|export|thread_local|atomic_cancel|atomic_commit|atomic_noexcept|co_await|co_return|co_yield|import|module|reflexpr|synchronized|audit|axiom|transaction_safe|transaction_safe_dynamic)\\b)((?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)\\b(?:(?]*|[^>]*+<[^>]*+>)++>\\s*)?(?![\\w<:.]))(((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))?(?:(?:\\&|\\*)((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z))))*(?:\\&|\\*))?((?:(?:(?>\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(\\()(\\*)\\s*((?:(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*)?)\\s*(?:(\\[)(\\w*)(\\])\\s*)*(\\))\\s*(\\()", "beginCaptures": { - "0": { - "name": "meta.preprocessor.cpp" - }, "1": { - "name": "keyword.control.directive.conditional.cpp" + "name": "meta.qualified_type.cpp", + "patterns": [ + { + "match": "(?:class|struct|union|enum)", + "name": "storage.type.$0.cpp" + }, + { + "include": "#attributes_context" + }, + { + "include": "#function_type" + }, + { + "include": "#storage_types" + }, + { + "include": "#number_literal" + }, + { + "include": "#string_context_c" + }, + { + "include": "#comma" + }, + { + "include": "#scope_resolution_inner_generated" + }, + { + "include": "#template_call_range" + }, + { + "match": "(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U[0-9a-fA-F]{8}))*", + "name": "entity.name.type.cpp" + } + ] }, "2": { - "name": "punctuation.definition.directive.cpp" - } - }, - "end": "^\\s*((#)\\s*endif\\b)", - "endCaptures": { - "0": { - "name": "meta.preprocessor.cpp" - }, - "1": { - "name": "keyword.control.directive.conditional.cpp" + "patterns": [ + { + "include": "#attributes_context" + }, + { + "include": "#number_literal" + } + ] }, - "2": { - "name": "punctuation.definition.directive.cpp" - } - }, - "patterns": [ - { - "begin": "\\G(?=.)(?!//|/\\*(?!.*\\\\\\s*\\n))", - "end": "(?=//)|(?=/\\*(?!.*\\\\\\s*\\n))|(?=\\n)", - "name": "meta.preprocessor.cpp", + "3": { "patterns": [ { - "include": "#preprocessor_rule_conditional_line_context" + "include": "#inline_comment" } ] }, - { - "include": "#comments_context" + "4": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" }, - { - "contentName": "comment.block.preprocessor.else-branch.in-block", - "begin": "^\\s*((#)\\s*else\\b)", - "beginCaptures": { - "0": { - "name": "meta.preprocessor.cpp" - }, - "1": { - "name": "keyword.control.directive.conditional.cpp" - }, - "2": { - "name": "punctuation.definition.directive.cpp" - } - }, - "end": "(?=^\\s*((#)\\s*endif\\b))", + "5": { + "name": "comment.block.cpp" + }, + "6": { "patterns": [ { - "include": "#disabled" + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" }, { - "include": "#pragma_mark" + "match": "\\*", + "name": "comment.block.cpp" } ] }, - { - "contentName": "comment.block.preprocessor.if-branch.in-block", - "begin": "^\\s*((#)\\s*elif\\b)", - "beginCaptures": { - "0": { - "name": "meta.preprocessor.cpp" - }, - "1": { - "name": "keyword.control.directive.conditional.cpp" - }, - "2": { - "name": "punctuation.definition.directive.cpp" + "7": { + "patterns": [ + { + "include": "#inline_comment" } - }, - "end": "(?=^\\s*((#)\\s*(?:else|elif|endif)\\b))", + ] + }, + "8": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" + }, + "9": { + "name": "comment.block.cpp" + }, + "10": { "patterns": [ { - "include": "#disabled" + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" }, { - "include": "#pragma_mark" + "match": "\\*", + "name": "comment.block.cpp" } ] }, - { - "begin": "\\n", - "end": "(?=^\\s*((#)\\s*(?:else|elif|endif)\\b))", + "12": { "patterns": [ { - "include": "#block_context" + "include": "#scope_resolution_inner_generated" } ] - } - ] - }, - "preprocessor_rule_enabled_elif": { - "begin": "^\\s*((#)\\s*elif\\b)(?=\\s*\\(*\\b0*1\\b\\)*\\s*(?:$|//|/\\*))", - "beginCaptures": { - "0": { - "name": "meta.preprocessor.cpp" }, - "1": { - "name": "keyword.control.directive.conditional.cpp" + "13": { + "name": "entity.name.scope-resolution.cpp" }, - "2": { - "name": "punctuation.definition.directive.cpp" - } - }, - "end": "(?=^\\s*((#)\\s*endif\\b))", - "patterns": [ - { - "begin": "\\G(?=.)(?!//|/\\*(?!.*\\\\\\s*\\n))", - "end": "(?=//)|(?=/\\*(?!.*\\\\\\s*\\n))|(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))){2,}\\&", + "captures": { "1": { - "name": "keyword.control.directive.conditional.cpp" + "patterns": [ + { + "include": "#inline_comment" + } + ] }, "2": { - "name": "punctuation.definition.directive.cpp" - } - }, - "end": "(?=^\\s*((#)\\s*(?:else|elif|endif)\\b))", - "patterns": [ - { - "include": "#disabled" + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" }, - { - "include": "#pragma_mark" + "3": { + "name": "comment.block.cpp" + }, + "4": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" + } + ] } - ] + }, + "name": "invalid.illegal.reference-type.cpp" }, { - "include": "#block_context" + "match": "\\&", + "name": "storage.modifier.reference.cpp" } ] - } - ] - }, - "preprocessor_rule_enabled_else": { - "begin": "^\\s*((#)\\s*else\\b)", - "beginCaptures": { - "0": { - "name": "meta.preprocessor.cpp" - }, - "1": { - "name": "keyword.control.directive.conditional.cpp" - }, - "2": { - "name": "punctuation.definition.directive.cpp" - } - }, - "end": "(?=^\\s*((#)\\s*endif\\b))", - "patterns": [ - { - "include": "$base" - } - ] - }, - "preprocessor_rule_enabled_else_block": { - "begin": "^\\s*((#)\\s*else\\b)", - "beginCaptures": { - "0": { - "name": "meta.preprocessor.cpp" }, - "1": { - "name": "keyword.control.directive.conditional.cpp" + "22": { + "patterns": [ + { + "include": "#inline_comment" + } + ] }, - "2": { - "name": "punctuation.definition.directive.cpp" - } - }, - "end": "(?=^\\s*((#)\\s*endif\\b))", - "patterns": [ - { - "include": "#block_context" - } - ] - }, - "preprocessor_rule_define_line_context": { - "patterns": [ - { - "include": "#vararg_ellipses" + "23": { + "name": "comment.block.cpp punctuation.definition.comment.begin.cpp" }, - { - "match": "(?-mix:##?(?:[a-zA-Z_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U000[0-9a-fA-F]))(?:(?:[a-zA-Z0-9_]|(?:\\\\u[0-9a-fA-F]{4}|\\\\U000[0-9a-fA-F])))*(?!\\w))", - "name": "variable.other.macro.argument.cpp" + "24": { + "name": "comment.block.cpp" }, - { - "begin": "{", - "beginCaptures": { - "0": { - "name": "punctuation.section.block.begin.bracket.curly.cpp" + "25": { + "patterns": [ + { + "match": "\\*\\/", + "name": "comment.block.cpp punctuation.definition.comment.end.cpp" + }, + { + "match": "\\*", + "name": "comment.block.cpp" } - }, - "end": "}|(?=\\s*#\\s*(?:elif|else|endif)\\b)|(?=+!]+|\\(\\)|\\[\\]))\\s*\\(\n)", - "end": "(?<=\\))(?!\\w)|(?\\s+)|(\\/\\*)((?>(?:[^\\*]|(?>\\*+)[^\\/])*)((?>\\*+)\\/)))+?|(?:(?:(?:(?:\\b|(?<=\\W))|(?=\\W))|\\A)|\\Z)))(?=[{=,);]|\\n)(?!\\()|(?=+!]+|\\(\\)|\\[\\]))\n)\n\\s*(\\()", - "beginCaptures": { - "1": { - "name": "entity.name.function.cpp" - }, - "2": { - "name": "punctuation.section.arguments.begin.bracket.round.cpp" - } - }, - "end": "(\\))|(?=+!]+|\\(\\)|\\[\\]))\n)\n\\s*(\\()", - "beginCaptures": { - "1": { - "name": "entity.name.function.cpp" - }, - "2": { - "name": "punctuation.section.parameters.begin.bracket.round.cpp" - } - }, - "end": "(?-mix:\\)|:)", - "endCaptures": { - "0": { - "name": "punctuation.section.parameters.end.bracket.round.cpp" - } - }, - "patterns": [ - { - "include": "#probably_a_parameter" - }, - { - "include": "#function_context_c" - } - ] + "include": "#typedef_keyword" }, { - "begin": "\\(", - "beginCaptures": { - "0": { - "name": "punctuation.section.parens.begin.bracket.round.cpp" - } - }, - "end": "\\)", - "endCaptures": { - "0": { - "name": "punctuation.section.parens.end.bracket.round.cpp" - } - }, - "patterns": [ - { - "include": "#function_context_c" - } - ] + "include": "#standard_declares" }, { - "include": "$base" - } - ] - }, - "function_call_context_c": { - "patterns": [ + "include": "#macro_safe_class_block" + }, { - "include": "#attributes" + "include": "#macro_safe_struct_block" }, { - "include": "#comments_context" + "include": "#macro_safe_union_block" }, { - "include": "#storage_types" + "include": "#macro_safe_enum_block" }, { - "include": "#method_access" + "include": "#template_isolated_definition" }, { - "include": "#member_access" + "include": "#macro_safe_template_definition" }, { - "include": "#operators" + "include": "#access_control_keywords" }, { - "begin": "(?x)\n(?!(?:while|for|do|if|else|switch|catch|return|typeid|alignof|alignas|sizeof|and|and_eq|bitand|bitor|compl|not|not_eq|or|or_eq|typeid|xor|xor_eq|alignof|alignas)\\s*\\()\n(\n(?:new)\\s*((?-mix:(?:(?-mix:(?:<(?:[\\s<>:,\\w])*>\\s*)))?)) # actual name\n|\n(?:(?<=operator)(?:[-*&<>=+!]+|\\(\\)|\\[\\]))\n)\n\\s*(\\()", - "beginCaptures": { - "1": { - "name": "keyword.operator.wordlike.cpp memory.cpp keyword.operator.new.cpp" - }, - "2": { - "patterns": [ - { - "include": "#template_call_innards" - } - ] - }, - "3": { - "name": "punctuation.section.arguments.begin.bracket.round.cpp" - } - }, - "end": "\\)", - "endCaptures": { - "0": { - "name": "punctuation.section.arguments.end.bracket.round.cpp" - } - }, - "patterns": [ - { - "include": "#function_call_context_c" - } - ] + "include": "#macro_safe_block" }, { - "include": "#function_call" + "include": "#macro_safe_static_assert" }, { - "begin": "\\(", - "beginCaptures": { - "0": { - "name": "punctuation.section.parens.begin.bracket.round.cpp" - } - }, - "end": "\\)", - "endCaptures": { - "0": { - "name": "punctuation.section.parens.end.bracket.round.cpp" - } - }, - "patterns": [ - { - "include": "#function_call_context_c" - } - ] + "include": "#macro_safe_assembly" + }, + { + "include": "#macro_safe_function_pointer" + }, + { + "include": "#evaluation_context" }, { - "include": "#block_context" + "include": "#macro_argument" } ] } diff --git a/extensions/cpp/test/colorize-fixtures/test.cpp b/extensions/cpp/test/colorize-fixtures/test.cpp index aa18e08cc..4c38c6904 100644 --- a/extensions/cpp/test/colorize-fixtures/test.cpp +++ b/extensions/cpp/test/colorize-fixtures/test.cpp @@ -2,6 +2,8 @@ #include using namespace std; +#define EXTERN_C extern "C" + class Rectangle { int width, height; public: @@ -18,5 +20,8 @@ int main () { Rectangle rect; rect.set_values (3,4); cout << "area: " << rect.area(); + Task::links_to; + int t = 2; + if (t > 0) puts("\n*************************************************"); return 0; } \ No newline at end of file diff --git a/extensions/cpp/test/colorize-results/test_c.json b/extensions/cpp/test/colorize-results/test_c.json index 5a83a3ac6..74be734c5 100644 --- a/extensions/cpp/test/colorize-results/test_c.json +++ b/extensions/cpp/test/colorize-results/test_c.json @@ -848,7 +848,7 @@ }, { "c": "4", - "t": "source.c meta.block.c constant.numeric.c", + "t": "source.c meta.block.c constant.numeric.decimal.c", "r": { "dark_plus": "constant.numeric: #B5CEA8", "light_plus": "constant.numeric: #09885A", @@ -980,7 +980,7 @@ }, { "c": "0", - "t": "source.c meta.block.c meta.parens.block.c constant.numeric.c", + "t": "source.c meta.block.c meta.parens.block.c constant.numeric.decimal.c", "r": { "dark_plus": "constant.numeric: #B5CEA8", "light_plus": "constant.numeric: #09885A", @@ -1178,7 +1178,7 @@ }, { "c": "2", - "t": "source.c meta.block.c meta.parens.block.c constant.numeric.c", + "t": "source.c meta.block.c meta.parens.block.c constant.numeric.decimal.c", "r": { "dark_plus": "constant.numeric: #B5CEA8", "light_plus": "constant.numeric: #09885A", @@ -1387,7 +1387,7 @@ }, { "c": "2", - "t": "source.c meta.block.c meta.parens.block.c constant.numeric.c", + "t": "source.c meta.block.c meta.parens.block.c constant.numeric.decimal.c", "r": { "dark_plus": "constant.numeric: #B5CEA8", "light_plus": "constant.numeric: #09885A", @@ -1717,7 +1717,7 @@ }, { "c": "0", - "t": "source.c meta.block.c meta.parens.block.c constant.numeric.c", + "t": "source.c meta.block.c meta.parens.block.c constant.numeric.decimal.c", "r": { "dark_plus": "constant.numeric: #B5CEA8", "light_plus": "constant.numeric: #09885A", @@ -1860,7 +1860,7 @@ }, { "c": "2", - "t": "source.c meta.block.c meta.parens.block.c constant.numeric.c", + "t": "source.c meta.block.c meta.parens.block.c constant.numeric.decimal.c", "r": { "dark_plus": "constant.numeric: #B5CEA8", "light_plus": "constant.numeric: #09885A", @@ -2223,7 +2223,7 @@ }, { "c": "2", - "t": "source.c meta.block.c meta.parens.block.c constant.numeric.c", + "t": "source.c meta.block.c meta.parens.block.c constant.numeric.decimal.c", "r": { "dark_plus": "constant.numeric: #B5CEA8", "light_plus": "constant.numeric: #09885A", @@ -2388,7 +2388,7 @@ }, { "c": "2", - "t": "source.c meta.block.c meta.parens.block.c constant.numeric.c", + "t": "source.c meta.block.c meta.parens.block.c constant.numeric.decimal.c", "r": { "dark_plus": "constant.numeric: #B5CEA8", "light_plus": "constant.numeric: #09885A", @@ -2762,7 +2762,7 @@ }, { "c": "0", - "t": "source.c meta.block.c constant.numeric.c", + "t": "source.c meta.block.c constant.numeric.decimal.c", "r": { "dark_plus": "constant.numeric: #B5CEA8", "light_plus": "constant.numeric: #09885A", diff --git a/extensions/cpp/test/colorize-results/test_cc.json b/extensions/cpp/test/colorize-results/test_cc.json index e53e3ede6..4567285df 100644 --- a/extensions/cpp/test/colorize-results/test_cc.json +++ b/extensions/cpp/test/colorize-results/test_cc.json @@ -56,7 +56,7 @@ }, { "c": "fprintf", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp entity.name.function.cpp", + "t": "source.cpp entity.name.function.call.cpp", "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", @@ -67,7 +67,7 @@ }, { "c": "(", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp punctuation.section.parameters.begin.bracket.round.cpp", + "t": "source.cpp punctuation.section.arguments.begin.bracket.round.function.call.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -78,7 +78,7 @@ }, { "c": "stderr", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp", + "t": "source.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -89,7 +89,7 @@ }, { "c": ",", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp comma.cpp punctuation.separator.delimiter.cpp", + "t": "source.cpp punctuation.separator.delimiter.comma.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -100,7 +100,7 @@ }, { "c": "\"", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp string.quoted.double.cpp punctuation.definition.string.begin.cpp", + "t": "source.cpp string.quoted.double.cpp punctuation.definition.string.begin.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -111,7 +111,7 @@ }, { "c": "num_candidate_ret=", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp string.quoted.double.cpp", + "t": "source.cpp string.quoted.double.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -122,7 +122,7 @@ }, { "c": "%d", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp string.quoted.double.cpp constant.other.placeholder.cpp", + "t": "source.cpp string.quoted.double.cpp constant.other.placeholder.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -133,7 +133,7 @@ }, { "c": ":", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp string.quoted.double.cpp", + "t": "source.cpp string.quoted.double.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -144,7 +144,7 @@ }, { "c": "\"", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp string.quoted.double.cpp punctuation.definition.string.end.cpp", + "t": "source.cpp string.quoted.double.cpp punctuation.definition.string.end.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -155,7 +155,7 @@ }, { "c": ",", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp comma.cpp punctuation.separator.delimiter.cpp", + "t": "source.cpp punctuation.separator.delimiter.comma.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -166,7 +166,7 @@ }, { "c": " num_candidate", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp", + "t": "source.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -177,7 +177,7 @@ }, { "c": ")", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp punctuation.section.parameters.end.bracket.round.cpp", + "t": "source.cpp punctuation.section.arguments.end.bracket.round.function.call.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -232,7 +232,7 @@ }, { "c": "int", - "t": "source.cpp meta.parens.cpp storage.type.primitive.cpp", + "t": "source.cpp meta.parens.cpp storage.type.primitive.cpp storage.type.built-in.primitive.cpp", "r": { "dark_plus": "storage.type: #569CD6", "light_plus": "storage.type: #0000FF", @@ -375,7 +375,7 @@ }, { "c": "fprintf", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp entity.name.function.cpp", + "t": "source.cpp entity.name.function.call.cpp", "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", @@ -386,7 +386,7 @@ }, { "c": "(", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp punctuation.section.parameters.begin.bracket.round.cpp", + "t": "source.cpp punctuation.section.arguments.begin.bracket.round.function.call.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -397,7 +397,7 @@ }, { "c": "stderr", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp", + "t": "source.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -408,7 +408,7 @@ }, { "c": ",", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp comma.cpp punctuation.separator.delimiter.cpp", + "t": "source.cpp punctuation.separator.delimiter.comma.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -419,7 +419,7 @@ }, { "c": "\"", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp string.quoted.double.cpp punctuation.definition.string.begin.cpp", + "t": "source.cpp string.quoted.double.cpp punctuation.definition.string.begin.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -430,7 +430,7 @@ }, { "c": "%d", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp string.quoted.double.cpp constant.other.placeholder.cpp", + "t": "source.cpp string.quoted.double.cpp constant.other.placeholder.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -441,7 +441,7 @@ }, { "c": ",", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp string.quoted.double.cpp", + "t": "source.cpp string.quoted.double.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -452,7 +452,7 @@ }, { "c": "\"", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp string.quoted.double.cpp punctuation.definition.string.end.cpp", + "t": "source.cpp string.quoted.double.cpp punctuation.definition.string.end.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -463,7 +463,7 @@ }, { "c": ",", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp comma.cpp punctuation.separator.delimiter.cpp", + "t": "source.cpp punctuation.separator.delimiter.comma.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -474,7 +474,7 @@ }, { "c": "user_candidate", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp meta.bracket.square.access.cpp variable.other.object.cpp", + "t": "source.cpp meta.bracket.square.access.cpp variable.other.object.cpp", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -485,7 +485,7 @@ }, { "c": "[", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp meta.bracket.square.access.cpp punctuation.definition.begin.bracket.square.cpp", + "t": "source.cpp meta.bracket.square.access.cpp punctuation.definition.begin.bracket.square.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -496,7 +496,7 @@ }, { "c": "i", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp meta.bracket.square.access.cpp", + "t": "source.cpp meta.bracket.square.access.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -507,7 +507,7 @@ }, { "c": "]", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp meta.bracket.square.access.cpp punctuation.definition.end.bracket.square.cpp", + "t": "source.cpp meta.bracket.square.access.cpp punctuation.definition.end.bracket.square.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -518,7 +518,7 @@ }, { "c": ")", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp punctuation.section.parameters.end.bracket.round.cpp", + "t": "source.cpp punctuation.section.arguments.end.bracket.round.function.call.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -551,7 +551,7 @@ }, { "c": "fprintf", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp entity.name.function.cpp", + "t": "source.cpp entity.name.function.call.cpp", "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", @@ -562,7 +562,7 @@ }, { "c": "(", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp punctuation.section.parameters.begin.bracket.round.cpp", + "t": "source.cpp punctuation.section.arguments.begin.bracket.round.function.call.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -573,7 +573,7 @@ }, { "c": "stderr", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp", + "t": "source.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -584,7 +584,7 @@ }, { "c": ",", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp comma.cpp punctuation.separator.delimiter.cpp", + "t": "source.cpp punctuation.separator.delimiter.comma.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -595,7 +595,7 @@ }, { "c": "\"", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp string.quoted.double.cpp punctuation.definition.string.begin.cpp", + "t": "source.cpp string.quoted.double.cpp punctuation.definition.string.begin.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -606,7 +606,7 @@ }, { "c": ";", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp string.quoted.double.cpp", + "t": "source.cpp string.quoted.double.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -617,7 +617,7 @@ }, { "c": "\"", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp string.quoted.double.cpp punctuation.definition.string.end.cpp", + "t": "source.cpp string.quoted.double.cpp punctuation.definition.string.end.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -628,7 +628,7 @@ }, { "c": ")", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp punctuation.section.parameters.end.bracket.round.cpp", + "t": "source.cpp punctuation.section.arguments.end.bracket.round.function.call.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -672,7 +672,7 @@ }, { "c": " ", - "t": "source.cpp", + "t": "source.cpp meta.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -683,7 +683,7 @@ }, { "c": "void", - "t": "source.cpp storage.type.primitive.cpp", + "t": "source.cpp meta.function.definition.cpp meta.qualified_type.cpp storage.type.primitive.cpp storage.type.built-in.primitive.cpp", "r": { "dark_plus": "storage.type: #569CD6", "light_plus": "storage.type: #0000FF", @@ -694,7 +694,7 @@ }, { "c": " ", - "t": "source.cpp", + "t": "source.cpp meta.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -705,7 +705,7 @@ }, { "c": "main", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp entity.name.function.cpp", + "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp entity.name.function.definition.cpp", "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", @@ -716,7 +716,7 @@ }, { "c": "(", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp punctuation.section.parameters.begin.bracket.round.cpp", + "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp punctuation.section.parameters.begin.bracket.round.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -726,8 +726,19 @@ } }, { - "c": "O ", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp", + "c": "O", + "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters.cpp meta.parameter.cpp entity.name.type.parameter.cpp", + "r": { + "dark_plus": "entity.name.type: #4EC9B0", + "light_plus": "entity.name.type: #267F99", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "entity.name.type: #4EC9B0" + } + }, + { + "c": " ", + "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters.cpp meta.parameter.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -738,7 +749,7 @@ }, { "c": "obj", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp variable.parameter.cpp", + "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters.cpp meta.parameter.cpp variable.parameter.cpp", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -749,7 +760,7 @@ }, { "c": ")", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp punctuation.section.parameters.end.bracket.round.cpp", + "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp punctuation.section.parameters.end.bracket.round.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -760,7 +771,7 @@ }, { "c": " ", - "t": "source.cpp", + "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -771,7 +782,7 @@ }, { "c": "{", - "t": "source.cpp meta.block.cpp punctuation.section.block.begin.bracket.curly.cpp", + "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp punctuation.section.block.begin.bracket.curly.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -782,7 +793,7 @@ }, { "c": " ", - "t": "source.cpp meta.block.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -793,7 +804,7 @@ }, { "c": "LOG_INFO", - "t": "source.cpp meta.block.cpp meta.function-call.cpp entity.name.function.call.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp entity.name.function.call.cpp", "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", @@ -804,7 +815,7 @@ }, { "c": "(", - "t": "source.cpp meta.block.cpp meta.function-call.cpp punctuation.section.arguments.begin.bracket.round.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.section.arguments.begin.bracket.round.function.call.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -815,7 +826,7 @@ }, { "c": "\"", - "t": "source.cpp meta.block.cpp meta.function-call.cpp string.quoted.double.cpp punctuation.definition.string.begin.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp string.quoted.double.cpp punctuation.definition.string.begin.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -826,7 +837,7 @@ }, { "c": "not hilighted as string", - "t": "source.cpp meta.block.cpp meta.function-call.cpp string.quoted.double.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp string.quoted.double.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -837,7 +848,7 @@ }, { "c": "\"", - "t": "source.cpp meta.block.cpp meta.function-call.cpp string.quoted.double.cpp punctuation.definition.string.end.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp string.quoted.double.cpp punctuation.definition.string.end.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -848,7 +859,7 @@ }, { "c": ")", - "t": "source.cpp meta.block.cpp meta.function-call.cpp punctuation.section.arguments.end.bracket.round.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.section.arguments.end.bracket.round.function.call.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -859,7 +870,7 @@ }, { "c": ";", - "t": "source.cpp meta.block.cpp punctuation.terminator.statement.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.terminator.statement.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -870,7 +881,7 @@ }, { "c": " ", - "t": "source.cpp meta.block.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -881,7 +892,7 @@ }, { "c": "LOG_INFO", - "t": "source.cpp meta.block.cpp meta.function-call.cpp entity.name.function.call.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp entity.name.function.call.cpp", "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", @@ -892,7 +903,7 @@ }, { "c": "(", - "t": "source.cpp meta.block.cpp meta.function-call.cpp punctuation.section.arguments.begin.bracket.round.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.section.arguments.begin.bracket.round.function.call.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -903,7 +914,7 @@ }, { "c": "obj ", - "t": "source.cpp meta.block.cpp meta.function-call.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -914,7 +925,7 @@ }, { "c": "<<", - "t": "source.cpp meta.block.cpp meta.function-call.cpp keyword.operator.bitwise.shift.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp keyword.operator.bitwise.shift.cpp", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -925,7 +936,7 @@ }, { "c": " ", - "t": "source.cpp meta.block.cpp meta.function-call.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -936,7 +947,7 @@ }, { "c": "\"", - "t": "source.cpp meta.block.cpp meta.function-call.cpp string.quoted.double.cpp punctuation.definition.string.begin.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp string.quoted.double.cpp punctuation.definition.string.begin.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -947,7 +958,7 @@ }, { "c": ", even worse; ", - "t": "source.cpp meta.block.cpp meta.function-call.cpp string.quoted.double.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp string.quoted.double.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -958,7 +969,7 @@ }, { "c": "\"", - "t": "source.cpp meta.block.cpp meta.function-call.cpp string.quoted.double.cpp punctuation.definition.string.end.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp string.quoted.double.cpp punctuation.definition.string.end.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -969,7 +980,7 @@ }, { "c": " ", - "t": "source.cpp meta.block.cpp meta.function-call.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -980,7 +991,7 @@ }, { "c": "<<", - "t": "source.cpp meta.block.cpp meta.function-call.cpp keyword.operator.bitwise.shift.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp keyword.operator.bitwise.shift.cpp", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -991,7 +1002,7 @@ }, { "c": " ", - "t": "source.cpp meta.block.cpp meta.function-call.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1002,7 +1013,7 @@ }, { "c": "obj", - "t": "source.cpp meta.block.cpp meta.function-call.cpp variable.other.object.access.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp variable.other.object.access.cpp", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -1013,7 +1024,7 @@ }, { "c": ".", - "t": "source.cpp meta.block.cpp meta.function-call.cpp punctuation.separator.dot-access.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.separator.dot-access.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1024,7 +1035,7 @@ }, { "c": "x", - "t": "source.cpp meta.block.cpp meta.function-call.cpp variable.other.property.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp variable.other.property.cpp", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -1035,7 +1046,7 @@ }, { "c": " ", - "t": "source.cpp meta.block.cpp meta.function-call.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1046,7 +1057,7 @@ }, { "c": "<<", - "t": "source.cpp meta.block.cpp meta.function-call.cpp keyword.operator.bitwise.shift.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp keyword.operator.bitwise.shift.cpp", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -1057,7 +1068,7 @@ }, { "c": " ", - "t": "source.cpp meta.block.cpp meta.function-call.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1068,7 +1079,7 @@ }, { "c": "\"", - "t": "source.cpp meta.block.cpp meta.function-call.cpp string.quoted.double.cpp punctuation.definition.string.begin.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp string.quoted.double.cpp punctuation.definition.string.begin.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1079,7 +1090,7 @@ }, { "c": " check this out.", - "t": "source.cpp meta.block.cpp meta.function-call.cpp string.quoted.double.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp string.quoted.double.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1090,7 +1101,7 @@ }, { "c": "\"", - "t": "source.cpp meta.block.cpp meta.function-call.cpp string.quoted.double.cpp punctuation.definition.string.end.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp string.quoted.double.cpp punctuation.definition.string.end.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1101,7 +1112,7 @@ }, { "c": ")", - "t": "source.cpp meta.block.cpp meta.function-call.cpp punctuation.section.arguments.end.bracket.round.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.section.arguments.end.bracket.round.function.call.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1112,7 +1123,7 @@ }, { "c": ";", - "t": "source.cpp meta.block.cpp punctuation.terminator.statement.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.terminator.statement.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1123,18 +1134,18 @@ }, { "c": " ", - "t": "source.cpp meta.block.cpp punctuation.whitespace.comment.leading.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp comment.line.double-slash.cpp", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" } }, { "c": "//", - "t": "source.cpp meta.block.cpp comment.line.double-slash.cpp punctuation.definition.comment.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp comment.line.double-slash.cpp punctuation.definition.comment.cpp", "r": { "dark_plus": "comment: #6A9955", "light_plus": "comment: #008000", @@ -1145,7 +1156,7 @@ }, { "c": " everything from this point on is interpeted as a string literal...", - "t": "source.cpp meta.block.cpp comment.line.double-slash.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp comment.line.double-slash.cpp", "r": { "dark_plus": "comment: #6A9955", "light_plus": "comment: #008000", @@ -1156,7 +1167,7 @@ }, { "c": " O x", - "t": "source.cpp meta.block.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1167,7 +1178,7 @@ }, { "c": ";", - "t": "source.cpp meta.block.cpp punctuation.terminator.statement.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.terminator.statement.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1178,7 +1189,7 @@ }, { "c": " ", - "t": "source.cpp meta.block.cpp meta.scope-resolution.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1189,18 +1200,18 @@ }, { "c": "std", - "t": "source.cpp meta.block.cpp meta.scope-resolution.cpp entity.name.type.namespace.scope-resolution.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp entity.name.scope-resolution.cpp", "r": { - "dark_plus": "entity.name.type: #4EC9B0", - "light_plus": "entity.name.type: #267F99", + "dark_plus": "entity.name.scope-resolution: #4EC9B0", + "light_plus": "entity.name.scope-resolution: #267F99", "dark_vs": "default: #D4D4D4", "light_vs": "default: #000000", - "hc_black": "entity.name.type: #4EC9B0" + "hc_black": "entity.name.scope-resolution: #4EC9B0" } }, { "c": "::", - "t": "source.cpp meta.block.cpp meta.scope-resolution.cpp punctuation.separator.namespace.access.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1211,7 +1222,7 @@ }, { "c": "unique_ptr", - "t": "source.cpp meta.block.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1222,7 +1233,7 @@ }, { "c": "<", - "t": "source.cpp meta.block.cpp keyword.operator.comparison.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp keyword.operator.comparison.cpp", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -1233,7 +1244,7 @@ }, { "c": "O", - "t": "source.cpp meta.block.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1244,7 +1255,7 @@ }, { "c": ">", - "t": "source.cpp meta.block.cpp keyword.operator.comparison.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp keyword.operator.comparison.cpp", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -1255,7 +1266,7 @@ }, { "c": " ", - "t": "source.cpp meta.block.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1266,7 +1277,7 @@ }, { "c": "o", - "t": "source.cpp meta.block.cpp meta.function-call.cpp entity.name.function.call.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp entity.name.function.call.cpp", "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", @@ -1277,7 +1288,7 @@ }, { "c": "(", - "t": "source.cpp meta.block.cpp meta.function-call.cpp punctuation.section.arguments.begin.bracket.round.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.section.arguments.begin.bracket.round.function.call.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1288,18 +1299,18 @@ }, { "c": "new", - "t": "source.cpp meta.block.cpp meta.function-call.cpp keyword.operator.wordlike.cpp alias.cpp keyword.operator.new.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp keyword.operator.wordlike.cpp keyword.operator.new.cpp", "r": { - "dark_plus": "keyword.operator.new.cpp: #C586C0", - "light_plus": "keyword.operator.new.cpp: #AF00DB", + "dark_plus": "source.cpp keyword.operator.new: #C586C0", + "light_plus": "source.cpp keyword.operator.new: #AF00DB", "dark_vs": "keyword.operator.new: #569CD6", "light_vs": "keyword.operator.new: #0000FF", - "hc_black": "keyword.operator.new.cpp: #C586C0" + "hc_black": "source.cpp keyword.operator.new: #C586C0" } }, { "c": " O", - "t": "source.cpp meta.block.cpp meta.function-call.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1310,7 +1321,7 @@ }, { "c": ")", - "t": "source.cpp meta.block.cpp meta.function-call.cpp punctuation.section.arguments.end.bracket.round.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.section.arguments.end.bracket.round.function.call.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1321,7 +1332,7 @@ }, { "c": ";", - "t": "source.cpp meta.block.cpp punctuation.terminator.statement.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.terminator.statement.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1332,18 +1343,18 @@ }, { "c": " ", - "t": "source.cpp meta.block.cpp punctuation.whitespace.comment.leading.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp comment.line.double-slash.cpp", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" } }, { "c": "//", - "t": "source.cpp meta.block.cpp comment.line.double-slash.cpp punctuation.definition.comment.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp comment.line.double-slash.cpp punctuation.definition.comment.cpp", "r": { "dark_plus": "comment: #6A9955", "light_plus": "comment: #008000", @@ -1354,7 +1365,7 @@ }, { "c": " sadness.", - "t": "source.cpp meta.block.cpp comment.line.double-slash.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp comment.line.double-slash.cpp", "r": { "dark_plus": "comment: #6A9955", "light_plus": "comment: #008000", @@ -1365,7 +1376,7 @@ }, { "c": " ", - "t": "source.cpp meta.block.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1376,7 +1387,7 @@ }, { "c": "sprintf", - "t": "source.cpp meta.block.cpp meta.function-call.cpp entity.name.function.call.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp entity.name.function.call.cpp", "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", @@ -1387,7 +1398,7 @@ }, { "c": "(", - "t": "source.cpp meta.block.cpp meta.function-call.cpp punctuation.section.arguments.begin.bracket.round.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.section.arguments.begin.bracket.round.function.call.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1398,7 +1409,7 @@ }, { "c": "options", - "t": "source.cpp meta.block.cpp meta.function-call.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1409,7 +1420,7 @@ }, { "c": ",", - "t": "source.cpp meta.block.cpp meta.function-call.cpp comma.cpp punctuation.separator.delimiter.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.separator.delimiter.comma.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1420,7 +1431,7 @@ }, { "c": " ", - "t": "source.cpp meta.block.cpp meta.function-call.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1431,7 +1442,7 @@ }, { "c": "\"", - "t": "source.cpp meta.block.cpp meta.function-call.cpp string.quoted.double.cpp punctuation.definition.string.begin.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp string.quoted.double.cpp punctuation.definition.string.begin.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1442,7 +1453,7 @@ }, { "c": "STYLE=Keramik;TITLE=", - "t": "source.cpp meta.block.cpp meta.function-call.cpp string.quoted.double.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp string.quoted.double.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1453,7 +1464,7 @@ }, { "c": "%s", - "t": "source.cpp meta.block.cpp meta.function-call.cpp string.quoted.double.cpp constant.other.placeholder.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp string.quoted.double.cpp constant.other.placeholder.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1464,7 +1475,7 @@ }, { "c": ";THEME=", - "t": "source.cpp meta.block.cpp meta.function-call.cpp string.quoted.double.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp string.quoted.double.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1475,7 +1486,7 @@ }, { "c": "%s", - "t": "source.cpp meta.block.cpp meta.function-call.cpp string.quoted.double.cpp constant.other.placeholder.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp string.quoted.double.cpp constant.other.placeholder.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1486,7 +1497,7 @@ }, { "c": "\"", - "t": "source.cpp meta.block.cpp meta.function-call.cpp string.quoted.double.cpp punctuation.definition.string.end.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp string.quoted.double.cpp punctuation.definition.string.end.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1497,18 +1508,7 @@ }, { "c": ",", - "t": "source.cpp meta.block.cpp meta.function-call.cpp comma.cpp punctuation.separator.delimiter.cpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": " ", - "t": "source.cpp meta.block.cpp meta.function-call.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.separator.delimiter.comma.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1518,8 +1518,8 @@ } }, { - "c": "...", - "t": "source.cpp meta.block.cpp meta.function-call.cpp punctuation.vararg-ellipses.cpp", + "c": " ...", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1530,7 +1530,7 @@ }, { "c": ")", - "t": "source.cpp meta.block.cpp meta.function-call.cpp punctuation.section.arguments.end.bracket.round.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.section.arguments.end.bracket.round.function.call.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1541,7 +1541,7 @@ }, { "c": ";", - "t": "source.cpp meta.block.cpp punctuation.terminator.statement.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.terminator.statement.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1552,7 +1552,7 @@ }, { "c": "}", - "t": "source.cpp meta.block.cpp punctuation.section.block.end.bracket.curly.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.section.block.end.bracket.curly.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1563,7 +1563,7 @@ }, { "c": "int", - "t": "source.cpp storage.type.primitive.cpp", + "t": "source.cpp meta.function.definition.cpp meta.qualified_type.cpp storage.type.primitive.cpp storage.type.built-in.primitive.cpp", "r": { "dark_plus": "storage.type: #569CD6", "light_plus": "storage.type: #0000FF", @@ -1574,7 +1574,7 @@ }, { "c": " ", - "t": "source.cpp", + "t": "source.cpp meta.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1585,7 +1585,7 @@ }, { "c": "main2", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp entity.name.function.cpp", + "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp entity.name.function.definition.cpp", "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", @@ -1596,7 +1596,7 @@ }, { "c": "(", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp punctuation.section.parameters.begin.bracket.round.cpp", + "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp punctuation.section.parameters.begin.bracket.round.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1607,7 +1607,7 @@ }, { "c": ")", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp punctuation.section.parameters.end.bracket.round.cpp", + "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp punctuation.section.parameters.end.bracket.round.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1618,7 +1618,7 @@ }, { "c": " ", - "t": "source.cpp", + "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1629,7 +1629,7 @@ }, { "c": "{", - "t": "source.cpp meta.block.cpp punctuation.section.block.begin.bracket.curly.cpp", + "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp punctuation.section.block.begin.bracket.curly.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1640,7 +1640,7 @@ }, { "c": " ", - "t": "source.cpp meta.block.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1651,7 +1651,7 @@ }, { "c": "printf", - "t": "source.cpp meta.block.cpp meta.function-call.cpp entity.name.function.call.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp entity.name.function.call.cpp", "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", @@ -1662,7 +1662,7 @@ }, { "c": "(", - "t": "source.cpp meta.block.cpp meta.function-call.cpp punctuation.section.arguments.begin.bracket.round.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.section.arguments.begin.bracket.round.function.call.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1673,7 +1673,7 @@ }, { "c": "\"", - "t": "source.cpp meta.block.cpp meta.function-call.cpp string.quoted.double.cpp punctuation.definition.string.begin.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp string.quoted.double.cpp punctuation.definition.string.begin.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1684,7 +1684,7 @@ }, { "c": ";", - "t": "source.cpp meta.block.cpp meta.function-call.cpp string.quoted.double.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp string.quoted.double.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1695,7 +1695,7 @@ }, { "c": "\"", - "t": "source.cpp meta.block.cpp meta.function-call.cpp string.quoted.double.cpp punctuation.definition.string.end.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp string.quoted.double.cpp punctuation.definition.string.end.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1706,7 +1706,7 @@ }, { "c": ")", - "t": "source.cpp meta.block.cpp meta.function-call.cpp punctuation.section.arguments.end.bracket.round.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.section.arguments.end.bracket.round.function.call.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1717,7 +1717,7 @@ }, { "c": ";", - "t": "source.cpp meta.block.cpp punctuation.terminator.statement.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.terminator.statement.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1728,18 +1728,18 @@ }, { "c": " ", - "t": "source.cpp meta.block.cpp punctuation.whitespace.comment.leading.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp comment.line.double-slash.cpp", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" } }, { "c": "//", - "t": "source.cpp meta.block.cpp comment.line.double-slash.cpp punctuation.definition.comment.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp comment.line.double-slash.cpp punctuation.definition.comment.cpp", "r": { "dark_plus": "comment: #6A9955", "light_plus": "comment: #008000", @@ -1750,7 +1750,7 @@ }, { "c": " the rest of", - "t": "source.cpp meta.block.cpp comment.line.double-slash.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp comment.line.double-slash.cpp", "r": { "dark_plus": "comment: #6A9955", "light_plus": "comment: #008000", @@ -1761,7 +1761,7 @@ }, { "c": " ", - "t": "source.cpp meta.block.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1771,8 +1771,74 @@ } }, { - "c": "asm(\"movw $0x38, %ax; ltr %ax\");", - "t": "source.cpp meta.block.cpp meta.function-call.cpp", + "c": "asm", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp meta.asm.cpp storage.type.asm.cpp", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + }, + { + "c": "(", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp meta.asm.cpp punctuation.section.parens.begin.bracket.round.assembly.cpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "\"", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp meta.asm.cpp string.quoted.double.cpp punctuation.definition.string.begin.assembly.cpp", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178" + } + }, + { + "c": "movw $0x38, %ax; ltr %ax", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp meta.asm.cpp string.quoted.double.cpp meta.embedded.assembly.cpp", + "r": { + "dark_plus": "meta.embedded: #D4D4D4", + "light_plus": "meta.embedded: #000000", + "dark_vs": "meta.embedded: #D4D4D4", + "light_vs": "meta.embedded: #000000", + "hc_black": "meta.embedded: #FFFFFF" + } + }, + { + "c": "\"", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp meta.asm.cpp string.quoted.double.cpp punctuation.definition.string.end.assembly.cpp", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178" + } + }, + { + "c": ")", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp meta.asm.cpp punctuation.section.parens.end.bracket.round.assembly.cpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ";", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.terminator.statement.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1783,7 +1849,7 @@ }, { "c": " ", - "t": "source.cpp meta.block.cpp meta.function-call.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1794,7 +1860,7 @@ }, { "c": "fn", - "t": "source.cpp meta.block.cpp meta.function-call.cpp entity.name.function.call.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp entity.name.function.call.cpp", "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", @@ -1805,7 +1871,7 @@ }, { "c": "(", - "t": "source.cpp meta.block.cpp meta.function-call.cpp punctuation.section.arguments.begin.bracket.round.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.section.arguments.begin.bracket.round.function.call.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1816,7 +1882,7 @@ }, { "c": "\"", - "t": "source.cpp meta.block.cpp meta.function-call.cpp string.quoted.double.cpp punctuation.definition.string.begin.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp string.quoted.double.cpp punctuation.definition.string.begin.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1827,7 +1893,7 @@ }, { "c": "{};", - "t": "source.cpp meta.block.cpp meta.function-call.cpp string.quoted.double.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp string.quoted.double.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1838,7 +1904,7 @@ }, { "c": "\"", - "t": "source.cpp meta.block.cpp meta.function-call.cpp string.quoted.double.cpp punctuation.definition.string.end.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp string.quoted.double.cpp punctuation.definition.string.end.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1849,7 +1915,7 @@ }, { "c": ")", - "t": "source.cpp meta.block.cpp meta.function-call.cpp punctuation.section.arguments.end.bracket.round.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.section.arguments.end.bracket.round.function.call.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1860,7 +1926,7 @@ }, { "c": ";", - "t": "source.cpp meta.block.cpp punctuation.terminator.statement.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.terminator.statement.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1871,18 +1937,18 @@ }, { "c": " ", - "t": "source.cpp meta.block.cpp punctuation.whitespace.comment.leading.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp comment.line.double-slash.cpp", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" } }, { "c": "//", - "t": "source.cpp meta.block.cpp comment.line.double-slash.cpp punctuation.definition.comment.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp comment.line.double-slash.cpp punctuation.definition.comment.cpp", "r": { "dark_plus": "comment: #6A9955", "light_plus": "comment: #008000", @@ -1893,7 +1959,7 @@ }, { "c": " the rest of", - "t": "source.cpp meta.block.cpp comment.line.double-slash.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp comment.line.double-slash.cpp", "r": { "dark_plus": "comment: #6A9955", "light_plus": "comment: #008000", @@ -1904,7 +1970,7 @@ }, { "c": "}", - "t": "source.cpp meta.block.cpp punctuation.section.block.end.bracket.curly.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.section.block.end.bracket.curly.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", diff --git a/extensions/cpp/test/colorize-results/test_cpp.json b/extensions/cpp/test/colorize-results/test_cpp.json index d82030e7d..025f668b4 100644 --- a/extensions/cpp/test/colorize-results/test_cpp.json +++ b/extensions/cpp/test/colorize-results/test_cpp.json @@ -133,13 +133,13 @@ }, { "c": "std", - "t": "source.cpp meta.using-namespace.cpp entity.name.type.namespace.cpp", + "t": "source.cpp meta.using-namespace.cpp entity.name.namespace.cpp", "r": { - "dark_plus": "entity.name.type: #4EC9B0", - "light_plus": "entity.name.type: #267F99", + "dark_plus": "entity.name.namespace: #4EC9B0", + "light_plus": "entity.name.namespace: #267F99", "dark_vs": "default: #D4D4D4", "light_vs": "default: #000000", - "hc_black": "entity.name.type: #4EC9B0" + "hc_black": "entity.name.namespace: #4EC9B0" } }, { @@ -153,6 +153,116 @@ "hc_black": "default: #FFFFFF" } }, + { + "c": "#", + "t": "source.cpp meta.preprocessor.macro.cpp keyword.control.directive.define.cpp punctuation.definition.directive.cpp", + "r": { + "dark_plus": "keyword.control: #C586C0", + "light_plus": "keyword.control: #AF00DB", + "dark_vs": "keyword.control: #569CD6", + "light_vs": "keyword.control: #0000FF", + "hc_black": "keyword.control: #C586C0" + } + }, + { + "c": "define", + "t": "source.cpp meta.preprocessor.macro.cpp keyword.control.directive.define.cpp", + "r": { + "dark_plus": "keyword.control: #C586C0", + "light_plus": "keyword.control: #AF00DB", + "dark_vs": "keyword.control: #569CD6", + "light_vs": "keyword.control: #0000FF", + "hc_black": "keyword.control: #C586C0" + } + }, + { + "c": " ", + "t": "source.cpp meta.preprocessor.macro.cpp", + "r": { + "dark_plus": "meta.preprocessor: #569CD6", + "light_plus": "meta.preprocessor: #0000FF", + "dark_vs": "meta.preprocessor: #569CD6", + "light_vs": "meta.preprocessor: #0000FF", + "hc_black": "meta.preprocessor: #569CD6" + } + }, + { + "c": "EXTERN_C", + "t": "source.cpp meta.preprocessor.macro.cpp entity.name.function.preprocessor.cpp", + "r": { + "dark_plus": "entity.name.function: #DCDCAA", + "light_plus": "entity.name.function: #795E26", + "dark_vs": "meta.preprocessor: #569CD6", + "light_vs": "meta.preprocessor: #0000FF", + "hc_black": "entity.name.function: #DCDCAA" + } + }, + { + "c": " ", + "t": "source.cpp meta.preprocessor.macro.cpp meta.block.extern.cpp", + "r": { + "dark_plus": "meta.preprocessor: #569CD6", + "light_plus": "meta.preprocessor: #0000FF", + "dark_vs": "meta.preprocessor: #569CD6", + "light_vs": "meta.preprocessor: #0000FF", + "hc_black": "meta.preprocessor: #569CD6" + } + }, + { + "c": "extern", + "t": "source.cpp meta.preprocessor.macro.cpp meta.block.extern.cpp meta.head.extern.cpp storage.type.extern.cpp", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + }, + { + "c": " ", + "t": "source.cpp meta.preprocessor.macro.cpp meta.block.extern.cpp meta.head.extern.cpp", + "r": { + "dark_plus": "meta.preprocessor: #569CD6", + "light_plus": "meta.preprocessor: #0000FF", + "dark_vs": "meta.preprocessor: #569CD6", + "light_vs": "meta.preprocessor: #0000FF", + "hc_black": "meta.preprocessor: #569CD6" + } + }, + { + "c": "\"", + "t": "source.cpp meta.preprocessor.macro.cpp meta.block.extern.cpp meta.head.extern.cpp string.quoted.double.cpp punctuation.definition.string.begin.cpp", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178" + } + }, + { + "c": "C", + "t": "source.cpp meta.preprocessor.macro.cpp meta.block.extern.cpp meta.head.extern.cpp string.quoted.double.cpp", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178" + } + }, + { + "c": "\"", + "t": "source.cpp meta.preprocessor.macro.cpp meta.block.extern.cpp meta.head.extern.cpp string.quoted.double.cpp punctuation.definition.string.end.cpp", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178" + } + }, { "c": "class", "t": "source.cpp meta.block.class.cpp meta.head.class.cpp storage.type.class.cpp", @@ -221,7 +331,7 @@ }, { "c": "int", - "t": "source.cpp meta.block.class.cpp meta.body.class.cpp storage.type.primitive.cpp", + "t": "source.cpp meta.block.class.cpp meta.body.class.cpp storage.type.primitive.cpp storage.type.built-in.primitive.cpp", "r": { "dark_plus": "storage.type: #569CD6", "light_plus": "storage.type: #0000FF", @@ -243,7 +353,7 @@ }, { "c": ",", - "t": "source.cpp meta.block.class.cpp meta.body.class.cpp comma.cpp punctuation.separator.delimiter.cpp", + "t": "source.cpp meta.block.class.cpp meta.body.class.cpp punctuation.separator.delimiter.comma.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -286,8 +396,19 @@ } }, { - "c": "public:", - "t": "source.cpp meta.block.class.cpp meta.body.class.cpp storage.type.modifier.access.control.public:.cpp", + "c": "public", + "t": "source.cpp meta.block.class.cpp meta.body.class.cpp storage.type.modifier.access.control.public.cpp", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + }, + { + "c": ":", + "t": "source.cpp meta.block.class.cpp meta.body.class.cpp storage.type.modifier.access.control.public.cpp punctuation.separator.colon.access.control.cpp", "r": { "dark_plus": "storage.type: #569CD6", "light_plus": "storage.type: #0000FF", @@ -298,7 +419,7 @@ }, { "c": " ", - "t": "source.cpp meta.block.class.cpp meta.body.class.cpp", + "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -309,7 +430,7 @@ }, { "c": "void", - "t": "source.cpp meta.block.class.cpp meta.body.class.cpp storage.type.primitive.cpp", + "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.cpp meta.qualified_type.cpp storage.type.primitive.cpp storage.type.built-in.primitive.cpp", "r": { "dark_plus": "storage.type: #569CD6", "light_plus": "storage.type: #0000FF", @@ -320,7 +441,7 @@ }, { "c": " ", - "t": "source.cpp meta.block.class.cpp meta.body.class.cpp", + "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -331,7 +452,7 @@ }, { "c": "set_values", - "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp entity.name.function.cpp", + "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.cpp meta.head.function.definition.cpp entity.name.function.definition.cpp", "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", @@ -342,7 +463,7 @@ }, { "c": " ", - "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp", + "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -353,7 +474,7 @@ }, { "c": "(", - "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp punctuation.section.parameters.begin.bracket.round.cpp", + "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.cpp meta.head.function.definition.cpp punctuation.section.parameters.begin.bracket.round.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -364,7 +485,7 @@ }, { "c": "int", - "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp storage.type.primitive.cpp", + "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters.cpp meta.parameter.cpp storage.type.primitive.cpp storage.type.built-in.primitive.cpp", "r": { "dark_plus": "storage.type: #569CD6", "light_plus": "storage.type: #0000FF", @@ -375,7 +496,7 @@ }, { "c": ",", - "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp comma.cpp punctuation.separator.delimiter.cpp", + "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters.cpp meta.parameter.cpp punctuation.separator.delimiter.comma.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -386,7 +507,7 @@ }, { "c": "int", - "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp storage.type.primitive.cpp", + "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters.cpp meta.parameter.cpp storage.type.primitive.cpp storage.type.built-in.primitive.cpp", "r": { "dark_plus": "storage.type: #569CD6", "light_plus": "storage.type: #0000FF", @@ -397,7 +518,7 @@ }, { "c": ")", - "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp punctuation.section.parameters.end.bracket.round.cpp", + "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.cpp meta.head.function.definition.cpp punctuation.section.parameters.end.bracket.round.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -419,7 +540,7 @@ }, { "c": " ", - "t": "source.cpp meta.block.class.cpp meta.body.class.cpp", + "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -430,7 +551,7 @@ }, { "c": "int", - "t": "source.cpp meta.block.class.cpp meta.body.class.cpp storage.type.primitive.cpp", + "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.cpp meta.qualified_type.cpp storage.type.primitive.cpp storage.type.built-in.primitive.cpp", "r": { "dark_plus": "storage.type: #569CD6", "light_plus": "storage.type: #0000FF", @@ -441,7 +562,7 @@ }, { "c": " ", - "t": "source.cpp meta.block.class.cpp meta.body.class.cpp", + "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -452,7 +573,7 @@ }, { "c": "area", - "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp entity.name.function.cpp", + "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.cpp meta.head.function.definition.cpp entity.name.function.definition.cpp", "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", @@ -463,7 +584,7 @@ }, { "c": "(", - "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp punctuation.section.parameters.begin.bracket.round.cpp", + "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.cpp meta.head.function.definition.cpp punctuation.section.parameters.begin.bracket.round.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -474,7 +595,7 @@ }, { "c": ")", - "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp punctuation.section.parameters.end.bracket.round.cpp", + "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.cpp meta.head.function.definition.cpp punctuation.section.parameters.end.bracket.round.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -485,7 +606,7 @@ }, { "c": " ", - "t": "source.cpp meta.block.class.cpp meta.body.class.cpp", + "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.cpp meta.head.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -496,7 +617,7 @@ }, { "c": "{", - "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.block.cpp punctuation.section.block.begin.bracket.curly.cpp", + "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.cpp meta.head.function.definition.cpp punctuation.section.block.begin.bracket.curly.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -507,7 +628,7 @@ }, { "c": "return", - "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.block.cpp keyword.control.return.cpp", + "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.cpp meta.body.function.definition.cpp keyword.control.return.cpp", "r": { "dark_plus": "keyword.control: #C586C0", "light_plus": "keyword.control: #AF00DB", @@ -518,7 +639,7 @@ }, { "c": " width", - "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.block.cpp", + "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -529,7 +650,7 @@ }, { "c": "*", - "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.block.cpp keyword.operator.cpp", + "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.cpp meta.body.function.definition.cpp keyword.operator.cpp", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -540,7 +661,7 @@ }, { "c": "height", - "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.block.cpp", + "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -551,7 +672,7 @@ }, { "c": ";", - "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.block.cpp punctuation.terminator.statement.cpp", + "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.terminator.statement.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -562,7 +683,7 @@ }, { "c": "}", - "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.block.cpp punctuation.section.block.end.bracket.curly.cpp", + "t": "source.cpp meta.block.class.cpp meta.body.class.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.section.block.end.bracket.curly.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -595,7 +716,7 @@ }, { "c": "void", - "t": "source.cpp storage.type.primitive.cpp", + "t": "source.cpp meta.function.definition.cpp meta.qualified_type.cpp storage.type.primitive.cpp storage.type.built-in.primitive.cpp", "r": { "dark_plus": "storage.type: #569CD6", "light_plus": "storage.type: #0000FF", @@ -606,7 +727,7 @@ }, { "c": " ", - "t": "source.cpp meta.scope-resolution.cpp", + "t": "source.cpp meta.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -617,18 +738,18 @@ }, { "c": "Rectangle", - "t": "source.cpp meta.scope-resolution.cpp entity.name.type.namespace.scope-resolution.cpp", + "t": "source.cpp meta.function.definition.cpp entity.name.scope-resolution.function.definition.cpp", "r": { - "dark_plus": "entity.name.type: #4EC9B0", - "light_plus": "entity.name.type: #267F99", + "dark_plus": "entity.name.scope-resolution: #4EC9B0", + "light_plus": "entity.name.scope-resolution: #267F99", "dark_vs": "default: #D4D4D4", "light_vs": "default: #000000", - "hc_black": "entity.name.type: #4EC9B0" + "hc_black": "entity.name.scope-resolution: #4EC9B0" } }, { "c": "::", - "t": "source.cpp meta.scope-resolution.cpp punctuation.separator.namespace.access.cpp", + "t": "source.cpp meta.function.definition.cpp punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -639,7 +760,7 @@ }, { "c": "set_values", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp entity.name.function.cpp", + "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp entity.name.function.definition.cpp", "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", @@ -650,7 +771,7 @@ }, { "c": " ", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp", + "t": "source.cpp meta.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -661,7 +782,7 @@ }, { "c": "(", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp punctuation.section.parameters.begin.bracket.round.cpp", + "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp punctuation.section.parameters.begin.bracket.round.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -672,7 +793,7 @@ }, { "c": "int", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp storage.type.primitive.cpp", + "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters.cpp meta.parameter.cpp storage.type.primitive.cpp storage.type.built-in.primitive.cpp", "r": { "dark_plus": "storage.type: #569CD6", "light_plus": "storage.type: #0000FF", @@ -683,7 +804,7 @@ }, { "c": " ", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp", + "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters.cpp meta.parameter.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -694,7 +815,7 @@ }, { "c": "x", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp variable.parameter.cpp", + "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters.cpp meta.parameter.cpp variable.parameter.cpp", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -705,7 +826,7 @@ }, { "c": ",", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp comma.cpp punctuation.separator.delimiter.cpp", + "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters.cpp meta.parameter.cpp punctuation.separator.delimiter.comma.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -716,7 +837,7 @@ }, { "c": " ", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp", + "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters.cpp meta.parameter.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -727,7 +848,7 @@ }, { "c": "int", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp storage.type.primitive.cpp", + "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters.cpp meta.parameter.cpp storage.type.primitive.cpp storage.type.built-in.primitive.cpp", "r": { "dark_plus": "storage.type: #569CD6", "light_plus": "storage.type: #0000FF", @@ -738,7 +859,7 @@ }, { "c": " ", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp", + "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters.cpp meta.parameter.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -749,7 +870,7 @@ }, { "c": "y", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp variable.parameter.cpp", + "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp meta.function.definition.parameters.cpp meta.parameter.cpp variable.parameter.cpp", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -760,7 +881,7 @@ }, { "c": ")", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp punctuation.section.parameters.end.bracket.round.cpp", + "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp punctuation.section.parameters.end.bracket.round.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -771,7 +892,7 @@ }, { "c": " ", - "t": "source.cpp", + "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -782,7 +903,7 @@ }, { "c": "{", - "t": "source.cpp meta.block.cpp punctuation.section.block.begin.bracket.curly.cpp", + "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp punctuation.section.block.begin.bracket.curly.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -793,7 +914,7 @@ }, { "c": " width ", - "t": "source.cpp meta.block.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -804,7 +925,7 @@ }, { "c": "=", - "t": "source.cpp meta.block.cpp keyword.operator.assignment.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp keyword.operator.assignment.cpp", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -815,7 +936,7 @@ }, { "c": " x", - "t": "source.cpp meta.block.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -826,7 +947,7 @@ }, { "c": ";", - "t": "source.cpp meta.block.cpp punctuation.terminator.statement.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.terminator.statement.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -837,7 +958,7 @@ }, { "c": " height ", - "t": "source.cpp meta.block.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -848,7 +969,7 @@ }, { "c": "=", - "t": "source.cpp meta.block.cpp keyword.operator.assignment.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp keyword.operator.assignment.cpp", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -859,7 +980,7 @@ }, { "c": " y", - "t": "source.cpp meta.block.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -870,7 +991,7 @@ }, { "c": ";", - "t": "source.cpp meta.block.cpp punctuation.terminator.statement.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.terminator.statement.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -881,7 +1002,7 @@ }, { "c": "}", - "t": "source.cpp meta.block.cpp punctuation.section.block.end.bracket.curly.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.section.block.end.bracket.curly.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -892,7 +1013,7 @@ }, { "c": "int", - "t": "source.cpp storage.type.primitive.cpp", + "t": "source.cpp meta.function.definition.cpp meta.qualified_type.cpp storage.type.primitive.cpp storage.type.built-in.primitive.cpp", "r": { "dark_plus": "storage.type: #569CD6", "light_plus": "storage.type: #0000FF", @@ -903,7 +1024,7 @@ }, { "c": " ", - "t": "source.cpp", + "t": "source.cpp meta.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -914,7 +1035,7 @@ }, { "c": "main", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp entity.name.function.cpp", + "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp entity.name.function.definition.cpp", "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", @@ -925,7 +1046,7 @@ }, { "c": " ", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp", + "t": "source.cpp meta.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -936,7 +1057,7 @@ }, { "c": "(", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp punctuation.section.parameters.begin.bracket.round.cpp", + "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp punctuation.section.parameters.begin.bracket.round.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -947,7 +1068,7 @@ }, { "c": ")", - "t": "source.cpp meta.function.definition.parameters.cpp meta.function.definition.parameters.cpp punctuation.section.parameters.end.bracket.round.cpp", + "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp punctuation.section.parameters.end.bracket.round.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -958,7 +1079,7 @@ }, { "c": " ", - "t": "source.cpp", + "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -969,7 +1090,7 @@ }, { "c": "{", - "t": "source.cpp meta.block.cpp punctuation.section.block.begin.bracket.curly.cpp", + "t": "source.cpp meta.function.definition.cpp meta.head.function.definition.cpp punctuation.section.block.begin.bracket.curly.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -980,7 +1101,7 @@ }, { "c": " Rectangle rect", - "t": "source.cpp meta.block.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -991,7 +1112,7 @@ }, { "c": ";", - "t": "source.cpp meta.block.cpp punctuation.terminator.statement.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.terminator.statement.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1002,7 +1123,7 @@ }, { "c": " ", - "t": "source.cpp meta.block.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1013,7 +1134,7 @@ }, { "c": "rect", - "t": "source.cpp meta.block.cpp variable.other.object.access.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp variable.other.object.access.cpp", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -1024,7 +1145,7 @@ }, { "c": ".", - "t": "source.cpp meta.block.cpp punctuation.separator.dot-access.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.separator.dot-access.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1035,18 +1156,18 @@ }, { "c": "set_values", - "t": "source.cpp meta.block.cpp variable.other.property.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp entity.name.function.member.cpp", "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", + "dark_plus": "entity.name.function: #DCDCAA", + "light_plus": "entity.name.function: #795E26", "dark_vs": "default: #D4D4D4", "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE" + "hc_black": "entity.name.function: #DCDCAA" } }, { "c": " ", - "t": "source.cpp meta.block.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1057,7 +1178,7 @@ }, { "c": "(", - "t": "source.cpp meta.block.cpp meta.parens.block.cpp punctuation.section.parens.begin.bracket.round.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.section.arguments.begin.bracket.round.function.member.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1068,7 +1189,7 @@ }, { "c": "3", - "t": "source.cpp meta.block.cpp meta.parens.block.cpp constant.numeric.decimal.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp constant.numeric.decimal.cpp", "r": { "dark_plus": "constant.numeric: #B5CEA8", "light_plus": "constant.numeric: #09885A", @@ -1079,7 +1200,7 @@ }, { "c": ",", - "t": "source.cpp meta.block.cpp meta.parens.block.cpp comma.cpp punctuation.separator.delimiter.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.separator.delimiter.comma.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1090,7 +1211,7 @@ }, { "c": "4", - "t": "source.cpp meta.block.cpp meta.parens.block.cpp constant.numeric.decimal.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp constant.numeric.decimal.cpp", "r": { "dark_plus": "constant.numeric: #B5CEA8", "light_plus": "constant.numeric: #09885A", @@ -1101,7 +1222,7 @@ }, { "c": ")", - "t": "source.cpp meta.block.cpp meta.parens.block.cpp punctuation.section.parens.end.bracket.round.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.section.arguments.end.bracket.round.function.member.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1112,7 +1233,7 @@ }, { "c": ";", - "t": "source.cpp meta.block.cpp punctuation.terminator.statement.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.terminator.statement.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1123,7 +1244,7 @@ }, { "c": " cout ", - "t": "source.cpp meta.block.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1134,7 +1255,7 @@ }, { "c": "<<", - "t": "source.cpp meta.block.cpp keyword.operator.bitwise.shift.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp keyword.operator.bitwise.shift.cpp", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -1145,7 +1266,7 @@ }, { "c": " ", - "t": "source.cpp meta.block.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1156,7 +1277,7 @@ }, { "c": "\"", - "t": "source.cpp meta.block.cpp string.quoted.double.cpp punctuation.definition.string.begin.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp string.quoted.double.cpp punctuation.definition.string.begin.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1167,7 +1288,7 @@ }, { "c": "area: ", - "t": "source.cpp meta.block.cpp string.quoted.double.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp string.quoted.double.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1178,7 +1299,7 @@ }, { "c": "\"", - "t": "source.cpp meta.block.cpp string.quoted.double.cpp punctuation.definition.string.end.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp string.quoted.double.cpp punctuation.definition.string.end.cpp", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1189,7 +1310,7 @@ }, { "c": " ", - "t": "source.cpp meta.block.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1200,7 +1321,7 @@ }, { "c": "<<", - "t": "source.cpp meta.block.cpp keyword.operator.bitwise.shift.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp keyword.operator.bitwise.shift.cpp", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -1211,7 +1332,7 @@ }, { "c": " ", - "t": "source.cpp meta.block.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1222,7 +1343,7 @@ }, { "c": "rect", - "t": "source.cpp meta.block.cpp variable.other.object.access.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp variable.other.object.access.cpp", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -1233,7 +1354,7 @@ }, { "c": ".", - "t": "source.cpp meta.block.cpp punctuation.separator.dot-access.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.separator.dot-access.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1244,7 +1365,7 @@ }, { "c": "area", - "t": "source.cpp meta.block.cpp entity.name.function.member.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp entity.name.function.member.cpp", "r": { "dark_plus": "entity.name.function: #DCDCAA", "light_plus": "entity.name.function: #795E26", @@ -1255,7 +1376,117 @@ }, { "c": "(", - "t": "source.cpp meta.block.cpp punctuation.section.arguments.begin.bracket.round.function.member.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.section.arguments.begin.bracket.round.function.member.cpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ")", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.section.arguments.end.bracket.round.function.member.cpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ";", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.terminator.statement.cpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "Task", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp entity.name.scope-resolution.cpp", + "r": { + "dark_plus": "entity.name.scope-resolution: #4EC9B0", + "light_plus": "entity.name.scope-resolution: #267F99", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "entity.name.scope-resolution: #4EC9B0" + } + }, + { + "c": "<", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp meta.template.call.cpp meta.template.call.cpp punctuation.section.angle-brackets.begin.template.call.cpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "ANY_OUTPUT_TYPE", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp meta.template.call.cpp meta.template.call.cpp meta.qualified_type.cpp entity.name.type.cpp", + "r": { + "dark_plus": "entity.name.type: #4EC9B0", + "light_plus": "entity.name.type: #267F99", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "entity.name.type: #4EC9B0" + } + }, + { + "c": ",", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp meta.template.call.cpp meta.template.call.cpp punctuation.separator.delimiter.comma.template.argument.cpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp meta.template.call.cpp meta.template.call.cpp meta.qualified_type.cpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "ANY_INPUT_TYPE", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp meta.template.call.cpp meta.template.call.cpp meta.qualified_type.cpp entity.name.type.cpp", + "r": { + "dark_plus": "entity.name.type: #4EC9B0", + "light_plus": "entity.name.type: #267F99", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "entity.name.type: #4EC9B0" + } + }, + { + "c": ">", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp meta.template.call.cpp meta.template.call.cpp punctuation.section.angle-brackets.end.template.call.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1264,9 +1495,295 @@ "hc_black": "default: #FFFFFF" } }, + { + "c": "::", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.separator.namespace.access.cpp punctuation.separator.scope-resolution.cpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "links_to", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ";", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.terminator.statement.cpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "int", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp storage.type.primitive.cpp storage.type.built-in.primitive.cpp", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + }, + { + "c": " t ", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "=", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp keyword.operator.assignment.cpp", + "r": { + "dark_plus": "keyword.operator: #D4D4D4", + "light_plus": "keyword.operator: #000000", + "dark_vs": "keyword.operator: #D4D4D4", + "light_vs": "keyword.operator: #000000", + "hc_black": "keyword.operator: #D4D4D4" + } + }, + { + "c": " ", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "2", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp constant.numeric.decimal.cpp", + "r": { + "dark_plus": "constant.numeric: #B5CEA8", + "light_plus": "constant.numeric: #09885A", + "dark_vs": "constant.numeric: #B5CEA8", + "light_vs": "constant.numeric: #09885A", + "hc_black": "constant.numeric: #B5CEA8" + } + }, + { + "c": ";", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.terminator.statement.cpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "if", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp keyword.control.if.cpp", + "r": { + "dark_plus": "keyword.control: #C586C0", + "light_plus": "keyword.control: #AF00DB", + "dark_vs": "keyword.control: #569CD6", + "light_vs": "keyword.control: #0000FF", + "hc_black": "keyword.control: #C586C0" + } + }, + { + "c": " ", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "(", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp meta.parens.cpp punctuation.section.parens.begin.bracket.round.cpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "t ", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp meta.parens.cpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ">", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp meta.parens.cpp keyword.operator.comparison.cpp", + "r": { + "dark_plus": "keyword.operator: #D4D4D4", + "light_plus": "keyword.operator: #000000", + "dark_vs": "keyword.operator: #D4D4D4", + "light_vs": "keyword.operator: #000000", + "hc_black": "keyword.operator: #D4D4D4" + } + }, + { + "c": " ", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp meta.parens.cpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "0", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp meta.parens.cpp constant.numeric.decimal.cpp", + "r": { + "dark_plus": "constant.numeric: #B5CEA8", + "light_plus": "constant.numeric: #09885A", + "dark_vs": "constant.numeric: #B5CEA8", + "light_vs": "constant.numeric: #09885A", + "hc_black": "constant.numeric: #B5CEA8" + } + }, + { + "c": ")", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp meta.parens.cpp punctuation.section.parens.end.bracket.round.cpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "puts", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp entity.name.function.call.cpp", + "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": "(", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.section.arguments.begin.bracket.round.function.call.cpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "\"", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp string.quoted.double.cpp punctuation.definition.string.begin.cpp", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178" + } + }, + { + "c": "\\n", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp string.quoted.double.cpp constant.character.escape.cpp", + "r": { + "dark_plus": "constant.character.escape: #D7BA7D", + "light_plus": "constant.character.escape: #FF0000", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "constant.character: #569CD6" + } + }, + { + "c": "*************************************************", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp string.quoted.double.cpp", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178" + } + }, + { + "c": "\"", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp string.quoted.double.cpp punctuation.definition.string.end.cpp", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178" + } + }, { "c": ")", - "t": "source.cpp meta.block.cpp punctuation.section.arguments.end.bracket.round.function.member.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.section.arguments.end.bracket.round.function.call.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1277,7 +1794,7 @@ }, { "c": ";", - "t": "source.cpp meta.block.cpp punctuation.terminator.statement.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.terminator.statement.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1288,7 +1805,7 @@ }, { "c": " ", - "t": "source.cpp meta.block.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1299,7 +1816,7 @@ }, { "c": "return", - "t": "source.cpp meta.block.cpp keyword.control.return.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp keyword.control.return.cpp", "r": { "dark_plus": "keyword.control: #C586C0", "light_plus": "keyword.control: #AF00DB", @@ -1310,7 +1827,7 @@ }, { "c": " ", - "t": "source.cpp meta.block.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1321,7 +1838,7 @@ }, { "c": "0", - "t": "source.cpp meta.block.cpp constant.numeric.decimal.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp constant.numeric.decimal.cpp", "r": { "dark_plus": "constant.numeric: #B5CEA8", "light_plus": "constant.numeric: #09885A", @@ -1332,7 +1849,7 @@ }, { "c": ";", - "t": "source.cpp meta.block.cpp punctuation.terminator.statement.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.terminator.statement.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1343,7 +1860,7 @@ }, { "c": "}", - "t": "source.cpp meta.block.cpp punctuation.section.block.end.bracket.curly.cpp", + "t": "source.cpp meta.function.definition.cpp meta.body.function.definition.cpp punctuation.section.block.end.bracket.curly.function.definition.cpp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", diff --git a/extensions/csharp/package.json b/extensions/csharp/package.json index 3e2925282..3841eabd1 100644 --- a/extensions/csharp/package.json +++ b/extensions/csharp/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "0.10.x" }, diff --git a/extensions/css-language-features/client/src/cssMain.ts b/extensions/css-language-features/client/src/cssMain.ts index 8d8542f5a..ee8c9973d 100644 --- a/extensions/css-language-features/client/src/cssMain.ts +++ b/extensions/css-language-features/client/src/cssMain.ts @@ -9,7 +9,7 @@ import * as fs from 'fs'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); -import { languages, window, commands, ExtensionContext, Range, Position, CompletionItem, CompletionItemKind, TextEdit, SnippetString, workspace, TextDocument, SelectionRange } from 'vscode'; +import { languages, window, commands, ExtensionContext, Range, Position, CompletionItem, CompletionItemKind, TextEdit, SnippetString, workspace } from 'vscode'; import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind, Disposable } from 'vscode-languageclient'; import { getCustomDataPathsInAllWorkspaces, getCustomDataPathsFromAllExtensions } from './customData'; @@ -78,26 +78,6 @@ export function activate(context: ExtensionContext) { client.onReady().then(() => { context.subscriptions.push(initCompletionProvider()); - - documentSelector.forEach(selector => { - context.subscriptions.push(languages.registerSelectionRangeProvider(selector, { - async provideSelectionRanges(document: TextDocument, positions: Position[]): Promise { - const textDocument = client.code2ProtocolConverter.asTextDocumentIdentifier(document); - const rawResult = await client.sendRequest('$/textDocument/selectionRanges', { textDocument, positions: positions.map(client.code2ProtocolConverter.asPosition) }); - if (Array.isArray(rawResult)) { - return rawResult.map(rawSelectionRanges => { - return rawSelectionRanges.reduceRight((parent: SelectionRange | undefined, selectionRange: SelectionRange) => { - return { - range: client.protocol2CodeConverter.asRange(selectionRange.range), - parent - }; - }, undefined)!; - }); - } - return []; - } - })); - }); }); function initCompletionProvider(): Disposable { diff --git a/extensions/css-language-features/package.json b/extensions/css-language-features/package.json index 0b2e83c1d..be663d36b 100644 --- a/extensions/css-language-features/package.json +++ b/extensions/css-language-features/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "^1.29.0" }, @@ -729,14 +730,20 @@ } } } + ], + "jsonValidation": [ + { + "fileMatch": "*.css-data.json", + "url": "https://raw.githubusercontent.com/Microsoft/vscode-css-languageservice/master/docs/customData.schema.json" + } ] }, "dependencies": { - "vscode-languageclient": "^5.2.1", - "vscode-nls": "^4.0.0" + "vscode-languageclient": "^5.3.0-next.6", + "vscode-nls": "^4.1.1" }, "devDependencies": { - "@types/node": "^10.12.21", + "@types/node": "^10.14.8", "mocha": "^5.2.0" } } diff --git a/extensions/css-language-features/server/package.json b/extensions/css-language-features/server/package.json index e3fd51ae5..c6e8600d2 100644 --- a/extensions/css-language-features/server/package.json +++ b/extensions/css-language-features/server/package.json @@ -9,15 +9,15 @@ }, "main": "./out/cssServerMain", "dependencies": { - "vscode-css-languageservice": "^4.0.2-next.3", - "vscode-languageserver": "^5.3.0-next.2" + "vscode-css-languageservice": "^4.0.3-next.1", + "vscode-languageserver": "^5.3.0-next.8" }, "devDependencies": { "@types/mocha": "2.2.33", - "@types/node": "^10.12.21", - "glob": "^7.1.2", - "mocha": "^5.2.0", - "mocha-junit-reporter": "^1.17.0", + "@types/node": "^10.14.8", + "glob": "^7.1.4", + "mocha": "^6.1.4", + "mocha-junit-reporter": "^1.23.0", "mocha-multi-reporters": "^1.1.7" }, "scripts": { diff --git a/extensions/css-language-features/server/src/cssServerMain.ts b/extensions/css-language-features/server/src/cssServerMain.ts index e1c78b158..0bfd886c3 100644 --- a/extensions/css-language-features/server/src/cssServerMain.ts +++ b/extensions/css-language-features/server/src/cssServerMain.ts @@ -8,11 +8,12 @@ import { } from 'vscode-languageserver'; import URI from 'vscode-uri'; import { TextDocument, CompletionList, Position } from 'vscode-languageserver-types'; +import { stat as fsStat } from 'fs'; -import { getCSSLanguageService, getSCSSLanguageService, getLESSLanguageService, LanguageSettings, LanguageService, Stylesheet } from 'vscode-css-languageservice'; +import { getCSSLanguageService, getSCSSLanguageService, getLESSLanguageService, LanguageSettings, LanguageService, Stylesheet, FileSystemProvider, FileType } from 'vscode-css-languageservice'; import { getLanguageModelCache } from './languageModelCache'; import { getPathCompletionParticipant } from './pathCompletion'; -import { formatError, runSafe } from './utils/runner'; +import { formatError, runSafe, runSafeAsync } from './utils/runner'; import { getDocumentContext } from './utils/documentContext'; import { getDataProviders } from './customData'; @@ -32,8 +33,7 @@ process.on('unhandledRejection', (e: any) => { connection.console.error(formatError(`Unhandled exception`, e)); }); -// Create a simple text document manager. The text document manager -// supports full document sync only +// Create a text document manager. const documents: TextDocuments = new TextDocuments(); // Make the text document manager listen on the connection // for open, change and close text document events @@ -53,6 +53,45 @@ let workspaceFolders: WorkspaceFolder[]; const languageServices: { [id: string]: LanguageService } = {}; +const fileSystemProvider: FileSystemProvider = { + stat(documentUri: string) { + const filePath = URI.parse(documentUri).fsPath; + + return new Promise((c, e) => { + fsStat(filePath, (err, stats) => { + if (err) { + if (err.code === 'ENOENT') { + return c({ + type: FileType.Unknown, + ctime: -1, + mtime: -1, + size: -1 + }); + } else { + return e(err); + } + } + + let type = FileType.Unknown; + if (stats.isFile()) { + type = FileType.File; + } else if (stats.isDirectory) { + type = FileType.Directory; + } else if (stats.isSymbolicLink) { + type = FileType.SymbolicLink; + } + + c({ + type, + ctime: stats.ctime.getTime(), + mtime: stats.mtime.getTime(), + size: stats.size + }); + }); + }); + } +}; + // After the server has started the client sends an initialize request. The server receives // in the passed params the rootPath of the workspace plus the client capabilities. connection.onInitialize((params: InitializeParams): InitializeResult => { @@ -82,9 +121,9 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { scopedSettingsSupport = !!getClientCapability('workspace.configuration', false); foldingRangeLimit = getClientCapability('textDocument.foldingRange.rangeLimit', Number.MAX_VALUE); - languageServices.css = getCSSLanguageService({ customDataProviders }); - languageServices.scss = getSCSSLanguageService({ customDataProviders }); - languageServices.less = getLESSLanguageService({ customDataProviders }); + languageServices.css = getCSSLanguageService({ customDataProviders, fileSystemProvider, clientCapabilities: params.capabilities }); + languageServices.scss = getSCSSLanguageService({ customDataProviders, fileSystemProvider, clientCapabilities: params.capabilities }); + languageServices.less = getLESSLanguageService({ customDataProviders, fileSystemProvider, clientCapabilities: params.capabilities }); const capabilities: ServerCapabilities = { // Tell the client that the server works in FULL text document sync mode @@ -101,7 +140,8 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { codeActionProvider: true, renameProvider: true, colorProvider: {}, - foldingRangeProvider: true + foldingRangeProvider: true, + selectionRangeProvider: true }; return { capabilities }; }); @@ -257,13 +297,13 @@ connection.onDocumentHighlight((documentHighlightParams, token) => { }); -connection.onDocumentLinks((documentLinkParams, token) => { - return runSafe(() => { +connection.onDocumentLinks(async (documentLinkParams, token) => { + return runSafeAsync(async () => { const document = documents.get(documentLinkParams.textDocument.uri); if (document) { const documentContext = getDocumentContext(document.uri, workspaceFolders); const stylesheet = stylesheets.get(document); - return getLanguageService(document).findDocumentLinks(document, stylesheet, documentContext); + return await getLanguageService(document).findDocumentLinks2(document, stylesheet, documentContext); } return []; }, [], `Error while computing document links for ${documentLinkParams.textDocument.uri}`, token); @@ -335,7 +375,7 @@ connection.onFoldingRanges((params, token) => { }, null, `Error while computing folding ranges for ${params.textDocument.uri}`, token); }); -connection.onRequest('$/textDocument/selectionRanges', async (params, token) => { +connection.onSelectionRanges((params, token) => { return runSafe(() => { const document = documents.get(params.textDocument.uri); const positions: Position[] = params.positions; @@ -344,8 +384,8 @@ connection.onRequest('$/textDocument/selectionRanges', async (params, token) => const stylesheet = stylesheets.get(document); return getLanguageService(document).getSelectionRanges(document, positions, stylesheet); } - return Promise.resolve(null); - }, null, `Error while computing selection ranges for ${params.textDocument.uri}`, token); + return []; + }, [], `Error while computing selection ranges for ${params.textDocument.uri}`, token); }); diff --git a/extensions/css-language-features/server/src/pathCompletion.ts b/extensions/css-language-features/server/src/pathCompletion.ts index 4d988a52d..aafed82b5 100644 --- a/extensions/css-language-features/server/src/pathCompletion.ts +++ b/extensions/css-language-features/server/src/pathCompletion.ts @@ -154,10 +154,10 @@ function pathToReplaceRange(valueBeforeCursor: string, fullValue: string, fullVa const valueAfterLastSlash = fullValue.slice(lastIndexOfSlash + 1); const startPos = shiftPosition(fullValueRange.end, -valueAfterLastSlash.length); // If whitespace exists, replace until it - const whiteSpaceIndex = valueAfterLastSlash.indexOf(' '); + const whitespaceIndex = valueAfterLastSlash.indexOf(' '); let endPos; - if (whiteSpaceIndex !== -1) { - endPos = shiftPosition(startPos, whiteSpaceIndex); + if (whitespaceIndex !== -1) { + endPos = shiftPosition(startPos, whitespaceIndex); } else { endPos = fullValueRange.end; } diff --git a/extensions/css-language-features/server/src/test/links.test.ts b/extensions/css-language-features/server/src/test/links.test.ts new file mode 100644 index 000000000..bce7a11bc --- /dev/null +++ b/extensions/css-language-features/server/src/test/links.test.ts @@ -0,0 +1,79 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +import 'mocha'; +import * as assert from 'assert'; +import Uri from 'vscode-uri'; +import { resolve } from 'path'; +import { TextDocument, DocumentLink } from 'vscode-languageserver-types'; +import { WorkspaceFolder } from 'vscode-languageserver-protocol'; +import { getCSSLanguageService } from 'vscode-css-languageservice'; +import { getDocumentContext } from '../utils/documentContext'; + +export interface ItemDescription { + offset: number; + value: string; + target: string; +} + +suite('Links', () => { + const cssLanguageService = getCSSLanguageService(); + + let assertLink = function (links: DocumentLink[], expected: ItemDescription, document: TextDocument) { + let matches = links.filter(link => { + return document.offsetAt(link.range.start) === expected.offset; + }); + + assert.equal(matches.length, 1, `${expected.offset} should only existing once: Actual: ${links.map(l => document.offsetAt(l.range.start)).join(', ')}`); + let match = matches[0]; + assert.equal(document.getText(match.range), expected.value); + assert.equal(match.target, expected.target); + }; + + function assertLinks(value: string, expected: ItemDescription[], testUri: string, workspaceFolders?: WorkspaceFolder[], lang: string = 'css'): void { + const offset = value.indexOf('|'); + value = value.substr(0, offset) + value.substr(offset + 1); + + const document = TextDocument.create(testUri, lang, 0, value); + + if (!workspaceFolders) { + workspaceFolders = [{ name: 'x', uri: testUri.substr(0, testUri.lastIndexOf('/')) }]; + } + + const context = getDocumentContext(testUri, workspaceFolders); + + const stylesheet = cssLanguageService.parseStylesheet(document); + let links = cssLanguageService.findDocumentLinks(document, stylesheet, context)!; + + assert.equal(links.length, expected.length); + + for (let item of expected) { + assertLink(links, item, document); + } + } + + function getTestResource(path: string) { + return Uri.file(resolve(__dirname, '../../test/linksTestFixtures', path)).toString(); + } + + test('url links', function () { + + let testUri = getTestResource('about.css'); + let folders = [{ name: 'x', uri: getTestResource('') }]; + + assertLinks('html { background-image: url("hello.html|")', + [{ offset: 29, value: '"hello.html"', target: getTestResource('hello.html') }], testUri, folders + ); + }); + + test('node module resolving', function () { + + let testUri = getTestResource('about.css'); + let folders = [{ name: 'x', uri: getTestResource('') }]; + + assertLinks('html { background-image: url("~foo/hello.html|")', + [{ offset: 29, value: '"~foo/hello.html"', target: getTestResource('node_modules/foo/hello.html') }], testUri, folders + ); + }); +}); \ No newline at end of file diff --git a/extensions/css-language-features/server/src/utils/documentContext.ts b/extensions/css-language-features/server/src/utils/documentContext.ts index 9858ca843..494ff395e 100644 --- a/extensions/css-language-features/server/src/utils/documentContext.ts +++ b/extensions/css-language-features/server/src/utils/documentContext.ts @@ -7,6 +7,27 @@ import { DocumentContext } from 'vscode-css-languageservice'; import { endsWith, startsWith } from '../utils/strings'; import * as url from 'url'; import { WorkspaceFolder } from 'vscode-languageserver'; +import URI from 'vscode-uri'; +import { join, dirname } from 'path'; +import { existsSync } from 'fs'; + +function getModuleNameFromPath(path: string) { + // If a scoped module (starts with @) then get up until second instance of '/', otherwise get until first isntance of '/' + if (path[0] === '@') { + return path.substring(0, path.indexOf('/', path.indexOf('/') + 1)); + } + return path.substring(0, path.indexOf('/')); +} + +function resolvePathToModule(_moduleName: string, _relativeTo: string): string | undefined { + // resolve the module relative to the document. We can't use `require` here as the code is webpacked. + const documentFolder = dirname(URI.parse(_relativeTo).fsPath); + const packPath = join(documentFolder, 'node_modules', _moduleName, 'package.json'); + if (existsSync(packPath)) { + return URI.file(packPath).toString(); + } + return undefined; +} export function getDocumentContext(documentUri: string, workspaceFolders: WorkspaceFolder[]): DocumentContext { function getRootFolder(): string | undefined { @@ -32,6 +53,22 @@ export function getDocumentContext(documentUri: string, workspaceFolders: Worksp } } } + // Following [css-loader](https://github.com/webpack-contrib/css-loader#url) + // and [sass-loader's](https://github.com/webpack-contrib/sass-loader#imports) + // convention, if an import path starts with ~ then use node module resolution + // *unless* it starts with "~/" as this refers to the user's home directory. + if (ref[0] === '~' && ref[1] !== '/') { + ref = ref.substring(1); + if (startsWith(base, 'file://')) { + const moduleName = getModuleNameFromPath(ref); + const modulePath = resolvePathToModule(moduleName, base); + if (modulePath) { + const pathWithinModule = ref.substring(moduleName.length + 1); + return url.resolve(modulePath, pathWithinModule); + } + } + + } return url.resolve(base, ref); }, }; diff --git a/extensions/css-language-features/server/src/utils/runner.ts b/extensions/css-language-features/server/src/utils/runner.ts index df024167d..98a7a96f9 100644 --- a/extensions/css-language-features/server/src/utils/runner.ts +++ b/extensions/css-language-features/server/src/utils/runner.ts @@ -17,6 +17,27 @@ export function formatError(message: string, err: any): string { return message; } +export function runSafeAsync(func: () => Thenable, errorVal: T, errorMessage: string, token: CancellationToken): Thenable> { + return new Promise>((resolve) => { + setImmediate(() => { + if (token.isCancellationRequested) { + resolve(cancelValue()); + } + return func().then(result => { + if (token.isCancellationRequested) { + resolve(cancelValue()); + return; + } else { + resolve(result); + } + }, e => { + console.error(formatError(errorMessage, e)); + resolve(errorVal); + }); + }); + }); +} + export function runSafe(func: () => T, errorVal: T, errorMessage: string, token: CancellationToken): Thenable> { return new Promise>((resolve) => { setImmediate(() => { diff --git a/extensions/css-language-features/server/test/linksTestFixtures/.gitignore b/extensions/css-language-features/server/test/linksTestFixtures/.gitignore new file mode 100644 index 000000000..d591cdfd5 --- /dev/null +++ b/extensions/css-language-features/server/test/linksTestFixtures/.gitignore @@ -0,0 +1 @@ +!/node_modules \ No newline at end of file diff --git a/src/vs/base/test/node/stream/fixtures/empty.txt b/extensions/css-language-features/server/test/linksTestFixtures/node_modules/foo/package.json similarity index 100% rename from src/vs/base/test/node/stream/fixtures/empty.txt rename to extensions/css-language-features/server/test/linksTestFixtures/node_modules/foo/package.json diff --git a/extensions/css-language-features/server/yarn.lock b/extensions/css-language-features/server/yarn.lock index dbe0fa51f..d93eec392 100644 --- a/extensions/css-language-features/server/yarn.lock +++ b/extensions/css-language-features/server/yarn.lock @@ -7,16 +7,45 @@ resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.33.tgz#d79a0061ec270379f4d9e225f4096fb436669def" integrity sha1-15oAYewnA3n02eIl9AlvtDZmne8= -"@types/node@^10.12.21": - version "10.12.21" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.21.tgz#7e8a0c34cf29f4e17a36e9bd0ea72d45ba03908e" - integrity sha512-CBgLNk4o3XMnqMc0rhb6lc77IwShMEglz05deDcn2lQxyXEZivfwgYJu7SMha9V5XcrP6qZuevTHV/QrN2vjKQ== +"@types/node@^10.14.8": + version "10.14.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9" + integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw== + +ansi-colors@3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" + integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw== + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= ansi-regex@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" @@ -35,32 +64,78 @@ browser-stdout@1.3.1: resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== +camelcase@^5.0.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +chalk@^2.0.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + charenc@~0.0.1: version "0.0.2" resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc= -commander@2.15.1: - version "2.15.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" - integrity sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag== +cliui@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" + integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== + dependencies: + string-width "^2.1.1" + strip-ansi "^4.0.0" + wrap-ansi "^2.0.0" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= +cross-spawn@^6.0.0: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + crypt@~0.0.1: version "0.0.2" resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs= -debug@3.1.0, debug@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== +debug@3.2.6: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== dependencies: - ms "2.0.0" + ms "^2.1.1" debug@^2.2.0: version "2.6.9" @@ -69,25 +144,143 @@ debug@^2.2.0: dependencies: ms "2.0.0" +debug@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + +decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + +define-properties@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + diff@3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== -escape-string-regexp@1.0.5: +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + +end-of-stream@^1.1.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" + integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q== + dependencies: + once "^1.4.0" + +es-abstract@^1.5.1: + version "1.13.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.13.0.tgz#ac86145fdd5099d8dd49558ccba2eaf9b88e24e9" + integrity sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg== + dependencies: + es-to-primitive "^1.2.0" + function-bind "^1.1.1" + has "^1.0.3" + is-callable "^1.1.4" + is-regex "^1.0.4" + object-keys "^1.0.12" + +es-to-primitive@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377" + integrity sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +find-up@3.0.0, find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +flat@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.0.tgz#090bec8b05e39cba309747f1d588f04dbaf98db2" + integrity sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw== + dependencies: + is-buffer "~2.0.3" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -glob@7.1.2, glob@^7.1.2: - version "7.1.2" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" - integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ== +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +get-caller-file@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" + integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== + +get-caller-file@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-stream@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + +glob@7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" + integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.1.4: + version "7.1.4" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" + integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -106,10 +299,22 @@ has-flag@^3.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= -he@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" - integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0= +has-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" + integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= + +has@^1.0.1, has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +he@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== inflight@^1.0.4: version "1.0.6" @@ -124,16 +329,114 @@ inherits@2: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= +invert-kv@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" + integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== + is-buffer@~1.1.1: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== +is-buffer@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725" + integrity sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw== + +is-callable@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" + integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== + +is-date-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" + integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-regex@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" + integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE= + dependencies: + has "^1.0.1" + +is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= + +is-symbol@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38" + integrity sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw== + dependencies: + has-symbols "^1.0.0" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +js-yaml@3.13.1: + version "3.13.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" + integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +lcid@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" + integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA== + dependencies: + invert-kv "^2.0.0" + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + lodash@^4.16.4: version "4.17.10" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" integrity sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg== +lodash@^4.17.11: + version "4.17.11" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" + integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== + +log-symbols@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" + integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== + dependencies: + chalk "^2.0.1" + +map-age-cleaner@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" + integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w== + dependencies: + p-defer "^1.0.0" + md5@^2.1.0: version "2.2.1" resolved "https://registry.yarnpkg.com/md5/-/md5-2.2.1.tgz#53ab38d5fe3c8891ba465329ea23fac0540126f9" @@ -143,6 +446,20 @@ md5@^2.1.0: crypt "~0.0.1" is-buffer "~1.1.1" +mem@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" + integrity sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w== + dependencies: + map-age-cleaner "^0.1.1" + mimic-fn "^2.0.0" + p-is-promise "^2.0.0" + +mimic-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + minimatch@3.0.4, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" @@ -162,10 +479,10 @@ mkdirp@0.5.1, mkdirp@~0.5.1: dependencies: minimist "0.0.8" -mocha-junit-reporter@^1.17.0: - version "1.17.0" - resolved "https://registry.yarnpkg.com/mocha-junit-reporter/-/mocha-junit-reporter-1.17.0.tgz#2e5149ed40fc5d2e3ca71e42db5ab1fec9c6d85c" - integrity sha1-LlFJ7UD8XS48px5C21qx/snG2Fw= +mocha-junit-reporter@^1.23.0: + version "1.23.0" + resolved "https://registry.yarnpkg.com/mocha-junit-reporter/-/mocha-junit-reporter-1.23.0.tgz#c5ad7f10b5aa9a7cc6e169b6bf15baf2700266ca" + integrity sha512-pmpnEO4iDTmLfrT2RKqPsc5relG4crnDSGmXPuGogdda27A7kLujDNJV4EbTbXlVBCZXggN9rQYPEWMkOv4AAA== dependencies: debug "^2.2.0" md5 "^2.1.0" @@ -181,40 +498,251 @@ mocha-multi-reporters@^1.1.7: debug "^3.1.0" lodash "^4.16.4" -mocha@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.2.0.tgz#6d8ae508f59167f940f2b5b3c4a612ae50c90ae6" - integrity sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ== +mocha@^6.1.4: + version "6.1.4" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-6.1.4.tgz#e35fada242d5434a7e163d555c705f6875951640" + integrity sha512-PN8CIy4RXsIoxoFJzS4QNnCH4psUCPWc4/rPrst/ecSJJbLBkubMiyGCP2Kj/9YnWbotFqAoeXyXMucj7gwCFg== dependencies: + ansi-colors "3.2.3" browser-stdout "1.3.1" - commander "2.15.1" - debug "3.1.0" + debug "3.2.6" diff "3.5.0" escape-string-regexp "1.0.5" - glob "7.1.2" + find-up "3.0.0" + glob "7.1.3" growl "1.10.5" - he "1.1.1" + he "1.2.0" + js-yaml "3.13.1" + log-symbols "2.2.0" minimatch "3.0.4" mkdirp "0.5.1" - supports-color "5.4.0" + ms "2.1.1" + node-environment-flags "1.0.5" + object.assign "4.1.0" + strip-json-comments "2.0.1" + supports-color "6.0.0" + which "1.3.1" + wide-align "1.1.3" + yargs "13.2.2" + yargs-parser "13.0.0" + yargs-unparser "1.5.0" ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= -once@^1.3.0: +ms@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + +ms@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +node-environment-flags@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.5.tgz#fa930275f5bf5dae188d6192b24b4c8bbac3d76a" + integrity sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ== + dependencies: + object.getownpropertydescriptors "^2.0.3" + semver "^5.7.0" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= + dependencies: + path-key "^2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + +object-keys@^1.0.11, object-keys@^1.0.12: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" + integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== + dependencies: + define-properties "^1.1.2" + function-bind "^1.1.1" + has-symbols "^1.0.0" + object-keys "^1.0.11" + +object.getownpropertydescriptors@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" + integrity sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY= + dependencies: + define-properties "^1.1.2" + es-abstract "^1.5.1" + +once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= dependencies: wrappy "1" +os-locale@^3.0.0, os-locale@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" + integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== + dependencies: + execa "^1.0.0" + lcid "^2.0.0" + mem "^4.0.0" + +p-defer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" + integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + +p-is-promise@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" + integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg== + +p-limit@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.0.tgz#417c9941e6027a9abcba5092dd2904e255b5fbc2" + integrity sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ== + dependencies: + p-try "^2.0.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= + +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + +semver@^5.5.0, semver@^5.7.0: + version "5.7.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" + integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== + +set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + +signal-exit@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string-width@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + strip-ansi@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" @@ -222,57 +750,120 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" -supports-color@5.4.0: - version "5.4.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" - integrity sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w== +strip-ansi@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== dependencies: - has-flag "^3.0.0" + ansi-regex "^4.1.0" -vscode-css-languageservice@^4.0.2-next.3: - version "4.0.2-next.3" - resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-4.0.2-next.3.tgz#f81925d6037f05724d1c1fe00e8fb7fcbece72ff" - integrity sha512-Th6ESBGTdNo4CbZEeKNVBKi4DwGjafS1+05kuoH3hO5mFCKr6ttdvu4GxMHca7nGN1efv5tiZ6slO8PCN1bLNA== +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= + +strip-json-comments@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= + +supports-color@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a" + integrity sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg== dependencies: - vscode-languageserver-types "^3.14.0" - vscode-nls "^4.0.0" - -vscode-jsonrpc@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-4.0.0.tgz#a7bf74ef3254d0a0c272fab15c82128e378b3be9" - integrity sha512-perEnXQdQOJMTDFNv+UF3h1Y0z4iSiaN9jIlb0OqIYgosPCZGYh/MCUlkFtV2668PL69lRDO32hmvL2yiidUYg== + has-flag "^3.0.0" -vscode-languageserver-protocol@3.15.0-next.1: - version "3.15.0-next.1" - resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.0-next.1.tgz#1e45e224d7eef8c79b4bed75b9dcb1930d2ab8ed" - integrity sha512-LXF0d9s3vxFBxVQ4aKl/XghdEMAncGt3dh4urIYa9Is43g3MfIQL9fC44YZtP+XXOrI2rpZU8lRNN01U1V6CDg== +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== dependencies: - vscode-jsonrpc "^4.0.0" - vscode-languageserver-types "3.14.0" - -vscode-languageserver-types@3.14.0, vscode-languageserver-types@^3.14.0: - version "3.14.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.14.0.tgz#d3b5952246d30e5241592b6dde8280e03942e743" - integrity sha512-lTmS6AlAlMHOvPQemVwo3CezxBp0sNB95KNPkqp3Nxd5VFEnuG1ByM0zlRWos0zjO3ZWtkvhal0COgiV1xIA4A== + has-flag "^3.0.0" -vscode-languageserver@^5.3.0-next.2: - version "5.3.0-next.2" - resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-5.3.0-next.2.tgz#31ce4c34d68b517b400ca9e211e43f8d868b8dcc" - integrity sha512-n5onRw9naMrRHp2jnOn+ZwN1n+tTfzftWLPonjp1FWf/iCZWIlnw2TyF/Hn+SDGhLoVtoghmxhwEQaxEAfLHvw== +vscode-css-languageservice@^4.0.3-next.1: + version "4.0.3-next.1" + resolved "https://registry.yarnpkg.com/vscode-css-languageservice/-/vscode-css-languageservice-4.0.3-next.1.tgz#e89d01ce0d79b3e6c2642f5e3ad73cb8160d38d9" + integrity sha512-Zrm5TeraVUJ8vRikWhFt259dQu+WK+Ie3K5UA8BB4kqcanoM+1mcnIt8fPkTXlZLbiEWElrkJ9yuYbDNkufeBg== + dependencies: + vscode-languageserver-types "^3.15.0-next.2" + vscode-nls "^4.1.1" + vscode-uri "^2.0.3" + +vscode-jsonrpc@^4.1.0-next.2: + version "4.1.0-next.2" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-4.1.0-next.2.tgz#3bd318910a48e631742b290975386e3dae685be3" + integrity sha512-GsBLjP9DxQ42yl1mW9GEIlnSc0+R8mfzhaebwmmTPEJjezD5SPoAo3DFrIAFZha9yvQ1nzZfZlhtVpGQmgxtXg== + +vscode-languageserver-protocol@^3.15.0-next.6: + version "3.15.0-next.6" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.0-next.6.tgz#a8aeb7e7dd65da8216b386db59494cdfd3215d92" + integrity sha512-/yDpYlWyNs26mM23mT73xmOFsh1iRfgZfBdHmfAxwDKwpQKLoOSqVidtYfxlK/pD3IEKGcAVnT4WXTsguxxAMQ== dependencies: - vscode-languageserver-protocol "3.15.0-next.1" + vscode-jsonrpc "^4.1.0-next.2" + vscode-languageserver-types "^3.15.0-next.2" + +vscode-languageserver-types@^3.15.0-next.2: + version "3.15.0-next.2" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.15.0-next.2.tgz#a0601332cdaafac21931f497bb080cfb8d73f254" + integrity sha512-2JkrMWWUi2rlVLSo9OFR2PIGUzdiowEM8NgNYiwLKnXTjpwpjjIrJbNNxDik7Rv4oo9KtikcFQZKXbrKilL/MQ== + +vscode-languageserver@^5.3.0-next.8: + version "5.3.0-next.8" + resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-5.3.0-next.8.tgz#12a4adf60374dbb93e153e08bdca5525f9b2029f" + integrity sha512-6vUb96wsRfrFqndril3gct/FBCSc24OxFZ2iz7kuEuXvLaIcEVOcSZIqQK8oFN7PdbAIaa9nnIpKSy4Yd15cIw== + dependencies: + vscode-languageserver-protocol "^3.15.0-next.6" + vscode-textbuffer "^1.0.0" vscode-uri "^1.0.6" -vscode-nls@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.0.0.tgz#4001c8a6caba5cedb23a9c5ce1090395c0e44002" - integrity sha512-qCfdzcH+0LgQnBpZA53bA32kzp9rpq/f66Som577ObeuDlFIrtbEJ+A/+CCxjIh4G8dpJYNCKIsxpRAHIfsbNw== +vscode-nls@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.1.tgz#f9916b64e4947b20322defb1e676a495861f133c" + integrity sha512-4R+2UoUUU/LdnMnFjePxfLqNhBS8lrAFyX7pjb2ud/lqDkrUavFUTcG7wR0HBZFakae0Q6KLBFjMS6W93F403A== + +vscode-textbuffer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/vscode-textbuffer/-/vscode-textbuffer-1.0.0.tgz#1faee638c8e0e4131c8d5c353993a1874acda086" + integrity sha512-zPaHo4urgpwsm+PrJWfNakolRpryNja18SUip/qIIsfhuEqEIPEXMxHOlFPjvDC4JgTaimkncNW7UMXRJTY6ow== vscode-uri@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-1.0.6.tgz#6b8f141b0bbc44ad7b07e94f82f168ac7608ad4d" integrity sha512-sLI2L0uGov3wKVb9EB+vIQBl9tVP90nqRvxSoJ35vI3NjxE8jfsE5DSOhWgSunHSZmKS4OCi2jrtfxK7uyp2ww== +vscode-uri@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.0.3.tgz#25e5f37f552fbee3cec7e5f80cef8469cefc6543" + integrity sha512-4D3DI3F4uRy09WNtDGD93H9q034OHImxiIcSq664Hq1Y1AScehlP3qqZyTkX/RWxeu0MRMHGkrxYqm2qlDF/aw== + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + +which@1.3.1, which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +wide-align@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== + dependencies: + string-width "^1.0.2 || 2" + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -282,3 +873,76 @@ xml@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" integrity sha1-eLpyAgApxbyHuKgaPPzXS0ovweU= + +"y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" + integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== + +yargs-parser@13.0.0: + version "13.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.0.0.tgz#3fc44f3e76a8bdb1cc3602e860108602e5ccde8b" + integrity sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-parser@^11.1.1: + version "11.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" + integrity sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-parser@^13.0.0: + version "13.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0" + integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-unparser@1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.5.0.tgz#f2bb2a7e83cbc87bb95c8e572828a06c9add6e0d" + integrity sha512-HK25qidFTCVuj/D1VfNiEndpLIeJN78aqgR23nL3y4N0U/91cOAzqfHlF8n2BvoNDcZmJKin3ddNSvOxSr8flw== + dependencies: + flat "^4.1.0" + lodash "^4.17.11" + yargs "^12.0.5" + +yargs@13.2.2: + version "13.2.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.2.2.tgz#0c101f580ae95cea7f39d927e7770e3fdc97f993" + integrity sha512-WyEoxgyTD3w5XRpAQNYUB9ycVH/PQrToaTXdYXRdOXvEy1l19br+VJsc0vcO8PTGg5ro/l/GY7F/JMEBmI0BxA== + dependencies: + cliui "^4.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + os-locale "^3.1.0" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^13.0.0" + +yargs@^12.0.5: + version "12.0.5" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" + integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw== + dependencies: + cliui "^4.0.0" + decamelize "^1.2.0" + find-up "^3.0.0" + get-caller-file "^1.0.1" + os-locale "^3.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1 || ^4.0.0" + yargs-parser "^11.1.1" diff --git a/extensions/css-language-features/yarn.lock b/extensions/css-language-features/yarn.lock index 385d59738..48f16a42f 100644 --- a/extensions/css-language-features/yarn.lock +++ b/extensions/css-language-features/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@types/node@^10.12.21": - version "10.12.21" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.21.tgz#7e8a0c34cf29f4e17a36e9bd0ea72d45ba03908e" - integrity sha512-CBgLNk4o3XMnqMc0rhb6lc77IwShMEglz05deDcn2lQxyXEZivfwgYJu7SMha9V5XcrP6qZuevTHV/QrN2vjKQ== +"@types/node@^10.14.8": + version "10.14.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9" + integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw== balanced-match@^1.0.0: version "1.0.0" @@ -162,36 +162,36 @@ supports-color@5.4.0: dependencies: has-flag "^3.0.0" -vscode-jsonrpc@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-4.0.0.tgz#a7bf74ef3254d0a0c272fab15c82128e378b3be9" - integrity sha512-perEnXQdQOJMTDFNv+UF3h1Y0z4iSiaN9jIlb0OqIYgosPCZGYh/MCUlkFtV2668PL69lRDO32hmvL2yiidUYg== +vscode-jsonrpc@^4.1.0-next.2: + version "4.1.0-next.2" + resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-4.1.0-next.2.tgz#3bd318910a48e631742b290975386e3dae685be3" + integrity sha512-GsBLjP9DxQ42yl1mW9GEIlnSc0+R8mfzhaebwmmTPEJjezD5SPoAo3DFrIAFZha9yvQ1nzZfZlhtVpGQmgxtXg== -vscode-languageclient@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-5.2.1.tgz#7cfc83a294c409f58cfa2b910a8cfeaad0397193" - integrity sha512-7jrS/9WnV0ruqPamN1nE7qCxn0phkH5LjSgSp9h6qoJGoeAKzwKz/PF6M+iGA/aklx4GLZg1prddhEPQtuXI1Q== +vscode-languageclient@^5.3.0-next.6: + version "5.3.0-next.6" + resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-5.3.0-next.6.tgz#35e74882781158e8b111911c0953869d3df08777" + integrity sha512-DxT8+gkenjCjJV6ArcP75/AQfx6HP6m6kHIbacPCpffMeoE1YMLKj6ZixA9J87yr0fMtBmqumLmDeGe7MIF2bw== dependencies: semver "^5.5.0" - vscode-languageserver-protocol "3.14.1" + vscode-languageserver-protocol "^3.15.0-next.6" -vscode-languageserver-protocol@3.14.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.14.1.tgz#b8aab6afae2849c84a8983d39a1cf742417afe2f" - integrity sha512-IL66BLb2g20uIKog5Y2dQ0IiigW0XKrvmWiOvc0yXw80z3tMEzEnHjaGAb3ENuU7MnQqgnYJ1Cl2l9RvNgDi4g== +vscode-languageserver-protocol@^3.15.0-next.6: + version "3.15.0-next.6" + resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.0-next.6.tgz#a8aeb7e7dd65da8216b386db59494cdfd3215d92" + integrity sha512-/yDpYlWyNs26mM23mT73xmOFsh1iRfgZfBdHmfAxwDKwpQKLoOSqVidtYfxlK/pD3IEKGcAVnT4WXTsguxxAMQ== dependencies: - vscode-jsonrpc "^4.0.0" - vscode-languageserver-types "3.14.0" - -vscode-languageserver-types@3.14.0: - version "3.14.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.14.0.tgz#d3b5952246d30e5241592b6dde8280e03942e743" - integrity sha512-lTmS6AlAlMHOvPQemVwo3CezxBp0sNB95KNPkqp3Nxd5VFEnuG1ByM0zlRWos0zjO3ZWtkvhal0COgiV1xIA4A== - -vscode-nls@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.0.0.tgz#4001c8a6caba5cedb23a9c5ce1090395c0e44002" - integrity sha512-qCfdzcH+0LgQnBpZA53bA32kzp9rpq/f66Som577ObeuDlFIrtbEJ+A/+CCxjIh4G8dpJYNCKIsxpRAHIfsbNw== + vscode-jsonrpc "^4.1.0-next.2" + vscode-languageserver-types "^3.15.0-next.2" + +vscode-languageserver-types@^3.15.0-next.2: + version "3.15.0-next.2" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.15.0-next.2.tgz#a0601332cdaafac21931f497bb080cfb8d73f254" + integrity sha512-2JkrMWWUi2rlVLSo9OFR2PIGUzdiowEM8NgNYiwLKnXTjpwpjjIrJbNNxDik7Rv4oo9KtikcFQZKXbrKilL/MQ== + +vscode-nls@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.1.tgz#f9916b64e4947b20322defb1e676a495861f133c" + integrity sha512-4R+2UoUUU/LdnMnFjePxfLqNhBS8lrAFyX7pjb2ud/lqDkrUavFUTcG7wR0HBZFakae0Q6KLBFjMS6W93F403A== wrappy@1: version "1.0.2" diff --git a/extensions/css/.vscodeignore b/extensions/css/.vscodeignore index 0a622e7e3..52ebcbd68 100644 --- a/extensions/css/.vscodeignore +++ b/extensions/css/.vscodeignore @@ -1,2 +1,3 @@ test/** cgmanifest.json +.vscode \ No newline at end of file diff --git a/extensions/css/cgmanifest.json b/extensions/css/cgmanifest.json index 7b7a8d5e8..a47fef967 100644 --- a/extensions/css/cgmanifest.json +++ b/extensions/css/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "octref/language-css", "repositoryUrl": "https://github.com/octref/language-css", - "commitHash": "6d3a2d01dd67ef062030f4520dd42a5424330a3b" + "commitHash": "377734aad976be88a425aab5667784f3f71ea7e5" } }, "license": "MIT", diff --git a/extensions/css/package.json b/extensions/css/package.json index 13f737e92..117f759dd 100644 --- a/extensions/css/package.json +++ b/extensions/css/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "0.10.x" }, diff --git a/extensions/css/syntaxes/css.tmLanguage.json b/extensions/css/syntaxes/css.tmLanguage.json index a45463c8b..8dbdf1f74 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/octref/language-css/commit/6d3a2d01dd67ef062030f4520dd42a5424330a3b", + "version": "https://github.com/octref/language-css/commit/377734aad976be88a425aab5667784f3f71ea7e5", "name": "CSS", "scopeName": "source.css", "patterns": [ @@ -606,8 +606,32 @@ ] }, { - "begin": "(?i)(?=@[\\w-]+(\\s|\\(|{|;|/\\*|$))", - "end": "(?<=}|;)(?!\\G)", + "begin": "(?i)(?=@[\\w-]+[^;]+;s*$)", + "end": "(?<=;)(?!\\G)", + "patterns": [ + { + "begin": "(?i)\\G(@)[\\w-]+", + "beginCaptures": { + "0": { + "name": "keyword.control.at-rule.css" + }, + "1": { + "name": "punctuation.definition.keyword.css" + } + }, + "end": ";", + "endCaptures": { + "0": { + "name": "punctuation.terminator.rule.css" + } + }, + "name": "meta.at-rule.header.css" + } + ] + }, + { + "begin": "(?i)(?=@[\\w-]+(\\s|\\(|{|/\\*|$))", + "end": "(?<=})(?!\\G)", "patterns": [ { "begin": "(?i)\\G(@)[\\w-]+", diff --git a/extensions/debug-auto-launch/package.json b/extensions/debug-auto-launch/package.json index 7b676cfbe..b1444f044 100644 --- a/extensions/debug-auto-launch/package.json +++ b/extensions/debug-auto-launch/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "^1.5.0" }, @@ -49,6 +50,6 @@ "vscode-nls": "^4.0.0" }, "devDependencies": { - "@types/node": "8.0.33" + "@types/node": "^10.14.8" } } diff --git a/extensions/debug-auto-launch/yarn.lock b/extensions/debug-auto-launch/yarn.lock index 6767cb8d8..e6247e292 100644 --- a/extensions/debug-auto-launch/yarn.lock +++ b/extensions/debug-auto-launch/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@types/node@8.0.33": - version "8.0.33" - resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.33.tgz#1126e94374014e54478092830704f6ea89df04cd" - integrity sha512-vmCdO8Bm1ExT+FWfC9sd9r4jwqM7o97gGy2WBshkkXbf/2nLAJQUrZfIhw27yVOtLUev6kSZc4cav/46KbDd8A== +"@types/node@^10.14.8": + version "10.14.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9" + integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw== vscode-nls@^4.0.0: version "4.0.0" diff --git a/extensions/debug-server-ready/.vscodeignore b/extensions/debug-server-ready/.vscodeignore index 36e8b0714..609d4c28b 100644 --- a/extensions/debug-server-ready/.vscodeignore +++ b/extensions/debug-server-ready/.vscodeignore @@ -2,4 +2,5 @@ src/** tsconfig.json out/** extension.webpack.config.js -yarn.lock \ No newline at end of file +yarn.lock +.vscode \ No newline at end of file diff --git a/extensions/debug-server-ready/package.json b/extensions/debug-server-ready/package.json index ee66be801..cd006ce71 100644 --- a/extensions/debug-server-ready/package.json +++ b/extensions/debug-server-ready/package.json @@ -105,6 +105,6 @@ "vscode-nls": "^4.0.0" }, "devDependencies": { - "@types/node": "8.0.33" + "@types/node": "^10.14.8" } } diff --git a/extensions/debug-server-ready/src/extension.ts b/extensions/debug-server-ready/src/extension.ts index 57863fd99..64c4ccffe 100644 --- a/extensions/debug-server-ready/src/extension.ts +++ b/extensions/debug-server-ready/src/extension.ts @@ -137,8 +137,7 @@ class ServerReadyDetector extends vscode.Disposable { break; case 'debugWithChrome': - const chrome = vscode.extensions.getExtension('msjsdiag.debugger-for-chrome'); - if (chrome) { + if (vscode.env.remoteName === 'wsl' || !!vscode.extensions.getExtension('msjsdiag.debugger-for-chrome')) { vscode.debug.startDebugging(session.workspaceFolder, { type: 'chrome', name: 'Chrome Debug', @@ -147,7 +146,7 @@ class ServerReadyDetector extends vscode.Disposable { webRoot: args.webRoot || WEB_ROOT }, session); } else { - const errMsg = localize('server.ready.chrome.not.installed', "The action 'debugWithChrome' requires the '{0}'", 'Debugger for Chrome'); + const errMsg = localize('server.ready.chrome.not.installed', "The action '{0}' requires the '{1}' extension.", 'debugWithChrome', 'Debugger for Chrome'); vscode.window.showErrorMessage(errMsg, { modal: true }).then(_ => undefined); } break; diff --git a/extensions/debug-server-ready/yarn.lock b/extensions/debug-server-ready/yarn.lock index 6767cb8d8..e6247e292 100644 --- a/extensions/debug-server-ready/yarn.lock +++ b/extensions/debug-server-ready/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@types/node@8.0.33": - version "8.0.33" - resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.33.tgz#1126e94374014e54478092830704f6ea89df04cd" - integrity sha512-vmCdO8Bm1ExT+FWfC9sd9r4jwqM7o97gGy2WBshkkXbf/2nLAJQUrZfIhw27yVOtLUev6kSZc4cav/46KbDd8A== +"@types/node@^10.14.8": + version "10.14.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9" + integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw== vscode-nls@^4.0.0: version "4.0.0" diff --git a/extensions/docker/package.json b/extensions/docker/package.json index 41df24723..f5f2f795f 100644 --- a/extensions/docker/package.json +++ b/extensions/docker/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "*" }, "scripts": { "update-grammar": "node ../../build/npm/update-grammar.js moby/moby contrib/syntax/textmate/Docker.tmbundle/Syntaxes/Dockerfile.tmLanguage ./syntaxes/docker.tmLanguage.json" diff --git a/extensions/emmet/.vscode/launch.json b/extensions/emmet/.vscode/launch.json index 8a89122da..0b693f921 100644 --- a/extensions/emmet/.vscode/launch.json +++ b/extensions/emmet/.vscode/launch.json @@ -1,21 +1,31 @@ { - // Use IntelliSense to learn about possible Node.js debug attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "extensionHost", - "request": "launch", - "name": "Launch Extension", - "runtimeExecutable": "${execPath}", - "args": [ - "--extensionDevelopmentPath=${workspaceFolder}" - ], - "sourceMaps": true, - "outFiles": [ - "${workspaceFolder}/out/**/*.js" - ] - } - ] -} \ No newline at end of file + // Use IntelliSense to learn about possible Node.js debug attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "extensionHost", + "request": "launch", + "name": "Launch Extension", + "runtimeExecutable": "${execPath}", + "args": ["--extensionDevelopmentPath=${workspaceFolder}"], + "sourceMaps": true, + "outFiles": ["${workspaceFolder}/out/**/*.js"] + }, + { + "type": "extensionHost", + "request": "launch", + "name": "Launch Tests", + "runtimeExecutable": "${execPath}", + "args": [ + "--extensionDevelopmentPath=${workspaceFolder}", + "--extensionTestsPath=${workspaceFolder}/out/test", + "--disable-extensions", + "--skip-getting-started", + ], + "sourceMaps": true, + "outFiles": ["${workspaceFolder}/out/**/*.js"] + } + ] +} diff --git a/extensions/emmet/.vscodeignore b/extensions/emmet/.vscodeignore index 50d0ee883..573d91ebe 100644 --- a/extensions/emmet/.vscodeignore +++ b/extensions/emmet/.vscodeignore @@ -6,3 +6,4 @@ extension.webpack.config.js CONTRIBUTING.md cgmanifest.json yarn.lock +.vscode \ No newline at end of file diff --git a/extensions/emmet/package.json b/extensions/emmet/package.json index 9805a694c..d88c3717a 100644 --- a/extensions/emmet/package.json +++ b/extensions/emmet/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "^1.13.0" }, @@ -439,7 +440,7 @@ "deps": "yarn add vscode-emmet-helper" }, "devDependencies": { - "@types/node": "8.0.33", + "@types/node": "^10.14.8", "mocha-junit-reporter": "^1.17.0", "mocha-multi-reporters": "^1.1.7", "vscode": "1.0.1" @@ -449,6 +450,7 @@ "@emmetio/html-matcher": "^0.3.3", "@emmetio/math-expression": "^0.1.1", "image-size": "^0.5.2", - "vscode-emmet-helper": "^1.2.15" + "vscode-emmet-helper": "^1.2.15", + "vscode-html-languageservice": "^3.0.3" } } diff --git a/extensions/emmet/src/abbreviationActions.ts b/extensions/emmet/src/abbreviationActions.ts index f332aff2e..9508d3a6a 100644 --- a/extensions/emmet/src/abbreviationActions.ts +++ b/extensions/emmet/src/abbreviationActions.ts @@ -84,8 +84,8 @@ function doWrapping(individualLines: boolean, args: any) { const firstLineOfSelection = editor.document.lineAt(rangeToReplace.start).text.substr(rangeToReplace.start.character); const matches = firstLineOfSelection.match(/^(\s*)/); - const extraWhiteSpaceSelected = matches ? matches[1].length : 0; - rangeToReplace = new vscode.Range(rangeToReplace.start.line, rangeToReplace.start.character + extraWhiteSpaceSelected, rangeToReplace.end.line, rangeToReplace.end.character); + const extraWhitespaceSelected = matches ? matches[1].length : 0; + rangeToReplace = new vscode.Range(rangeToReplace.start.line, rangeToReplace.start.character + extraWhitespaceSelected, rangeToReplace.end.line, rangeToReplace.end.character); let textToWrapInPreview: string[]; let textToReplace = editor.document.getText(rangeToReplace); @@ -94,8 +94,8 @@ function doWrapping(individualLines: boolean, args: any) { } else { const wholeFirstLine = editor.document.lineAt(rangeToReplace.start).text; const otherMatches = wholeFirstLine.match(/^(\s*)/); - const preceedingWhiteSpace = otherMatches ? otherMatches[1] : ''; - textToWrapInPreview = rangeToReplace.isSingleLine ? [textToReplace] : ['\n\t' + textToReplace.split('\n' + preceedingWhiteSpace).join('\n\t') + '\n']; + const preceedingWhitespace = otherMatches ? otherMatches[1] : ''; + textToWrapInPreview = rangeToReplace.isSingleLine ? [textToReplace] : ['\n\t' + textToReplace.split('\n' + preceedingWhitespace).join('\n\t') + '\n']; } textToWrapInPreview = textToWrapInPreview.map(e => e.replace(/(\$\d)/g, '\\$1')); @@ -491,7 +491,7 @@ export function isValidLocationForEmmetAbbreviation(document: vscode.TextDocumen } let valid = true; - let foundSpace = false; // If < is found before finding whitespace, then its valid abbreviation. Eg: | undefined { const completionResult = this.provideCompletionItemsInternal(document, position, context); if (!completionResult) { @@ -76,20 +79,55 @@ export class DefaultCompletionItemProvider implements vscode.CompletionItemProvi } if (validateLocation) { - rootNode = parseDocument(document, false); - currentNode = getNode(rootNode, position, true); - if (isStyleAttribute(currentNode, position)) { + const lsDoc = TextDocument.create(document.uri.toString(), 'html', 0, document.getText()); + const parsedLsDoc = this.htmlLS.parseHTMLDocument(lsDoc); + const positionOffset = document.offsetAt(position); + const node = parsedLsDoc.findNodeAt(positionOffset); + + if (node.tag === 'script') { + if (node.attributes && 'type' in node.attributes) { + const rawTypeAttrValue = node.attributes['type']; + if (rawTypeAttrValue) { + const typeAttrValue = trimQuotes(rawTypeAttrValue); + if (typeAttrValue === 'application/javascript' || typeAttrValue === 'text/javascript') { + if (!getSyntaxFromArgs({ language: 'javascript' })) { + return; + } else { + validateLocation = false; + } + } + + else if (allowedMimeTypesInScriptTag.indexOf(trimQuotes(rawTypeAttrValue)) > -1) { + validateLocation = false; + } + } + } else { + return; + } + } + else if (node.tag === 'style') { syntax = 'css'; validateLocation = false; } else { - const embeddedCssNode = getEmbeddedCssNodeIfAny(document, currentNode, position); - if (embeddedCssNode) { - currentNode = getNode(embeddedCssNode, position, true); - syntax = 'css'; + if (node.attributes && node.attributes['style']) { + const scanner = this.htmlLS.createScanner(document.getText(), node.start); + let tokenType = scanner.scan(); + let prevAttr = undefined; + while (tokenType !== TokenType.EOS && (scanner.getTokenEnd() <= positionOffset)) { + tokenType = scanner.scan(); + if (tokenType === TokenType.AttributeName) { + prevAttr = scanner.getTokenText(); + } + } + if (prevAttr === 'style') { + syntax = 'css'; + validateLocation = false; + } } } } + } const extractAbbreviationResults = helper.extractAbbreviation(document, position, !isStyleSheet(syntax)); @@ -158,4 +196,4 @@ export class DefaultCompletionItemProvider implements vscode.CompletionItemProvi return new vscode.CompletionList(newItems, true); }); } -} \ No newline at end of file +} diff --git a/extensions/emmet/src/test/abbreviationAction.test.ts b/extensions/emmet/src/test/abbreviationAction.test.ts index 0a99bae18..31f468919 100644 --- a/extensions/emmet/src/test/abbreviationAction.test.ts +++ b/extensions/emmet/src/test/abbreviationAction.test.ts @@ -264,16 +264,6 @@ suite('Tests for Expand Abbreviations (HTML)', () => { }); }); - test('No expanding text in completion list inside style tag if position is not for property name (HTML)', () => { - return withRandomFileEditor(htmlContents, 'html', (editor, _doc) => { - editor.selection = new Selection(13, 14, 13, 14); - const cancelSrc = new CancellationTokenSource(); - const completionPromise = completionProvider.provideCompletionItems(editor.document, editor.selection.active, cancelSrc.token, { triggerKind: CompletionTriggerKind.Invoke }); - assert.equal(!completionPromise, true, `Got unexpected comapletion promise instead of undefined`); - return Promise.resolve(); - }); - }); - test('Expand css when inside style attribute (HTML)', () => { const styleAttributeContent = '
'; return withRandomFileEditor(styleAttributeContent, 'html', async (editor, _doc) => { diff --git a/extensions/emmet/src/util.ts b/extensions/emmet/src/util.ts index c90ff7f5c..b62812728 100644 --- a/extensions/emmet/src/util.ts +++ b/extensions/emmet/src/util.ts @@ -95,7 +95,7 @@ export function getMappingForIncludedLanguages(): any { /** * Get the corresponding emmet mode for given vscode language mode -* Eg: jsx for typescriptreact/javascriptreact or pug for jade +* E.g.: jsx for typescriptreact/javascriptreact or pug for jade * If the language is not supported by emmet or has been excluded via `excludeLanguages` setting, * then nothing is returned * @@ -608,3 +608,18 @@ export function isStyleAttribute(currentNode: Node | null, position: vscode.Posi } +export function trimQuotes(s: string) { + if (s.length <= 1) { + return s.replace(/['"]/, ''); + } + + if (s[0] === `'` || s[0] === `"`) { + s = s.slice(1); + } + + if (s[s.length - 1] === `'` || s[s.length - 1] === `"`) { + s = s.slice(0, -1); + } + + return s; +} \ No newline at end of file diff --git a/extensions/emmet/yarn.lock b/extensions/emmet/yarn.lock index 1fb4a9aff..7b22c5334 100644 --- a/extensions/emmet/yarn.lock +++ b/extensions/emmet/yarn.lock @@ -40,10 +40,10 @@ resolved "https://registry.yarnpkg.com/@emmetio/stream-reader/-/stream-reader-2.2.0.tgz#46cffea119a0a003312a21c2d9b5628cb5fcd442" integrity sha1-Rs/+oRmgoAMxKiHC2bVijLX81EI= -"@types/node@8.0.33": - version "8.0.33" - resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.33.tgz#1126e94374014e54478092830704f6ea89df04cd" - integrity sha512-vmCdO8Bm1ExT+FWfC9sd9r4jwqM7o97gGy2WBshkkXbf/2nLAJQUrZfIhw27yVOtLUev6kSZc4cav/46KbDd8A== +"@types/node@^10.14.8": + version "10.14.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9" + integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw== ajv@^5.1.0: version "5.3.0" @@ -2478,11 +2478,35 @@ vscode-emmet-helper@^1.2.15: jsonc-parser "^1.0.0" vscode-languageserver-types "^3.6.0-next.1" +vscode-html-languageservice@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/vscode-html-languageservice/-/vscode-html-languageservice-3.0.3.tgz#0aeae18a59000e317447ea34965f72680a2140ef" + integrity sha512-U+upM3gHp3HaF3wXAnUduA6IDKcz6frWS/dTAju3cZVIyZwOLBBFElQVlLH0ycHyMzqUFrjvdv+kEyPAEWfQ/g== + dependencies: + vscode-languageserver-types "^3.15.0-next.2" + vscode-nls "^4.1.1" + vscode-uri "^2.0.3" + +vscode-languageserver-types@^3.15.0-next.2: + version "3.15.0-next.2" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.15.0-next.2.tgz#a0601332cdaafac21931f497bb080cfb8d73f254" + integrity sha512-2JkrMWWUi2rlVLSo9OFR2PIGUzdiowEM8NgNYiwLKnXTjpwpjjIrJbNNxDik7Rv4oo9KtikcFQZKXbrKilL/MQ== + vscode-languageserver-types@^3.6.0-next.1: version "3.6.0-next.1" resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.6.0-next.1.tgz#98e488d3f87b666b4ee1a3d89f0023e246d358f3" integrity sha512-n4G+hCgZwAhtcJSCkwJP153TLdcEBWwrIrb3Su/SpOkhmU7KjDgxaQBLA45hf+QbhB8uKQb+TVStPvbuYFHSMA== +vscode-nls@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.1.1.tgz#f9916b64e4947b20322defb1e676a495861f133c" + integrity sha512-4R+2UoUUU/LdnMnFjePxfLqNhBS8lrAFyX7pjb2ud/lqDkrUavFUTcG7wR0HBZFakae0Q6KLBFjMS6W93F403A== + +vscode-uri@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.0.3.tgz#25e5f37f552fbee3cec7e5f80cef8469cefc6543" + integrity sha512-4D3DI3F4uRy09WNtDGD93H9q034OHImxiIcSq664Hq1Y1AScehlP3qqZyTkX/RWxeu0MRMHGkrxYqm2qlDF/aw== + vscode@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/vscode/-/vscode-1.0.1.tgz#3d161200615fe2af1d92ddc650751159411a513b" diff --git a/extensions/extension-editing/package.json b/extensions/extension-editing/package.json index 52159b965..9c07a2568 100644 --- a/extensions/extension-editing/package.json +++ b/extensions/extension-editing/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "^1.4.0" }, @@ -53,6 +54,6 @@ }, "devDependencies": { "@types/markdown-it": "0.0.2", - "@types/node": "^10.12.21" + "@types/node": "^10.14.8" } } diff --git a/extensions/extension-editing/yarn.lock b/extensions/extension-editing/yarn.lock index 720c84f06..971bf580b 100644 --- a/extensions/extension-editing/yarn.lock +++ b/extensions/extension-editing/yarn.lock @@ -7,10 +7,10 @@ resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-0.0.2.tgz#5d9ad19e6e6508cdd2f2596df86fd0aade598660" integrity sha1-XZrRnm5lCM3S8llt+G/Qqt5ZhmA= -"@types/node@^10.12.21": - version "10.12.21" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.21.tgz#7e8a0c34cf29f4e17a36e9bd0ea72d45ba03908e" - integrity sha512-CBgLNk4o3XMnqMc0rhb6lc77IwShMEglz05deDcn2lQxyXEZivfwgYJu7SMha9V5XcrP6qZuevTHV/QrN2vjKQ== +"@types/node@^10.14.8": + version "10.14.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9" + integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw== "@types/node@^6.0.46": version "6.0.78" diff --git a/extensions/fsharp/cgmanifest.json b/extensions/fsharp/cgmanifest.json index 851e97ca6..b093d9085 100644 --- a/extensions/fsharp/cgmanifest.json +++ b/extensions/fsharp/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "ionide/ionide-fsgrammar", "repositoryUrl": "https://github.com/ionide/ionide-fsgrammar", - "commitHash": "be0bdfd1e272b6633f5edf1429052fe9fa4df7c1" + "commitHash": "b57388e5a0971412c081cf0cea8b50b9c24ea4e8" } }, "license": "MIT", diff --git a/extensions/fsharp/package.json b/extensions/fsharp/package.json index 8aee9182f..b7050e22b 100644 --- a/extensions/fsharp/package.json +++ b/extensions/fsharp/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "*" }, "scripts": { "update-grammar": "node ../../build/npm/update-grammar.js ionide/ionide-fsgrammar grammar/fsharp.json ./syntaxes/fsharp.tmLanguage.json" diff --git a/extensions/fsharp/syntaxes/fsharp.tmLanguage.json b/extensions/fsharp/syntaxes/fsharp.tmLanguage.json index 9a9b1b1f2..82bd02d54 100644 --- a/extensions/fsharp/syntaxes/fsharp.tmLanguage.json +++ b/extensions/fsharp/syntaxes/fsharp.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/ionide/ionide-fsgrammar/commit/be0bdfd1e272b6633f5edf1429052fe9fa4df7c1", + "version": "https://github.com/ionide/ionide-fsgrammar/commit/b57388e5a0971412c081cf0cea8b50b9c24ea4e8", "name": "fsharp", "scopeName": "source.fsharp", "patterns": [ @@ -285,6 +285,33 @@ } ] }, + { + "begin": "(\\()", + "end": "(\\))", + "beginCaptures": { + "1": { + "name": "keyword.symbol.fsharp" + } + }, + "endCaptures": { + "1": { + "name": "keyword.symbol.fsharp" + } + }, + "patterns": [ + { + "match": "(([?[:alpha:]0-9'`^._ ]+))+", + "captures": { + "1": { + "name": "entity.name.type.fsharp" + } + } + }, + { + "include": "#tuple_signature" + } + ] + }, { "match": "(?!when|and|or\\b)\\b([\\w0-9'`^._]+)", "comments": "Here we need the \\w modifier in order to check that the words isn't blacklisted", @@ -308,6 +335,44 @@ } ] }, + "anonymous_record_declaration": { + "begin": "(\\{\\|)", + "end": "(\\|\\})", + "beginCaptures": { + "1": { + "name": "keyword.symbol.fsharp" + } + }, + "endCaptures": { + "1": { + "name": "keyword.symbol.fsharp" + } + }, + "patterns": [ + { + "match": "[[:alpha:]0-9'`^_ ]+(:)", + "captures": { + "1": { + "name": "keyword.symbol.fsharp" + } + } + }, + { + "match": "([[:alpha:]0-9'`^_ ]+)", + "captures": { + "1": { + "name": "entity.name.type.fsharp" + } + } + }, + { + "include": "#anonymous_record_declaration" + }, + { + "include": "#keywords" + } + ] + }, "record_signature": { "patterns": [ { @@ -571,7 +636,7 @@ "include": "#common_declaration" }, { - "match": "(\\?{0,1})([[:alpha:]0-9'`^._ ]+)\\s*(:)(\\s*([[:alpha:]0-9'`^._ ]+)){0,1}", + "match": "(\\?{0,1})([[:alpha:]0-9'`^._ ]+)\\s*(:)((?!with\\b)\\b([\\w0-9'`^._ ]+)){0,1}", "captures": { "1": { "name": "keyword.symbol.fsharp" @@ -772,9 +837,9 @@ } }, { - "begin": "(<(?![[:space:]]*\\)))", + "begin": "(<+(?![[:space:]]*\\)))", "beginComment": "The group (?![[:space:]]*\\) is for protection against overload operator. static member (<)", - "end": "((?)", + "end": "((?|\\))", "endComment": "The group (? when using SRTP synthax", "beginCaptures": { "1": { @@ -792,6 +857,9 @@ } ] }, + { + "include": "#anonymous_record_declaration" + }, { "begin": "({)", "end": "(})", @@ -814,6 +882,14 @@ { "include": "#definition" }, + { + "match": "(?<=>)\\s*(``([[:alpha:]0-9'^._ ]+)``|[[:alpha:]0-9'`^._]+)", + "captures": { + "1": { + "name": "entity.name.type.fsharp" + } + } + }, { "include": "#variables" }, @@ -826,7 +902,7 @@ "patterns": [ { "name": "binding.fsharp", - "begin": "\\b(let mutable|static let mutable|let inline|let|member val|static member inline|static member|default|member|override|let!)(\\s+rec|mutable)?(\\s+\\[\\<.*\\>\\])?\\s*(private|internal|public)?\\s+(\\[[^-=]*\\]|[_[:alpha:]]([_[:alpha:]0-9,\\._]+)*|``[_[:alpha:]]([_[:alpha:]0-9,\\._`\\s]+|(?<=,)\\s)*)?", + "begin": "\\b(let mutable|static let mutable|let inline|let|member val|static member inline|static member|default|member|override|let!)(\\s+rec|mutable)?(\\s+\\[\\<.*\\>\\])?\\s*(private|internal|public)?\\s+(\\[[^-=]*\\]|[_[:alpha:]]([_[:alpha:]0-9\\._]+)*|``[_[:alpha:]]([_[:alpha:]0-9\\._`\\s]+|(?<=,)\\s)*)?", "end": "\\s*(with\\b|=|\\n+=|(?<=\\=))", "beginCaptures": { "1": { @@ -856,6 +932,26 @@ } ] }, + { + "name": "binding.fsharp", + "begin": "\\b((get|set)\\s*(?=\\())(\\[[^-=]*\\]|[_[:alpha:]]([_[:alpha:]0-9\\._]+)*|``[_[:alpha:]]([_[:alpha:]0-9\\._`\\s]+|(?<=,)\\s)*)?", + "end": "\\s*(=|\\n+=|(?<=\\=))", + "beginCaptures": { + "3": { + "name": "variable.fsharp" + } + }, + "endCaptures": { + "1": { + "name": "keyword.fsharp" + } + }, + "patterns": [ + { + "include": "#common_binding_definition" + } + ] + }, { "name": "binding.fsharp", "begin": "\\b(static val mutable|val mutable|val)(\\s+rec|mutable)?(\\s+\\[\\<.*\\>\\])?\\s*(private|internal|public)?\\s+(\\[[^-=]*\\]|[_[:alpha:]]([_[:alpha:]0-9,\\._]+)*|``[_[:alpha:]]([_[:alpha:]0-9,\\._`\\s]+|(?<=,)\\s)*)?", @@ -920,13 +1016,16 @@ } }, { - "match": "([[:alpha:]0-9'`^._]+)|``([[:alpha:]0-9'^._ ]+)``", + "match": "(``([[:alpha:]0-9'^._ ]+)``|[[:alpha:]0-9'`^._]+)", "captures": { "1": { "name": "entity.name.type.fsharp" } } }, + { + "include": "#anonymous_record_declaration" + }, { "include": "#keywords" } @@ -1007,6 +1106,9 @@ "name": "entity.name.section.fsharp" } } + }, + { + "include": "#comments" } ] }, @@ -1142,7 +1244,7 @@ "match": "\\(\\)" }, { - "match": "(\\?{0,1})(``[[:alpha:]0-9'`^:,._ ]+``|[[:alpha:]0-9'`<>^._ ]\\w*)", + "match": "(\\?{0,1})(``[[:alpha:]0-9'`^:,._ ]+``|(?!private\\b)\\b[\\w[:alpha:]0-9'`<>^._ ]+)", "captures": { "1": { "name": "keyword.symbol.fsharp" @@ -1200,6 +1302,9 @@ } } }, + { + "include": "#anonymous_record_declaration" + }, { "begin": "(\\?{0,1})([[:alpha:]0-9'`^._ ]+)\\s*(:)(\\s*([?[:alpha:]0-9'`^._ ]+)(<))", "end": "(>)", diff --git a/extensions/fsharp/test/colorize-results/test_fs.json b/extensions/fsharp/test/colorize-results/test_fs.json index 37c0b61c1..e5736fc10 100644 --- a/extensions/fsharp/test/colorize-results/test_fs.json +++ b/extensions/fsharp/test/colorize-results/test_fs.json @@ -605,7 +605,7 @@ } }, { - "c": " get", + "c": " ", "t": "source.fsharp", "r": { "dark_plus": "default: #D4D4D4", @@ -615,9 +615,20 @@ "hc_black": "default: #FFFFFF" } }, + { + "c": "get", + "t": "source.fsharp binding.fsharp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, { "c": "()", - "t": "source.fsharp constant.language.unit.fsharp", + "t": "source.fsharp binding.fsharp constant.language.unit.fsharp", "r": { "dark_plus": "constant.language: #569CD6", "light_plus": "constant.language: #0000FF", @@ -628,7 +639,7 @@ }, { "c": " ", - "t": "source.fsharp", + "t": "source.fsharp binding.fsharp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -639,7 +650,7 @@ }, { "c": "=", - "t": "source.fsharp keyword.symbol.fsharp", + "t": "source.fsharp binding.fsharp keyword.fsharp", "r": { "dark_plus": "keyword: #569CD6", "light_plus": "keyword: #0000FF", @@ -682,7 +693,7 @@ } }, { - "c": " set", + "c": " ", "t": "source.fsharp", "r": { "dark_plus": "default: #D4D4D4", @@ -692,9 +703,20 @@ "hc_black": "default: #FFFFFF" } }, + { + "c": "set", + "t": "source.fsharp binding.fsharp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, { "c": "(", - "t": "source.fsharp keyword.symbol.fsharp", + "t": "source.fsharp binding.fsharp keyword.symbol.fsharp", "r": { "dark_plus": "keyword: #569CD6", "light_plus": "keyword: #0000FF", @@ -705,18 +727,18 @@ }, { "c": "value", - "t": "source.fsharp", + "t": "source.fsharp binding.fsharp variable.parameter.fsharp", "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.fsharp keyword.symbol.fsharp", + "t": "source.fsharp binding.fsharp keyword.symbol.fsharp", "r": { "dark_plus": "keyword: #569CD6", "light_plus": "keyword: #0000FF", @@ -727,7 +749,7 @@ }, { "c": " ", - "t": "source.fsharp", + "t": "source.fsharp binding.fsharp", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -738,7 +760,7 @@ }, { "c": "=", - "t": "source.fsharp keyword.symbol.fsharp", + "t": "source.fsharp binding.fsharp keyword.fsharp", "r": { "dark_plus": "keyword: #569CD6", "light_plus": "keyword: #0000FF", @@ -979,7 +1001,7 @@ } }, { - "c": " targetAge", + "c": " targetAge ", "t": "source.fsharp binding.fsharp variable.parameter.fsharp", "r": { "dark_plus": "variable: #9CDCFE", @@ -989,17 +1011,6 @@ "hc_black": "variable: #9CDCFE" } }, - { - "c": " ", - "t": "source.fsharp binding.fsharp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, { "c": "=", "t": "source.fsharp binding.fsharp keyword.fsharp", diff --git a/extensions/git-ui/.vscodeignore b/extensions/git-ui/.vscodeignore new file mode 100644 index 000000000..7462f7448 --- /dev/null +++ b/extensions/git-ui/.vscodeignore @@ -0,0 +1,8 @@ +src/** +test/** +out/** +tsconfig.json +build/** +extension.webpack.config.js +cgmanifest.json +yarn.lock diff --git a/extensions/git-ui/README.md b/extensions/git-ui/README.md new file mode 100644 index 000000000..d418425ac --- /dev/null +++ b/extensions/git-ui/README.md @@ -0,0 +1,7 @@ +# Git UI integration for Visual Studio Code + +**Notice:** This extension is bundled with Visual Studio Code. It can be disabled but not uninstalled. + +## Features + +See [Git support in VS Code](https://code.visualstudio.com/docs/editor/versioncontrol#_git-support) to learn about the features of this extension. diff --git a/extensions/git-ui/cgmanifest.json b/extensions/git-ui/cgmanifest.json new file mode 100644 index 000000000..f3071eb69 --- /dev/null +++ b/extensions/git-ui/cgmanifest.json @@ -0,0 +1,4 @@ +{ + "registrations": [], + "version": 1 +} \ No newline at end of file diff --git a/extensions/git-ui/extension.webpack.config.js b/extensions/git-ui/extension.webpack.config.js new file mode 100644 index 000000000..19c0ea304 --- /dev/null +++ b/extensions/git-ui/extension.webpack.config.js @@ -0,0 +1,17 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +//@ts-check + +'use strict'; + +const withDefaults = require('../shared.webpack.config'); + +module.exports = withDefaults({ + context: __dirname, + entry: { + main: './src/main.ts' + } +}); diff --git a/extensions/git-ui/package.json b/extensions/git-ui/package.json new file mode 100644 index 000000000..2f1ab43f8 --- /dev/null +++ b/extensions/git-ui/package.json @@ -0,0 +1,28 @@ +{ + "name": "git-ui", + "displayName": "%displayName%", + "description": "%description%", + "publisher": "vscode", + "version": "1.0.0", + "engines": { + "vscode": "^1.5.0" + }, + "extensionKind": "ui", + "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", + "enableProposedApi": true, + "categories": [ + "Other" + ], + "activationEvents": [ + "onCommand:git.credential" + ], + "main": "./out/main", + "icon": "resources/icons/git.png", + "scripts": { + "compile": "gulp compile-extension:git-ui", + "watch": "gulp watch-extension:git-ui" + }, + "devDependencies": { + "@types/node": "^10.14.8" + } +} \ No newline at end of file diff --git a/extensions/git-ui/package.nls.json b/extensions/git-ui/package.nls.json new file mode 100644 index 000000000..5303e91f4 --- /dev/null +++ b/extensions/git-ui/package.nls.json @@ -0,0 +1,4 @@ +{ + "displayName": "Git UI", + "description": "Git SCM UI Integration" +} \ No newline at end of file diff --git a/extensions/git-ui/resources/icons/git.png b/extensions/git-ui/resources/icons/git.png new file mode 100644 index 000000000..51f4ae540 Binary files /dev/null and b/extensions/git-ui/resources/icons/git.png differ diff --git a/extensions/git-ui/src/main.ts b/extensions/git-ui/src/main.ts new file mode 100644 index 000000000..d233b753b --- /dev/null +++ b/extensions/git-ui/src/main.ts @@ -0,0 +1,57 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ExtensionContext, commands } from 'vscode'; + +import * as cp from 'child_process'; + +export async function deactivate(): Promise { +} + +export async function activate(context: ExtensionContext): Promise { + context.subscriptions.push(commands.registerCommand('git.credential', async (data: any) => { + try { + const { stdout, stderr } = await exec(`git credential ${data.command}`, { + stdin: data.stdin, + env: Object.assign(process.env, { GIT_TERMINAL_PROMPT: '0' }) + }); + return { stdout, stderr, code: 0 }; + } catch ({ stdout, stderr, error }) { + const code = error.code || 0; + if (stderr.indexOf('terminal prompts disabled') !== -1) { + stderr = ''; + } + return { stdout, stderr, code }; + } + })); +} + +export interface ExecResult { + error: Error | null; + stdout: string; + stderr: string; +} + + +export function exec(command: string, options: cp.ExecOptions & { stdin?: string } = {}) { + return new Promise((resolve, reject) => { + const child = cp.exec(command, options, (error, stdout, stderr) => { + (error ? reject : resolve)({ error, stdout, stderr }); + }); + if (options.stdin) { + child.stdin.write(options.stdin, (err: any) => { + if (err) { + reject(err); + return; + } + child.stdin.end((err: any) => { + if (err) { + reject(err); + } + }); + }); + } + }); +} diff --git a/extensions/git-ui/src/typings/refs.d.ts b/extensions/git-ui/src/typings/refs.d.ts new file mode 100644 index 000000000..a93343122 --- /dev/null +++ b/extensions/git-ui/src/typings/refs.d.ts @@ -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. + *--------------------------------------------------------------------------------------------*/ + +/// +/// +/// \ No newline at end of file diff --git a/extensions/git-ui/tsconfig.json b/extensions/git-ui/tsconfig.json new file mode 100644 index 000000000..27e9268b3 --- /dev/null +++ b/extensions/git-ui/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../shared.tsconfig.json", + "compilerOptions": { + "outDir": "./out", + "experimentalDecorators": true, + "typeRoots": [ + "./node_modules/@types" + ] + }, + "include": [ + "src/**/*" + ] +} \ No newline at end of file diff --git a/extensions/git-ui/yarn.lock b/extensions/git-ui/yarn.lock new file mode 100644 index 000000000..b23b0ac03 --- /dev/null +++ b/extensions/git-ui/yarn.lock @@ -0,0 +1,8 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@types/node@^10.14.8": + version "10.14.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9" + integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw== diff --git a/extensions/git/cgmanifest.json b/extensions/git/cgmanifest.json index d0bdb9ac4..e8081d647 100644 --- a/extensions/git/cgmanifest.json +++ b/extensions/git/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "textmate/git.tmbundle", "repositoryUrl": "https://github.com/textmate/git.tmbundle", - "commitHash": "3f6ad2138200db14b57a090ecb2d2e733275ca3e" + "commitHash": "5870cf3f8abad3a6637bdf69250b5d2ded427dc4" } }, "licenseDetail": [ diff --git a/extensions/git/package.json b/extensions/git/package.json index 4395d306b..4a789aaa6 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -3,6 +3,7 @@ "displayName": "%displayName%", "description": "%description%", "publisher": "vscode", + "license": "MIT", "version": "1.0.0", "engines": { "vscode": "^1.5.0" @@ -20,7 +21,8 @@ "scripts": { "compile": "gulp compile-extension:git", "watch": "gulp watch-extension:git", - "update-grammar": "node ./build/update-grammars.js" + "update-grammar": "node ./build/update-grammars.js", + "test": "mocha" }, "contributes": { "commands": [ @@ -80,8 +82,8 @@ "title": "%command.openFile%", "category": "Git", "icon": { - "light": "resources/icons/light/open-file-mono.svg", - "dark": "resources/icons/dark/open-file-mono.svg" + "light": "resources/icons/light/open-file.svg", + "dark": "resources/icons/dark/open-file.svg" } }, { @@ -317,12 +319,12 @@ }, { "command": "git.pushWithTags", - "title": "%command.pushWithTags%", + "title": "%command.pushFollowTags%", "category": "Git" }, { "command": "git.pushWithTagsForce", - "title": "%command.pushWithTagsForce%", + "title": "%command.pushFollowTagsForce%", "category": "Git" }, { @@ -1244,12 +1246,18 @@ }, "git.ignoredRepositories": { "type": "array", + "items": { + "type": "string" + }, "default": [], "scope": "window", "description": "%config.ignoredRepositories%" }, "git.scanRepositories": { "type": "array", + "items": { + "type": "string" + }, "default": [], "scope": "resource", "description": "%config.scanRepositories%" @@ -1272,6 +1280,12 @@ "default": false, "description": "%config.fetchOnPull%" }, + "git.pullTags": { + "type": "boolean", + "scope": "resource", + "default": true, + "description": "%config.pullTags%" + }, "git.autoStash": { "type": "boolean", "scope": "resource", @@ -1452,13 +1466,14 @@ "jschardet": "^1.6.0", "vscode-extension-telemetry": "0.1.1", "vscode-nls": "^4.0.0", + "vscode-uri": "^2.0.0", "which": "^1.3.0" }, "devDependencies": { "@types/byline": "4.2.31", "@types/file-type": "^5.2.1", "@types/mocha": "2.2.43", - "@types/node": "^10.12.21", + "@types/node": "^10.14.8", "@types/which": "^1.0.28", "mocha": "^3.2.0" } diff --git a/extensions/git/package.nls.json b/extensions/git/package.nls.json index 892e3519c..adff0134e 100644 --- a/extensions/git/package.nls.json +++ b/extensions/git/package.nls.json @@ -47,8 +47,8 @@ "command.pushForce": "Push (Force)", "command.pushTo": "Push to...", "command.pushToForce": "Push to... (Force)", - "command.pushWithTags": "Push With Tags", - "command.pushWithTagsForce": "Push With Tags (Force)", + "command.pushFollowTags": "Push (Follow Tags)", + "command.pushFollowTagsForce": "Push (Follow Tags, Force)", "command.addRemote": "Add Remote", "command.removeRemote": "Remove Remote", "command.sync": "Sync", @@ -112,6 +112,7 @@ "config.rebaseWhenSync": "Force git to use rebase when running the sync command.", "config.confirmEmptyCommits": "Always confirm the creation of empty commits.", "config.fetchOnPull": "Fetch all branches when pulling or just the current one.", + "config.pullTags": "Fetch all tags when pulling.", "config.autoStash": "Stash any changes before pulling and restore them after successful pull.", "config.allowForcePush": "Controls whether force push (with or without lease) is enabled.", "config.useForcePushWithLease": "Controls whether force pushing uses the safer force-with-lease variant.", diff --git a/extensions/git/resources/icons/dark/check.svg b/extensions/git/resources/icons/dark/check.svg index c225b2f59..865cc83c3 100644 --- a/extensions/git/resources/icons/dark/check.svg +++ b/extensions/git/resources/icons/dark/check.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + diff --git a/extensions/git/resources/icons/dark/clean.svg b/extensions/git/resources/icons/dark/clean.svg index 3770d63d5..de85d6ba6 100644 --- a/extensions/git/resources/icons/dark/clean.svg +++ b/extensions/git/resources/icons/dark/clean.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + diff --git a/extensions/git/resources/icons/dark/git.svg b/extensions/git/resources/icons/dark/git.svg index c08b1c2e4..4d9389336 100644 --- a/extensions/git/resources/icons/dark/git.svg +++ b/extensions/git/resources/icons/dark/git.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + diff --git a/extensions/git/resources/icons/dark/open-change.svg b/extensions/git/resources/icons/dark/open-change.svg index 6f785c26a..41ebc85a8 100644 --- a/extensions/git/resources/icons/dark/open-change.svg +++ b/extensions/git/resources/icons/dark/open-change.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + diff --git a/extensions/git/resources/icons/dark/open-file-mono.svg b/extensions/git/resources/icons/dark/open-file-mono.svg deleted file mode 100644 index 830727e70..000000000 --- a/extensions/git/resources/icons/dark/open-file-mono.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/extensions/git/resources/icons/dark/open-file.svg b/extensions/git/resources/icons/dark/open-file.svg index f6302185a..ed302ae13 100644 --- a/extensions/git/resources/icons/dark/open-file.svg +++ b/extensions/git/resources/icons/dark/open-file.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + diff --git a/extensions/git/resources/icons/dark/refresh.svg b/extensions/git/resources/icons/dark/refresh.svg index d79fdaa4e..e1f05aade 100644 --- a/extensions/git/resources/icons/dark/refresh.svg +++ b/extensions/git/resources/icons/dark/refresh.svg @@ -1 +1,4 @@ - \ No newline at end of file + + + + diff --git a/extensions/git/resources/icons/dark/stage.svg b/extensions/git/resources/icons/dark/stage.svg index 3475c1e19..4d9389336 100644 --- a/extensions/git/resources/icons/dark/stage.svg +++ b/extensions/git/resources/icons/dark/stage.svg @@ -1 +1,3 @@ -Layer 1 \ No newline at end of file + + + diff --git a/extensions/git/resources/icons/dark/unstage.svg b/extensions/git/resources/icons/dark/unstage.svg index 2de46fcf5..4c5a9c1e3 100644 --- a/extensions/git/resources/icons/dark/unstage.svg +++ b/extensions/git/resources/icons/dark/unstage.svg @@ -1 +1,3 @@ -Layer 1 \ No newline at end of file + + + diff --git a/extensions/git/resources/icons/light/check.svg b/extensions/git/resources/icons/light/check.svg index 3f365c480..e1a546660 100644 --- a/extensions/git/resources/icons/light/check.svg +++ b/extensions/git/resources/icons/light/check.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + diff --git a/extensions/git/resources/icons/light/clean.svg b/extensions/git/resources/icons/light/clean.svg index f86ec7d62..b70626957 100644 --- a/extensions/git/resources/icons/light/clean.svg +++ b/extensions/git/resources/icons/light/clean.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + diff --git a/extensions/git/resources/icons/light/git.svg b/extensions/git/resources/icons/light/git.svg index d1049a44d..01a9de7d5 100644 --- a/extensions/git/resources/icons/light/git.svg +++ b/extensions/git/resources/icons/light/git.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + diff --git a/extensions/git/resources/icons/light/open-change.svg b/extensions/git/resources/icons/light/open-change.svg index 873b93d81..772c3c198 100644 --- a/extensions/git/resources/icons/light/open-change.svg +++ b/extensions/git/resources/icons/light/open-change.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + diff --git a/extensions/git/resources/icons/light/open-file-mono.svg b/extensions/git/resources/icons/light/open-file-mono.svg deleted file mode 100644 index fa3f245b7..000000000 --- a/extensions/git/resources/icons/light/open-file-mono.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/extensions/git/resources/icons/light/open-file.svg b/extensions/git/resources/icons/light/open-file.svg index d23a23c6b..392a840c5 100644 --- a/extensions/git/resources/icons/light/open-file.svg +++ b/extensions/git/resources/icons/light/open-file.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + diff --git a/extensions/git/resources/icons/light/refresh.svg b/extensions/git/resources/icons/light/refresh.svg index e03457481..9b1d91084 100644 --- a/extensions/git/resources/icons/light/refresh.svg +++ b/extensions/git/resources/icons/light/refresh.svg @@ -1 +1,4 @@ - \ No newline at end of file + + + + diff --git a/extensions/git/resources/icons/light/stage.svg b/extensions/git/resources/icons/light/stage.svg index bdecdb0e4..01a9de7d5 100644 --- a/extensions/git/resources/icons/light/stage.svg +++ b/extensions/git/resources/icons/light/stage.svg @@ -1 +1,3 @@ -Layer 1 \ No newline at end of file + + + diff --git a/extensions/git/resources/icons/light/unstage.svg b/extensions/git/resources/icons/light/unstage.svg index f5d128b2d..d12a8ee31 100644 --- a/extensions/git/resources/icons/light/unstage.svg +++ b/extensions/git/resources/icons/light/unstage.svg @@ -1 +1,3 @@ -Layer 1 \ No newline at end of file + + + diff --git a/extensions/git/src/api/api1.ts b/extensions/git/src/api/api1.ts index 25742babc..a4fd677db 100644 --- a/extensions/git/src/api/api1.ts +++ b/extensions/git/src/api/api1.ts @@ -5,7 +5,7 @@ import { Model } from '../model'; import { Repository as BaseRepository, Resource } from '../repository'; -import { InputBox, Git, API, Repository, Remote, RepositoryState, Branch, Ref, Submodule, Commit, Change, RepositoryUIState, Status, LogOptions } from './git'; +import { InputBox, Git, API, Repository, Remote, RepositoryState, Branch, Ref, Submodule, Commit, Change, RepositoryUIState, Status, LogOptions, APIState } from './git'; import { Event, SourceControlInputBox, Uri, SourceControl } from 'vscode'; import { mapEvent } from '../util'; @@ -214,6 +214,14 @@ export class ApiImpl implements API { readonly git = new ApiGit(this._model); + get state(): APIState { + return this._model.state; + } + + get onDidChangeState(): Event { + return this._model.onDidChangeState; + } + get onDidOpenRepository(): Event { return mapEvent(this._model.onDidOpenRepository, r => new ApiRepository(r)); } diff --git a/extensions/git/src/api/git.d.ts b/extensions/git/src/api/git.d.ts index ae8eb5315..21195974f 100644 --- a/extensions/git/src/api/git.d.ts +++ b/extensions/git/src/api/git.d.ts @@ -176,7 +176,11 @@ export interface Repository { log(options?: LogOptions): Promise; } +export type APIState = 'uninitialized' | 'initialized'; + export interface API { + readonly state: APIState; + readonly onDidChangeState: Event; readonly git: Git; readonly repositories: Repository[]; readonly onDidOpenRepository: Event; @@ -235,4 +239,4 @@ export const enum GitErrorCodes { CantRebaseMultipleBranches = 'CantRebaseMultipleBranches', PatchDoesNotApply = 'PatchDoesNotApply', NoPathFound = 'NoPathFound' -} \ No newline at end of file +} diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index f6e00e9ab..d75e6f9bc 100755 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -56,7 +56,13 @@ class CheckoutRemoteHeadItem extends CheckoutItem { return; } - await repository.checkoutTracking(this.ref.name); + const branches = await repository.findTrackingBranches(this.ref.name); + + if (branches.length > 0) { + await repository.checkout(branches[0].name!); + } else { + await repository.checkoutTracking(this.ref.name); + } } } @@ -196,7 +202,7 @@ function createCheckoutItems(repository: Repository): CheckoutItem[] { enum PushType { Push, PushTo, - PushTags, + PushFollowTags, } interface PushOptions { @@ -481,10 +487,10 @@ export class CommandCenter { (_, token) => this.git.clone(url!, parentPath, token) ); - const choices = []; let message = localize('proposeopen', "Would you like to open the cloned repository?"); - const open = localize('openrepo', "Open Repository"); - choices.push(open); + const open = localize('openrepo', "Open"); + const openNewWindow = localize('openreponew', "Open in New Window"); + const choices = [open, openNewWindow]; const addToWorkspace = localize('add', "Add to Workspace"); if (workspace.workspaceFolders) { @@ -509,6 +515,8 @@ export class CommandCenter { commands.executeCommand('vscode.openFolder', uri); } else if (result === addToWorkspace) { workspace.updateWorkspaceFolders(workspace.workspaceFolders!.length, 0, { uri }); + } else if (result === openNewWindow) { + commands.executeCommand('vscode.openFolder', uri, true); } } catch (err) { if (/already exists and is not an empty directory/.test(err && err.stderr || '')) { @@ -593,10 +601,10 @@ export class CommandCenter { await this.git.init(repositoryPath); - const choices = []; let message = localize('proposeopen init', "Would you like to open the initialized repository?"); - const open = localize('openrepo', "Open Repository"); - choices.push(open); + const open = localize('openrepo', "Open"); + const openNewWindow = localize('openreponew', "Open in New Window"); + const choices = [open, openNewWindow]; if (!askToOpen) { return; @@ -615,6 +623,8 @@ export class CommandCenter { commands.executeCommand('vscode.openFolder', uri); } else if (result === addToWorkspace) { workspace.updateWorkspaceFolders(workspace.workspaceFolders!.length, 0, { uri }); + } else if (result === openNewWindow) { + commands.executeCommand('vscode.openFolder', uri, true); } else { await this.model.openRepository(repositoryPath); } @@ -663,7 +673,6 @@ export class CommandCenter { if (!(resource instanceof Resource)) { // can happen when called from a keybinding - console.log('WHAT'); resource = this.getSCMResource(); } @@ -728,6 +737,8 @@ export class CommandCenter { } const HEAD = await this.getLeftResource(resource); + const basename = path.basename(resource.resourceUri.fsPath); + const title = `${basename} (HEAD)`; if (!HEAD) { window.showWarningMessage(localize('HEAD not available', "HEAD version of '{0}' is not available.", path.basename(resource.resourceUri.fsPath))); @@ -738,7 +749,7 @@ export class CommandCenter { preview }; - return await commands.executeCommand('vscode.open', HEAD, opts); + return await commands.executeCommand('vscode.open', HEAD, opts, title); } @command('git.openChange') @@ -1104,7 +1115,7 @@ export class CommandCenter { if (scmResources.length === 1) { if (untrackedCount > 0) { - message = localize('confirm delete', "Are you sure you want to DELETE {0}?", path.basename(scmResources[0].resourceUri.fsPath)); + message = localize('confirm delete', "Are you sure you want to DELETE {0}?\nThis is IRREVERSIBLE!\nThis file will be FOREVER LOST.", path.basename(scmResources[0].resourceUri.fsPath)); yes = localize('delete file', "Delete file"); } else { if (scmResources[0].type === Status.DELETED) { @@ -1123,7 +1134,7 @@ export class CommandCenter { } if (untrackedCount > 0) { - message = `${message}\n\n${localize('warn untracked', "This will DELETE {0} untracked files!", untrackedCount)}`; + message = `${message}\n\n${localize('warn untracked', "This will DELETE {0} untracked files!\nThis is IRREVERSIBLE!\nThese files will be FOREVER LOST.", untrackedCount)}`; } } @@ -1164,7 +1175,7 @@ export class CommandCenter { await repository.clean(resources.map(r => r.resourceUri)); return; } else if (resources.length === 1) { - const message = localize('confirm delete', "Are you sure you want to DELETE {0}?", path.basename(resources[0].resourceUri.fsPath)); + const message = localize('confirm delete', "Are you sure you want to DELETE {0}?\nThis is IRREVERSIBLE!\nThis file will be FOREVER LOST.", path.basename(resources[0].resourceUri.fsPath)); const yes = localize('delete file', "Delete file"); const pick = await window.showWarningMessage(message, { modal: true }, yes); @@ -1560,8 +1571,11 @@ export class CommandCenter { @command('git.renameBranch', { repository: true }) async renameBranch(repository: Repository): Promise { - const placeHolder = localize('provide branch name', "Please provide a branch name"); - const name = await window.showInputBox({ placeHolder }); + const name = await window.showInputBox({ + placeHolder: localize('branch name', "Branch name"), + prompt: localize('provide branch name', "Please provide a branch name"), + value: repository.HEAD && repository.HEAD.name + }); if (!name || name.trim().length === 0) { return; @@ -1753,10 +1767,8 @@ export class CommandCenter { } } - if (pushOptions.pushType === PushType.PushTags) { - await repository.pushTags(undefined, forcePushMode); - - window.showInformationMessage(localize('push with tags success', "Successfully pushed with tags.")); + if (pushOptions.pushType === PushType.PushFollowTags) { + await repository.pushFollowTags(undefined, forcePushMode); return; } @@ -1813,13 +1825,13 @@ export class CommandCenter { } @command('git.pushWithTags', { repository: true }) - async pushWithTags(repository: Repository): Promise { - await this._push(repository, { pushType: PushType.PushTags }); + async pushFollowTags(repository: Repository): Promise { + await this._push(repository, { pushType: PushType.PushFollowTags }); } @command('git.pushWithTagsForce', { repository: true }) - async pushWithTagsForce(repository: Repository): Promise { - await this._push(repository, { pushType: PushType.PushTags, forcePush: true }); + async pushFollowTagsForce(repository: Repository): Promise { + await this._push(repository, { pushType: PushType.PushFollowTags, forcePush: true }); } @command('git.pushTo', { repository: true }) diff --git a/extensions/git/src/git.ts b/extensions/git/src/git.ts index 3132b8cdf..30348608d 100644 --- a/extensions/git/src/git.ts +++ b/extensions/git/src/git.ts @@ -12,7 +12,8 @@ import { EventEmitter } from 'events'; import iconv = require('iconv-lite'); import * as filetype from 'file-type'; import { assign, groupBy, denodeify, IDisposable, toDisposable, dispose, mkdirp, readBytes, detectUnicodeEncoding, Encoding, onceEvent } from './util'; -import { CancellationToken, Uri } from 'vscode'; +import { CancellationToken } from 'vscode'; +import { URI } from 'vscode-uri'; import { detectEncoding } from './encoding'; import { Ref, RefType, Branch, Remote, GitErrorCodes, LogOptions, Change, Status } from './api/git'; @@ -306,6 +307,8 @@ function getGitErrorCode(stderr: string): string | undefined { return GitErrorCodes.BranchAlreadyExists; } else if (/'.+' is not a valid branch name/.test(stderr)) { return GitErrorCodes.InvalidBranchName; + } else if (/Please,? commit your changes or stash them/.test(stderr)) { + return GitErrorCodes.DirtyWorkTree; } return undefined; @@ -326,8 +329,8 @@ export class Git { this.env = options.env || {}; } - open(repository: string): Repository { - return new Repository(this, repository); + open(repository: string, dotGit: string): Repository { + return new Repository(this, repository, dotGit); } async init(repository: string): Promise { @@ -336,7 +339,7 @@ export class Git { } async clone(url: string, parentPath: string, cancellationToken?: CancellationToken): Promise { - let baseFolderName = decodeURI(url).replace(/^.*\//, '').replace(/\.git$/, '') || 'repository'; + let baseFolderName = decodeURI(url).replace(/[\/]+$/, '').replace(/^.*\//, '').replace(/\.git$/, '') || 'repository'; let folderName = baseFolderName; let folderPath = path.join(parentPath, folderName); let count = 1; @@ -367,6 +370,17 @@ export class Git { return path.normalize(result.stdout.trim()); } + async getRepositoryDotGit(repositoryPath: string): Promise { + const result = await this.exec(repositoryPath, ['rev-parse', '--git-dir']); + let dotGitPath = result.stdout.trim(); + + if (!path.isAbsolute(dotGitPath)) { + dotGitPath = path.join(repositoryPath, dotGitPath); + } + + return path.normalize(dotGitPath); + } + async exec(cwd: string, args: string[], options: SpawnOptions = {}): Promise> { options = assign({ cwd }, options || {}); return await this._exec(args, options); @@ -555,7 +569,7 @@ export function parseGitmodules(raw: string): Submodule[] { return; } - const propertyMatch = /^\s*(\w+) = (.*)$/.exec(line); + const propertyMatch = /^\s*(\w+)\s+=\s+(.*)$/.exec(line); if (!propertyMatch) { return; @@ -634,6 +648,7 @@ export interface CommitOptions { export interface PullOptions { unshallow?: boolean; + tags?: boolean; } export enum ForcePushMode { @@ -645,7 +660,8 @@ export class Repository { constructor( private _git: Git, - private repositoryRoot: string + private repositoryRoot: string, + readonly dotGit: string ) { } get git(): Git { @@ -993,7 +1009,7 @@ export class Repository { break; } - const originalUri = Uri.file(path.isAbsolute(resourcePath) ? resourcePath : path.join(this.repositoryRoot, resourcePath)); + const originalUri = URI.file(path.isAbsolute(resourcePath) ? resourcePath : path.join(this.repositoryRoot, resourcePath)); let status: Status = Status.UNTRACKED; // Copy or Rename status comes with a number, e.g. 'R100'. We don't need the number, so we use only first character of the status. @@ -1021,7 +1037,7 @@ export class Repository { break; } - const uri = Uri.file(path.isAbsolute(newPath) ? newPath : path.join(this.repositoryRoot, newPath)); + const uri = URI.file(path.isAbsolute(newPath) ? newPath : path.join(this.repositoryRoot, newPath)); result.push({ uri, renameUri: uri, @@ -1360,7 +1376,11 @@ export class Repository { } async pull(rebase?: boolean, remote?: string, branch?: string, options: PullOptions = {}): Promise { - const args = ['pull', '--tags']; + const args = ['pull']; + + if (options.tags) { + args.push('--tags'); + } if (options.unshallow) { args.push('--unshallow'); @@ -1411,7 +1431,7 @@ export class Repository { } if (tags) { - args.push('--tags'); + args.push('--follow-tags'); } if (remote) { @@ -1571,6 +1591,14 @@ export class Repository { } } + async findTrackingBranches(upstreamBranch: string): Promise { + const result = await this.run(['for-each-ref', '--format', '%(refname:short)%00%(upstream:short)', 'refs/heads']); + return result.stdout.trim().split('\n') + .map(line => line.trim().split('\0')) + .filter(([_, upstream]) => upstream === upstreamBranch) + .map(([ref]) => ({ name: ref, type: RefType.Head } as Branch)); + } + async getRefs(): Promise { const result = await this.run(['for-each-ref', '--format', '%(refname) %(objectname)', '--sort', '-committerdate']); diff --git a/extensions/git/src/model.ts b/extensions/git/src/model.ts index 22c690a5d..da6a94042 100644 --- a/extensions/git/src/model.ts +++ b/extensions/git/src/model.ts @@ -12,7 +12,7 @@ import * as path from 'path'; import * as fs from 'fs'; import * as nls from 'vscode-nls'; import { fromGitUri } from './uri'; -import { GitErrorCodes } from './api/git'; +import { GitErrorCodes, APIState as State } from './api/git'; const localize = nls.loadMessageBundle(); @@ -63,26 +63,41 @@ export class Model { private possibleGitRepositoryPaths = new Set(); + private _onDidChangeState = new EventEmitter(); + readonly onDidChangeState = this._onDidChangeState.event; + + private _state: State = 'uninitialized'; + get state(): State { return this._state; } + + setState(state: State): void { + this._state = state; + this._onDidChangeState.fire(state); + } + private disposables: Disposable[] = []; constructor(readonly git: Git, private globalState: Memento, private outputChannel: OutputChannel) { workspace.onDidChangeWorkspaceFolders(this.onDidChangeWorkspaceFolders, this, this.disposables); - this.onDidChangeWorkspaceFolders({ added: workspace.workspaceFolders || [], removed: [] }); - window.onDidChangeVisibleTextEditors(this.onDidChangeVisibleTextEditors, this, this.disposables); - this.onDidChangeVisibleTextEditors(window.visibleTextEditors); - workspace.onDidChangeConfiguration(this.onDidChangeConfiguration, this, this.disposables); const fsWatcher = workspace.createFileSystemWatcher('**'); this.disposables.push(fsWatcher); const onWorkspaceChange = anyEvent(fsWatcher.onDidChange, fsWatcher.onDidCreate, fsWatcher.onDidDelete); - const onGitRepositoryChange = filterEvent(onWorkspaceChange, uri => /\/\.git\//.test(uri.path)); + const onGitRepositoryChange = filterEvent(onWorkspaceChange, uri => /\/\.git/.test(uri.path)); const onPossibleGitRepositoryChange = filterEvent(onGitRepositoryChange, uri => !this.getRepository(uri)); onPossibleGitRepositoryChange(this.onPossibleGitRepositoryChange, this, this.disposables); - this.scanWorkspaceFolders(); + this.doInitialScan().finally(() => this.setState('initialized')); + } + + private async doInitialScan(): Promise { + await Promise.all([ + this.onDidChangeWorkspaceFolders({ added: workspace.workspaceFolders || [], removed: [] }), + this.onDidChangeVisibleTextEditors(window.visibleTextEditors), + this.scanWorkspaceFolders() + ]); } /** @@ -157,8 +172,8 @@ export class Model { .filter(r => !activeRepositories.has(r!.repository)) .filter(r => !(workspace.workspaceFolders || []).some(f => isDescendant(f.uri.fsPath, r!.repository.root))) as OpenRepository[]; - possibleRepositoryFolders.forEach(p => this.openRepository(p.uri.fsPath)); openRepositoriesToDispose.forEach(r => r.dispose()); + await Promise.all(possibleRepositoryFolders.map(p => this.openRepository(p.uri.fsPath))); } private onDidChangeConfiguration(): void { @@ -175,7 +190,7 @@ export class Model { openRepositoriesToDispose.forEach(r => r.dispose()); } - private onDidChangeVisibleTextEditors(editors: TextEditor[]): void { + private async onDidChangeVisibleTextEditors(editors: TextEditor[]): Promise { const config = workspace.getConfiguration('git'); const autoRepositoryDetection = config.get('autoRepositoryDetection'); @@ -183,7 +198,7 @@ export class Model { return; } - editors.forEach(editor => { + await Promise.all(editors.map(async editor => { const uri = editor.document.uri; if (uri.scheme !== 'file') { @@ -196,8 +211,8 @@ export class Model { return; } - this.openRepository(path.dirname(uri.fsPath)); - }); + await this.openRepository(path.dirname(uri.fsPath)); + })); } @sequentialize @@ -232,9 +247,11 @@ export class Model { return; } - const repository = new Repository(this.git.open(repositoryRoot), this.globalState); + const dotGit = await this.git.getRepositoryDotGit(repositoryRoot); + const repository = new Repository(this.git.open(repositoryRoot, dotGit), this.globalState, this.outputChannel); this.open(repository); + await repository.status(); } catch (err) { if (err.gitErrorCode === GitErrorCodes.NotAGitRepository) { return; @@ -420,4 +437,4 @@ export class Model { this.possibleGitRepositoryPaths.clear(); this.disposables = dispose(this.disposables); } -} \ No newline at end of file +} diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index 2fac9e2a3..196a1bdda 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -3,9 +3,9 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { commands, Uri, Command, EventEmitter, Event, scm, SourceControl, SourceControlInputBox, SourceControlResourceGroup, SourceControlResourceState, SourceControlResourceDecorations, SourceControlInputBoxValidation, Disposable, ProgressLocation, window, workspace, WorkspaceEdit, ThemeColor, DecorationData, Memento, SourceControlInputBoxValidationType } from 'vscode'; +import { commands, Uri, Command, EventEmitter, Event, scm, SourceControl, SourceControlInputBox, SourceControlResourceGroup, SourceControlResourceState, SourceControlResourceDecorations, SourceControlInputBoxValidation, Disposable, ProgressLocation, window, workspace, WorkspaceEdit, ThemeColor, DecorationData, Memento, SourceControlInputBoxValidationType, OutputChannel, LogLevel, env } from 'vscode'; import { Repository as BaseRepository, Commit, Stash, GitError, Submodule, CommitOptions, ForcePushMode } from './git'; -import { anyEvent, filterEvent, eventToPromise, dispose, find, isDescendant, IDisposable, onceEvent, EmptyDisposable, debounceEvent } from './util'; +import { anyEvent, filterEvent, eventToPromise, dispose, find, isDescendant, IDisposable, onceEvent, EmptyDisposable, debounceEvent, combinedDisposable, watch, IFileWatcher } from './util'; import { memoize, throttle, debounce } from './decorators'; import { toGitUri } from './uri'; import { AutoFetcher } from './autofetch'; @@ -299,6 +299,7 @@ export const enum Operation { GetObjectDetails = 'GetObjectDetails', SubmoduleUpdate = 'SubmoduleUpdate', RebaseContinue = 'RebaseContinue', + FindTrackingBranches = 'GetTracking', Apply = 'Apply', Blame = 'Blame', Log = 'Log', @@ -446,6 +447,91 @@ class ProgressManager { } } +class FileEventLogger { + + private eventDisposable: IDisposable = EmptyDisposable; + private logLevelDisposable: IDisposable = EmptyDisposable; + + constructor( + private onWorkspaceWorkingTreeFileChange: Event, + private onDotGitFileChange: Event, + private outputChannel: OutputChannel + ) { + this.logLevelDisposable = env.onDidChangeLogLevel(this.onDidChangeLogLevel, this); + this.onDidChangeLogLevel(env.logLevel); + } + + private onDidChangeLogLevel(level: LogLevel): void { + this.eventDisposable.dispose(); + + if (level > LogLevel.Debug) { + return; + } + + this.eventDisposable = combinedDisposable([ + this.onWorkspaceWorkingTreeFileChange(uri => this.outputChannel.appendLine(`[debug] [wt] Change: ${uri.fsPath}`)), + this.onDotGitFileChange(uri => this.outputChannel.appendLine(`[debug] [.git] Change: ${uri.fsPath}`)) + ]); + } + + dispose(): void { + this.eventDisposable.dispose(); + this.logLevelDisposable.dispose(); + } +} + +class DotGitWatcher implements IFileWatcher { + + readonly event: Event; + + private emitter = new EventEmitter(); + private transientDisposables: IDisposable[] = []; + private disposables: IDisposable[] = []; + + constructor( + private repository: Repository, + private outputChannel: OutputChannel + ) { + const rootWatcher = watch(repository.dotGit); + this.disposables.push(rootWatcher); + + const filteredRootWatcher = filterEvent(rootWatcher.event, uri => !/\/\.git(\/index\.lock)?$/.test(uri.path)); + this.event = anyEvent(filteredRootWatcher, this.emitter.event); + + repository.onDidRunGitStatus(this.updateTransientWatchers, this, this.disposables); + this.updateTransientWatchers(); + } + + private updateTransientWatchers() { + this.transientDisposables = dispose(this.transientDisposables); + + if (!this.repository.HEAD || !this.repository.HEAD.upstream) { + return; + } + + this.transientDisposables = dispose(this.transientDisposables); + + const { name, remote } = this.repository.HEAD.upstream; + const upstreamPath = path.join(this.repository.dotGit, 'refs', 'remotes', remote, name); + + try { + const upstreamWatcher = watch(upstreamPath); + this.transientDisposables.push(upstreamWatcher); + upstreamWatcher.event(this.emitter.fire, this.emitter, this.transientDisposables); + } catch (err) { + if (env.logLevel <= LogLevel.Error) { + this.outputChannel.appendLine(`Failed to watch ref '${upstreamPath}', is most likely packed.\n${err.stack || err}`); + } + } + } + + dispose() { + this.emitter.dispose(); + this.transientDisposables = dispose(this.transientDisposables); + this.disposables = dispose(this.disposables); + } +} + export class Repository implements Disposable { private _onDidChangeRepository = new EventEmitter(); @@ -543,36 +629,52 @@ export class Repository implements Disposable { return this.repository.root; } + get dotGit(): string { + return this.repository.dotGit; + } + private isRepositoryHuge = false; private didWarnAboutLimit = false; private isFreshRepository: boolean | undefined = undefined; + private disposables: Disposable[] = []; constructor( private readonly repository: BaseRepository, - globalState: Memento + globalState: Memento, + outputChannel: OutputChannel ) { - const fsWatcher = workspace.createFileSystemWatcher('**'); - this.disposables.push(fsWatcher); + const workspaceWatcher = workspace.createFileSystemWatcher('**'); + this.disposables.push(workspaceWatcher); + + const onWorkspaceFileChange = anyEvent(workspaceWatcher.onDidChange, workspaceWatcher.onDidCreate, workspaceWatcher.onDidDelete); + const onWorkspaceRepositoryFileChange = filterEvent(onWorkspaceFileChange, uri => isDescendant(repository.root, uri.fsPath)); + const onWorkspaceWorkingTreeFileChange = filterEvent(onWorkspaceRepositoryFileChange, uri => !/\/\.git($|\/)/.test(uri.path)); + + let onDotGitFileChange: Event; + + try { + const dotGitFileWatcher = new DotGitWatcher(this, outputChannel); + onDotGitFileChange = dotGitFileWatcher.event; + this.disposables.push(dotGitFileWatcher); + } catch (err) { + if (env.logLevel <= LogLevel.Error) { + outputChannel.appendLine(`Failed to watch '${this.dotGit}', reverting to legacy API file watched. Some events might be lost.\n${err.stack || err}`); + } - const workspaceFilter = (uri: Uri) => isDescendant(repository.root, uri.fsPath); - const onWorkspaceDelete = filterEvent(fsWatcher.onDidDelete, workspaceFilter); - const onWorkspaceChange = filterEvent(anyEvent(fsWatcher.onDidChange, fsWatcher.onDidCreate), workspaceFilter); - const onRepositoryDotGitDelete = filterEvent(onWorkspaceDelete, uri => /\/\.git$/.test(uri.path)); - const onRepositoryChange = anyEvent(onWorkspaceDelete, onWorkspaceChange); + onDotGitFileChange = filterEvent(onWorkspaceRepositoryFileChange, uri => /\/\.git($|\/)/.test(uri.path)); + } - // relevant repository changes are: - // - DELETE .git folder - // - ANY CHANGE within .git folder except .git itself and .git/index.lock - const onRelevantRepositoryChange = anyEvent( - onRepositoryDotGitDelete, - filterEvent(onRepositoryChange, uri => !/\/\.git(\/index\.lock)?$/.test(uri.path)) - ); + // FS changes should trigger `git status`: + // - any change inside the repository working tree + // - any change whithin the first level of the `.git` folder, except the folder itself and `index.lock` + const onFileChange = anyEvent(onWorkspaceWorkingTreeFileChange, onDotGitFileChange); + onFileChange(this.onFileChange, this, this.disposables); - onRelevantRepositoryChange(this.onFSChange, this, this.disposables); + // Relevate repository changes should trigger virtual document change events + onDotGitFileChange(this._onDidChangeRepository.fire, this._onDidChangeRepository, this.disposables); - const onRelevantGitChange = filterEvent(onRelevantRepositoryChange, uri => /\/\.git\//.test(uri.path)); - onRelevantGitChange(this._onDidChangeRepository.fire, this._onDidChangeRepository, this.disposables); + this.disposables.push(new FileEventLogger(onWorkspaceWorkingTreeFileChange, onDotGitFileChange, outputChannel)); const root = Uri.file(repository.root); this._sourceControl = scm.createSourceControl('git', 'Git', root); @@ -582,9 +684,9 @@ export class Repository implements Disposable { this._sourceControl.inputBox.validateInput = this.validateInput.bind(this); this.disposables.push(this._sourceControl); - this._mergeGroup = this._sourceControl.createResourceGroup('merge', localize('merge changes', "Merge Changes")); - this._indexGroup = this._sourceControl.createResourceGroup('index', localize('staged changes', "Staged Changes")); - this._workingTreeGroup = this._sourceControl.createResourceGroup('workingTree', localize('changes', "Changes")); + this._mergeGroup = this._sourceControl.createResourceGroup('merge', localize('merge changes', "MERGE CHANGES")); + this._indexGroup = this._sourceControl.createResourceGroup('index', localize('staged changes', "STAGED CHANGES")); + this._workingTreeGroup = this._sourceControl.createResourceGroup('workingTree', localize('changes', "CHANGES")); const updateIndexGroupVisibility = () => { const config = workspace.getConfiguration('git', root); @@ -622,7 +724,6 @@ export class Repository implements Disposable { this.disposables.push(progressManager); this.updateCommitTemplate(); - this.status(); } validateInput(text: string, position: number): SourceControlInputBoxValidation | undefined { @@ -909,6 +1010,10 @@ export class Repository implements Disposable { await this.run(Operation.CheckoutTracking, () => this.repository.checkout(treeish, [], { track: true })); } + async findTrackingBranches(upstreamRef: string): Promise { + return await this.run(Operation.FindTrackingBranches, () => this.repository.findTrackingBranches(upstreamRef)); + } + async getCommit(ref: string): Promise { return await this.repository.getCommit(ref); } @@ -979,11 +1084,12 @@ export class Repository implements Disposable { await this.maybeAutoStash(async () => { const config = workspace.getConfiguration('git', Uri.file(this.root)); const fetchOnPull = config.get('fetchOnPull'); + const tags = config.get('pullTags'); if (fetchOnPull) { - await this.repository.pull(rebase, undefined, undefined, { unshallow }); + await this.repository.pull(rebase, undefined, undefined, { unshallow, tags }); } else { - await this.repository.pull(rebase, remote, branch, { unshallow }); + await this.repository.pull(rebase, remote, branch, { unshallow, tags }); } }); }); @@ -1006,7 +1112,7 @@ export class Repository implements Disposable { await this.run(Operation.Push, () => this.repository.push(remote, name, setUpstream, undefined, forcePushMode)); } - async pushTags(remote?: string, forcePushMode?: ForcePushMode): Promise { + async pushFollowTags(remote?: string, forcePushMode?: ForcePushMode): Promise { await this.run(Operation.Push, () => this.repository.push(remote, undefined, false, true, forcePushMode)); } @@ -1039,11 +1145,12 @@ export class Repository implements Disposable { await this.maybeAutoStash(async () => { const config = workspace.getConfiguration('git', Uri.file(this.root)); const fetchOnPull = config.get('fetchOnPull'); + const tags = config.get('pullTags'); if (fetchOnPull) { - await this.repository.pull(rebase); + await this.repository.pull(rebase, undefined, undefined, { tags }); } else { - await this.repository.pull(rebase, remoteName, pullBranch); + await this.repository.pull(rebase, remoteName, pullBranch, { tags }); } const remote = this.remotes.find(r => r.name === remoteName); @@ -1156,7 +1263,7 @@ export class Repository implements Disposable { } // https://git-scm.com/docs/git-check-ignore#git-check-ignore--z - const child = this.repository.stream(['check-ignore', '-z', '--stdin'], { stdio: [null, null, null] }); + const child = this.repository.stream(['check-ignore', '-v', '-z', '--stdin'], { stdio: [null, null, null] }); child.stdin.end(filePaths.join('\0'), 'utf8'); const onExit = (exitCode: number) => { @@ -1164,8 +1271,7 @@ export class Repository implements Disposable { // nothing ignored resolve(new Set()); } else if (exitCode === 0) { - // paths are separated by the null-character - resolve(new Set(data.split('\0'))); + resolve(new Set(this.parseIgnoreCheck(data))); } else { if (/ is in submodule /.test(stderr)) { reject(new GitError({ stdout: data, stderr, exitCode, gitErrorCode: GitErrorCodes.IsInSubmodule })); @@ -1193,6 +1299,23 @@ export class Repository implements Disposable { }); } + // Parses output of `git check-ignore -v -z` and returns only those paths + // that are actually ignored by git. + // Matches to a negative pattern (starting with '!') are filtered out. + // See also https://git-scm.com/docs/git-check-ignore#_output. + private parseIgnoreCheck(raw: string): string[] { + const ignored = []; + const elements = raw.split('\0'); + for (let i = 0; i < elements.length; i += 4) { + const pattern = elements[i + 2]; + const path = elements[i + 3]; + if (pattern && !pattern.startsWith('!')) { + ignored.push(path); + } + } + return ignored; + } + private async run(operation: Operation, runOperation: () => Promise = () => Promise.resolve(null)): Promise { if (this.state !== RepositoryState.Idle) { throw new Error('Repository not initialized'); @@ -1430,7 +1553,7 @@ export class Repository implements Disposable { return result; } - private onFSChange(_uri: Uri): void { + private onFileChange(_uri: Uri): void { const config = workspace.getConfiguration('git'); const autorefresh = config.get('autorefresh'); diff --git a/extensions/git/src/test/git.test.ts b/extensions/git/src/test/git.test.ts index e28cf10d1..f0444ce57 100644 --- a/extensions/git/src/test/git.test.ts +++ b/extensions/git/src/test/git.test.ts @@ -172,6 +172,17 @@ suite('git', () => { { name: 'deps/spdlog4', path: 'deps/spdlog4', url: 'https://github.com/gabime/spdlog4.git' } ]); }); + + test('whitespace #74844', () => { + const sample = `[submodule "deps/spdlog"] + path = deps/spdlog + url = https://github.com/gabime/spdlog.git +`; + + assert.deepEqual(parseGitmodules(sample), [ + { name: 'deps/spdlog', path: 'deps/spdlog', url: 'https://github.com/gabime/spdlog.git' } + ]); + }); }); suite('parseGitCommit', () => { diff --git a/extensions/git/src/util.ts b/extensions/git/src/util.ts index 7bf81adcc..c4e938506 100644 --- a/extensions/git/src/util.ts +++ b/extensions/git/src/util.ts @@ -3,8 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Event } from 'vscode'; -import { dirname, sep } from 'path'; +import { Event, EventEmitter, Uri } from 'vscode'; +import { dirname, sep, join } from 'path'; import { Readable } from 'stream'; import * as fs from 'fs'; import * as byline from 'byline'; @@ -343,4 +343,20 @@ export function pathEquals(a: string, b: string): boolean { } return a === b; -} \ No newline at end of file +} + +export interface IFileWatcher extends IDisposable { + readonly event: Event; +} + +export function watch(location: string): IFileWatcher { + const dotGitWatcher = fs.watch(location); + const onDotGitFileChangeEmitter = new EventEmitter(); + dotGitWatcher.on('change', (_, e) => onDotGitFileChangeEmitter.fire(Uri.file(join(location, e as string)))); + dotGitWatcher.on('error', err => console.error(err)); + + return new class implements IFileWatcher { + event = onDotGitFileChangeEmitter.event; + dispose() { dotGitWatcher.close(); } + }; +} diff --git a/extensions/git/syntaxes/git-rebase.tmLanguage.json b/extensions/git/syntaxes/git-rebase.tmLanguage.json index a2c116bd0..0238d8a6f 100644 --- a/extensions/git/syntaxes/git-rebase.tmLanguage.json +++ b/extensions/git/syntaxes/git-rebase.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/textmate/git.tmbundle/commit/3f6ad2138200db14b57a090ecb2d2e733275ca3e", + "version": "https://github.com/textmate/git.tmbundle/commit/5870cf3f8abad3a6637bdf69250b5d2ded427dc4", "name": "Git Rebase Message", "scopeName": "text.git-rebase", "patterns": [ @@ -47,6 +47,15 @@ }, "match": "^\\s*(exec|x)\\s+(.*)$", "name": "meta.commit-command.git-rebase" + }, + { + "captures": { + "1": { + "name": "support.function.git-rebase" + } + }, + "match": "^\\s*(break|b)\\s*$", + "name": "meta.commit-command.git-rebase" } ] } \ No newline at end of file diff --git a/extensions/git/yarn.lock b/extensions/git/yarn.lock index f13ef93c3..1f2ea8aed 100644 --- a/extensions/git/yarn.lock +++ b/extensions/git/yarn.lock @@ -26,10 +26,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.51.tgz#b31d716fb8d58eeb95c068a039b9b6292817d5fb" integrity sha512-El3+WJk2D/ppWNd2X05aiP5l2k4EwF7KwheknQZls+I26eSICoWRhRIJ56jGgw2dqNGQ5LtNajmBU2ajS28EvQ== -"@types/node@^10.12.21": - version "10.12.21" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.21.tgz#7e8a0c34cf29f4e17a36e9bd0ea72d45ba03908e" - integrity sha512-CBgLNk4o3XMnqMc0rhb6lc77IwShMEglz05deDcn2lQxyXEZivfwgYJu7SMha9V5XcrP6qZuevTHV/QrN2vjKQ== +"@types/node@^10.14.8": + version "10.14.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9" + integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw== "@types/which@^1.0.28": version "1.0.28" @@ -325,6 +325,11 @@ vscode-nls@^4.0.0: resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.0.0.tgz#4001c8a6caba5cedb23a9c5ce1090395c0e44002" integrity sha512-qCfdzcH+0LgQnBpZA53bA32kzp9rpq/f66Som577ObeuDlFIrtbEJ+A/+CCxjIh4G8dpJYNCKIsxpRAHIfsbNw== +vscode-uri@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.0.0.tgz#2df704222f72b8a71ff266ba0830ed6c51ac1542" + integrity sha512-lWXWofDSYD8r/TIyu64MdwB4FaSirQ608PP/TzUyslyOeHGwQ0eTHUZeJrK1ILOmwUHaJtV693m2JoUYroUDpw== + which@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" diff --git a/extensions/go/language-configuration.json b/extensions/go/language-configuration.json index cf20e02f3..a5e06a56b 100644 --- a/extensions/go/language-configuration.json +++ b/extensions/go/language-configuration.json @@ -27,5 +27,11 @@ "indentationRules": { "increaseIndentPattern": "^.*(\\bcase\\b.*:|\\bdefault\\b:|(\\b(func|if|else|switch|select|for|struct)\\b.*)?{[^}\"'`]*|\\([^)\"'`]*)$", "decreaseIndentPattern": "^\\s*(\\bcase\\b.*:|\\bdefault\\b:|}[)}]*[),]?|\\)[,]?)$" + }, + "folding": { + "markers": { + "start": "^\\s*//\\s*#?region\\b", + "end": "^\\s*//\\s*#?endregion\\b" + } } } \ No newline at end of file diff --git a/extensions/go/package.json b/extensions/go/package.json index 97aced567..a91d729ad 100644 --- a/extensions/go/package.json +++ b/extensions/go/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "*" }, "scripts": { "update-grammar": "node ../../build/npm/update-grammar.js atom/language-go grammars/go.cson ./syntaxes/go.tmLanguage.json" diff --git a/extensions/groovy/package.json b/extensions/groovy/package.json index 9cb93f299..9bed57804 100644 --- a/extensions/groovy/package.json +++ b/extensions/groovy/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "*" }, "scripts": { "update-grammar": "node ../../build/npm/update-grammar.js textmate/groovy.tmbundle Syntaxes/Groovy.tmLanguage ./syntaxes/groovy.tmLanguage.json" diff --git a/extensions/grunt/package.json b/extensions/grunt/package.json index 74fa45202..f65cc6e62 100644 --- a/extensions/grunt/package.json +++ b/extensions/grunt/package.json @@ -5,6 +5,7 @@ "displayName": "Grunt support for VS Code", "version": "1.0.0", "icon": "images/grunt.png", + "license": "MIT", "engines": { "vscode": "*" }, @@ -19,7 +20,7 @@ "vscode-nls": "^4.0.0" }, "devDependencies": { - "@types/node": "^10.12.21" + "@types/node": "^10.14.8" }, "main": "./out/main", "activationEvents": [ diff --git a/extensions/grunt/src/main.ts b/extensions/grunt/src/main.ts index 09a812ac0..deec1587c 100644 --- a/extensions/grunt/src/main.ts +++ b/extensions/grunt/src/main.ts @@ -54,14 +54,14 @@ function isTestTask(name: string): boolean { let _channel: vscode.OutputChannel; function getOutputChannel(): vscode.OutputChannel { if (!_channel) { - _channel = vscode.window.createOutputChannel('Gulp Auto Detection'); + _channel = vscode.window.createOutputChannel('Grunt Auto Detection'); } return _channel; } function showError() { - vscode.window.showWarningMessage(localize('gulpTaskDetectError', 'Problem finding jake tasks. See the output for more information.'), - localize('jakeShowOutput', 'Go to output')).then(() => { + vscode.window.showWarningMessage(localize('gruntTaskDetectError', 'Problem finding grunt tasks. See the output for more information.'), + localize('gruntShowOutput', 'Go to output')).then(() => { getOutputChannel().show(true); }); } @@ -230,7 +230,7 @@ class TaskDetector { this.detectors.clear(); } - private updateWorkspaceFolders(added: vscode.WorkspaceFolder[], removed: vscode.WorkspaceFolder[]): void { + private updateWorkspaceFolders(added: readonly vscode.WorkspaceFolder[], removed: readonly vscode.WorkspaceFolder[]): void { for (let remove of removed) { let detector = this.detectors.get(remove.uri.toString()); if (detector) { @@ -272,7 +272,7 @@ class TaskDetector { private updateProvider(): void { if (!this.taskProvider && this.detectors.size > 0) { - this.taskProvider = vscode.workspace.registerTaskProvider('gulp', { + this.taskProvider = vscode.workspace.registerTaskProvider('grunt', { provideTasks: () => { return this.getTasks(); }, diff --git a/extensions/grunt/yarn.lock b/extensions/grunt/yarn.lock index 1bcd757b8..e6247e292 100644 --- a/extensions/grunt/yarn.lock +++ b/extensions/grunt/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@types/node@^10.12.21": - version "10.12.21" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.21.tgz#7e8a0c34cf29f4e17a36e9bd0ea72d45ba03908e" - integrity sha512-CBgLNk4o3XMnqMc0rhb6lc77IwShMEglz05deDcn2lQxyXEZivfwgYJu7SMha9V5XcrP6qZuevTHV/QrN2vjKQ== +"@types/node@^10.14.8": + version "10.14.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9" + integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw== vscode-nls@^4.0.0: version "4.0.0" diff --git a/extensions/gulp/package.json b/extensions/gulp/package.json index a9139780f..b602bf30c 100644 --- a/extensions/gulp/package.json +++ b/extensions/gulp/package.json @@ -5,6 +5,7 @@ "displayName": "%displayName%", "version": "1.0.0", "icon": "images/gulp.png", + "license": "MIT", "engines": { "vscode": "*" }, @@ -19,7 +20,7 @@ "vscode-nls": "^4.0.0" }, "devDependencies": { - "@types/node": "^10.12.21" + "@types/node": "^10.14.8" }, "main": "./out/main", "activationEvents": [ diff --git a/extensions/gulp/src/main.ts b/extensions/gulp/src/main.ts index 653e34bd2..ddc07a2f5 100644 --- a/extensions/gulp/src/main.ts +++ b/extensions/gulp/src/main.ts @@ -67,6 +67,24 @@ function showError() { }); } +async function findGulpCommand(rootPath: string): Promise { + let gulpCommand: string; + let platform = process.platform; + if (platform === 'win32' && await exists(path.join(rootPath, 'node_modules', '.bin', 'gulp.cmd'))) { + const globalGulp = path.join(process.env.APPDATA ? process.env.APPDATA : '', 'npm', 'gulp.cmd'); + if (await exists(globalGulp)) { + gulpCommand = '"' + globalGulp + '"'; + } else { + 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'; + } + return gulpCommand; +} + interface GulpTaskDefinition extends vscode.TaskDefinition { task: string; file?: string; @@ -77,7 +95,9 @@ class FolderDetector { private fileWatcher: vscode.FileSystemWatcher | undefined; private promise: Thenable | undefined; - constructor(private _workspaceFolder: vscode.WorkspaceFolder) { + constructor( + private _workspaceFolder: vscode.WorkspaceFolder, + private _gulpCommand: Promise) { } public get workspaceFolder(): vscode.WorkspaceFolder { @@ -97,10 +117,28 @@ class FolderDetector { } public async getTasks(): Promise { - if (!this.promise) { - this.promise = this.computeTasks(); + if (this.isEnabled()) { + if (!this.promise) { + this.promise = this.computeTasks(); + } + return this.promise; + } else { + return []; + } + } + + public async getTask(_task: vscode.Task): Promise { + const gulpTask = (_task.definition).task; + if (gulpTask) { + let kind: GulpTaskDefinition = { + type: 'gulp', + task: gulpTask + }; + let options: vscode.ShellExecutionOptions = { cwd: this.workspaceFolder.uri.fsPath }; + let task = new vscode.Task(kind, this.workspaceFolder, gulpTask, 'gulp', new vscode.ShellExecution(await this._gulpCommand, [gulpTask], options)); + return task; } - return this.promise; + return undefined; } private async computeTasks(): Promise { @@ -117,22 +155,7 @@ class FolderDetector { } } - let gulpCommand: string; - let platform = process.platform; - if (platform === 'win32' && await exists(path.join(rootPath!, 'node_modules', '.bin', 'gulp.cmd'))) { - const globalGulp = path.join(process.env.APPDATA ? process.env.APPDATA : '', 'npm', 'gulp.cmd'); - if (await exists(globalGulp)) { - gulpCommand = '"' + globalGulp + '"'; - } else { - 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`; + let commandLine = `${await this._gulpCommand} --tasks-simple --no-color`; try { let { stdout, stderr } = await exec(commandLine, { cwd: rootPath }); if (stderr && stderr.length > 0) { @@ -151,7 +174,7 @@ class FolderDetector { 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)); + let task = new vscode.Task(kind, this.workspaceFolder, line, 'gulp', new vscode.ShellExecution(await this._gulpCommand, [line], options)); result.push(task); let lowerCaseLine = line.toLowerCase(); if (isBuildTask(lowerCaseLine)) { @@ -209,7 +232,7 @@ class TaskDetector { this.detectors.clear(); } - private updateWorkspaceFolders(added: vscode.WorkspaceFolder[], removed: vscode.WorkspaceFolder[]): void { + private updateWorkspaceFolders(added: readonly vscode.WorkspaceFolder[], removed: readonly vscode.WorkspaceFolder[]): void { for (let remove of removed) { let detector = this.detectors.get(remove.uri.toString()); if (detector) { @@ -218,9 +241,9 @@ class TaskDetector { } } for (let add of added) { - let detector = new FolderDetector(add); + let detector = new FolderDetector(add, findGulpCommand(add.uri.fsPath)); + this.detectors.set(add.uri.toString(), detector); if (detector.isEnabled()) { - this.detectors.set(add.uri.toString(), detector); detector.start(); } } @@ -229,18 +252,16 @@ class TaskDetector { private updateConfiguration(): void { for (let detector of this.detectors.values()) { - if (!detector.isEnabled()) { - detector.dispose(); - this.detectors.delete(detector.workspaceFolder.uri.toString()); - } + 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); + let detector = new FolderDetector(folder, findGulpCommand(folder.uri.fsPath)); + this.detectors.set(folder.uri.toString(), detector); if (detector.isEnabled()) { - this.detectors.set(folder.uri.toString(), detector); detector.start(); } } @@ -251,12 +272,13 @@ class TaskDetector { private updateProvider(): void { if (!this.taskProvider && this.detectors.size > 0) { + const thisCapture = this; this.taskProvider = vscode.workspace.registerTaskProvider('gulp', { - provideTasks: () => { - return this.getTasks(); + provideTasks(): Promise { + return thisCapture.getTasks(); }, - resolveTask(_task: vscode.Task): vscode.Task | undefined { - return undefined; + resolveTask(_task: vscode.Task): Promise { + return thisCapture.getTask(_task); } }); } @@ -291,6 +313,25 @@ class TaskDetector { }); } } + + public async getTask(task: vscode.Task): Promise { + if (this.detectors.size === 0) { + return undefined; + } else if (this.detectors.size === 1) { + return this.detectors.values().next().value.getTask(task); + } else { + if ((task.scope === vscode.TaskScope.Workspace) || (task.scope === vscode.TaskScope.Global)) { + // Not supported, we don't have enough info to create the task. + return undefined; + } else if (task.scope) { + const detector = this.detectors.get(task.scope.uri.toString()); + if (detector) { + return detector.getTask(task); + } + } + return undefined; + } + } } let detector: TaskDetector; diff --git a/extensions/gulp/yarn.lock b/extensions/gulp/yarn.lock index 1bcd757b8..e6247e292 100644 --- a/extensions/gulp/yarn.lock +++ b/extensions/gulp/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@types/node@^10.12.21": - version "10.12.21" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.21.tgz#7e8a0c34cf29f4e17a36e9bd0ea72d45ba03908e" - integrity sha512-CBgLNk4o3XMnqMc0rhb6lc77IwShMEglz05deDcn2lQxyXEZivfwgYJu7SMha9V5XcrP6qZuevTHV/QrN2vjKQ== +"@types/node@^10.14.8": + version "10.14.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9" + integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw== vscode-nls@^4.0.0: version "4.0.0" diff --git a/extensions/handlebars/cgmanifest.json b/extensions/handlebars/cgmanifest.json index 4d30387e9..39f8efc67 100644 --- a/extensions/handlebars/cgmanifest.json +++ b/extensions/handlebars/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "daaain/Handlebars", "repositoryUrl": "https://github.com/daaain/Handlebars", - "commitHash": "790f2b0222098a3a236bd9e91bb9a039eeca4d8e" + "commitHash": "85a153a6f759df4e8da7533e1b3651f007867c51" } }, "licenseDetail": [ @@ -29,7 +29,7 @@ "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." ], "license": "MIT", - "version": "1.7.1" + "version": "1.8.0" } ], "version": 1 diff --git a/extensions/handlebars/package.json b/extensions/handlebars/package.json index fdb8d4fc7..37b63ee54 100644 --- a/extensions/handlebars/package.json +++ b/extensions/handlebars/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "0.10.x" }, diff --git a/extensions/handlebars/syntaxes/Handlebars.tmLanguage.json b/extensions/handlebars/syntaxes/Handlebars.tmLanguage.json index 957f16ae0..be8b06fa0 100644 --- a/extensions/handlebars/syntaxes/Handlebars.tmLanguage.json +++ b/extensions/handlebars/syntaxes/Handlebars.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/daaain/Handlebars/commit/790f2b0222098a3a236bd9e91bb9a039eeca4d8e", + "version": "https://github.com/daaain/Handlebars/commit/85a153a6f759df4e8da7533e1b3651f007867c51", "name": "Handlebars", "scopeName": "text.html.handlebars", "patterns": [ @@ -653,7 +653,7 @@ ] }, "else_token": { - "begin": "(\\{\\{)(~?else)(@?\\s(if)\\s([-a-zA-Z0-9_\\./]+))?", + "begin": "(\\{\\{)(~?else)(@?\\s(if)\\s([-a-zA-Z0-9_\\.\\(\\s\\)/]+))?", "end": "(~?\\}\\}\\}*)", "name": "meta.function.inline.else.handlebars", "beginCaptures": { diff --git a/extensions/hlsl/package.json b/extensions/hlsl/package.json index f68ce50ee..b2f635b4a 100644 --- a/extensions/hlsl/package.json +++ b/extensions/hlsl/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "*" }, "scripts": { "update-grammar": "node ../../build/npm/update-grammar.js tgjones/shaders-tmLanguage grammars/hlsl.json ./syntaxes/hlsl.tmLanguage.json" diff --git a/extensions/html-language-features/client/src/htmlMain.ts b/extensions/html-language-features/client/src/htmlMain.ts index 6fe901907..5f98f732b 100644 --- a/extensions/html-language-features/client/src/htmlMain.ts +++ b/extensions/html-language-features/client/src/htmlMain.ts @@ -8,7 +8,7 @@ import * as fs from 'fs'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); -import { languages, ExtensionContext, IndentAction, Position, TextDocument, Range, CompletionItem, CompletionItemKind, SnippetString, workspace, SelectionRange } from 'vscode'; +import { languages, ExtensionContext, IndentAction, Position, TextDocument, Range, CompletionItem, CompletionItemKind, SnippetString, workspace } from 'vscode'; import { LanguageClient, LanguageClientOptions, ServerOptions, TransportKind, RequestType, TextDocumentPositionParams } from 'vscode-languageclient'; import { EMPTY_ELEMENTS } from './htmlEmptyTagsShared'; import { activateTagClosing } from './tagClosing'; @@ -87,26 +87,6 @@ export function activate(context: ExtensionContext) { } }); toDispose.push(disposable); - - documentSelector.forEach(selector => { - context.subscriptions.push(languages.registerSelectionRangeProvider(selector, { - async provideSelectionRanges(document: TextDocument, positions: Position[]): Promise { - const textDocument = client.code2ProtocolConverter.asTextDocumentIdentifier(document); - const rawResult = await client.sendRequest('$/textDocument/selectionRanges', { textDocument, positions: positions.map(client.code2ProtocolConverter.asPosition) }); - if (Array.isArray(rawResult)) { - return rawResult.map(rawSelectionRanges => { - return rawSelectionRanges.reduceRight((parent: SelectionRange | undefined, selectionRange: SelectionRange) => { - return { - range: client.protocol2CodeConverter.asRange(selectionRange.range), - parent - }; - }, undefined)!; - }); - } - return []; - } - })); - }); }); languages.setLanguageConfiguration('html', { diff --git a/extensions/html-language-features/client/src/tagClosing.ts b/extensions/html-language-features/client/src/tagClosing.ts index 35511e63f..298edcdaa 100644 --- a/extensions/html-language-features/client/src/tagClosing.ts +++ b/extensions/html-language-features/client/src/tagClosing.ts @@ -32,7 +32,7 @@ export function activateTagClosing(tagProvider: (document: TextDocument, positio isEnabled = true; } - function onDidChangeTextDocument(document: TextDocument, changes: TextDocumentContentChangeEvent[]) { + function onDidChangeTextDocument(document: TextDocument, changes: readonly TextDocumentContentChangeEvent[]) { if (!isEnabled) { return; } diff --git a/extensions/html-language-features/package.json b/extensions/html-language-features/package.json index e44dc9f71..3985c07b9 100644 --- a/extensions/html-language-features/package.json +++ b/extensions/html-language-features/package.json @@ -5,6 +5,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", "engines": { "vscode": "0.10.x" @@ -172,14 +173,20 @@ "description": "%html.trace.server.desc%" } } - } + }, + "jsonValidation": [ + { + "fileMatch": "*.html-data.json", + "url": "https://raw.githubusercontent.com/Microsoft/vscode-html-languageservice/master/docs/customData.schema.json" + } + ] }, "dependencies": { "vscode-extension-telemetry": "0.1.1", - "vscode-languageclient": "^5.2.1", - "vscode-nls": "^4.0.0" + "vscode-languageclient": "^5.3.0-next.6", + "vscode-nls": "^4.1.1" }, "devDependencies": { - "@types/node": "^10.12.21" + "@types/node": "^10.14.8" } } diff --git a/extensions/html-language-features/server/package.json b/extensions/html-language-features/server/package.json index 74aa5e694..95a97f111 100644 --- a/extensions/html-language-features/server/package.json +++ b/extensions/html-language-features/server/package.json @@ -9,16 +9,16 @@ }, "main": "./out/htmlServerMain", "dependencies": { - "vscode-css-languageservice": "^4.0.2-next.3", - "vscode-html-languageservice": "^3.0.0-next.6", - "vscode-languageserver": "^5.3.0-next.2", - "vscode-languageserver-types": "^3.14.0", - "vscode-nls": "^4.0.0", - "vscode-uri": "^1.0.6" + "vscode-css-languageservice": "^4.0.3-next.1", + "vscode-html-languageservice": "^3.0.4-next.0", + "vscode-languageserver": "^5.3.0-next.8", + "vscode-languageserver-types": "3.15.0-next.2", + "vscode-nls": "^4.1.1", + "vscode-uri": "^2.0.3" }, "devDependencies": { "@types/mocha": "2.2.33", - "@types/node": "^10.12.21", + "@types/node": "^10.14.8", "glob": "^7.1.2", "mocha": "^5.2.0", "mocha-junit-reporter": "^1.17.0", diff --git a/extensions/html-language-features/server/src/htmlServerMain.ts b/extensions/html-language-features/server/src/htmlServerMain.ts index 7974284bd..01b43d9a9 100644 --- a/extensions/html-language-features/server/src/htmlServerMain.ts +++ b/extensions/html-language-features/server/src/htmlServerMain.ts @@ -15,7 +15,7 @@ import { getLanguageModes, LanguageModes, Settings } from './modes/languageModes import { format } from './modes/formatting'; import { pushAll } from './utils/arrays'; import { getDocumentContext } from './utils/documentContext'; -import uri from 'vscode-uri'; +import { URI } from 'vscode-uri'; import { formatError, runSafe, runSafeAsync } from './utils/runner'; import { getFoldingRanges } from './modes/htmlFolding'; @@ -38,8 +38,7 @@ process.on('uncaughtException', (e: any) => { console.error(formatError(`Unhandled exception`, e)); }); -// Create a simple text document manager. The text document manager -// supports full document sync only +// Create a text document manager. const documents: TextDocuments = new TextDocuments(); // Make the text document manager listen on the connection // for open, change and close text document events @@ -85,7 +84,7 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { if (!Array.isArray(workspaceFolders)) { workspaceFolders = []; if (params.rootPath) { - workspaceFolders.push({ name: '', uri: uri.file(params.rootPath).toString() }); + workspaceFolders.push({ name: '', uri: URI.file(params.rootPath).toString() }); } } @@ -97,7 +96,7 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { get folders() { return workspaceFolders; } }; - languageModes = getLanguageModes(initializationOptions ? initializationOptions.embeddedLanguages : { css: true, javascript: true }, workspace, providers); + languageModes = getLanguageModes(initializationOptions ? initializationOptions.embeddedLanguages : { css: true, javascript: true }, workspace, params.capabilities, providers); documents.onDidClose(e => { languageModes.onDocumentRemoved(e.document); @@ -136,7 +135,8 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { signatureHelpProvider: { triggerCharacters: ['('] }, referencesProvider: true, colorProvider: {}, - foldingRangeProvider: true + foldingRangeProvider: true, + selectionRangeProvider: true }; return { capabilities }; }); @@ -455,7 +455,7 @@ connection.onFoldingRanges((params, token) => { }, null, `Error while computing folding regions for ${params.textDocument.uri}`, token); }); -connection.onRequest('$/textDocument/selectionRanges', async (params, token) => { +connection.onSelectionRanges((params, token) => { return runSafe(() => { const document = documents.get(params.textDocument.uri); const positions: Position[] = params.positions; @@ -466,8 +466,8 @@ connection.onRequest('$/textDocument/selectionRanges', async (params, token) => return htmlMode.getSelectionRanges(document, positions); } } - return Promise.resolve(null); - }, null, `Error while computing selection ranges for ${params.textDocument.uri}`, token); + return []; + }, [], `Error while computing selection ranges for ${params.textDocument.uri}`, token); }); diff --git a/extensions/html-language-features/server/src/modes/cssMode.ts b/extensions/html-language-features/server/src/modes/cssMode.ts index 168c7ceff..6e60c32d8 100644 --- a/extensions/html-language-features/server/src/modes/cssMode.ts +++ b/extensions/html-language-features/server/src/modes/cssMode.ts @@ -5,13 +5,12 @@ import { LanguageModelCache, getLanguageModelCache } from '../languageModelCache'; import { TextDocument, Position, Range, CompletionList } from 'vscode-languageserver-types'; -import { getCSSLanguageService, Stylesheet, FoldingRange } from 'vscode-css-languageservice'; +import { Stylesheet, FoldingRange, LanguageService as CSSLanguageService } from 'vscode-css-languageservice'; import { LanguageMode, Workspace } from './languageModes'; import { HTMLDocumentRegions, CSS_STYLE_RULE } from './embeddedSupport'; import { Color } from 'vscode-languageserver'; -export function getCSSMode(documentRegions: LanguageModelCache, workspace: Workspace): LanguageMode { - let cssLanguageService = getCSSLanguageService(); +export function getCSSMode(cssLanguageService: CSSLanguageService, documentRegions: LanguageModelCache, workspace: Workspace): LanguageMode { let embeddedCSSDocuments = getLanguageModelCache(10, 60, document => documentRegions.get(document).getEmbeddedDocument('css')); let cssStylesheets = getLanguageModelCache(10, 60, document => cssLanguageService.parseStylesheet(document)); diff --git a/extensions/html-language-features/server/src/modes/htmlMode.ts b/extensions/html-language-features/server/src/modes/htmlMode.ts index 09efb996f..57249a65b 100644 --- a/extensions/html-language-features/server/src/modes/htmlMode.ts +++ b/extensions/html-language-features/server/src/modes/htmlMode.ts @@ -15,7 +15,7 @@ export function getHTMLMode(htmlLanguageService: HTMLLanguageService, workspace: getId() { return 'html'; }, - getSelectionRanges(document: TextDocument, positions: Position[]): SelectionRange[][] { + getSelectionRanges(document: TextDocument, positions: Position[]): SelectionRange[] { return htmlLanguageService.getSelectionRanges(document, positions); }, doComplete(document: TextDocument, position: Position, settings = workspace.settings) { diff --git a/extensions/html-language-features/server/src/modes/languageModes.ts b/extensions/html-language-features/server/src/modes/languageModes.ts index 94c0b04a2..d07e0bd80 100644 --- a/extensions/html-language-features/server/src/modes/languageModes.ts +++ b/extensions/html-language-features/server/src/modes/languageModes.ts @@ -3,18 +3,15 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { getLanguageService as getHTMLLanguageService, DocumentContext, IHTMLDataProvider, SelectionRange } from 'vscode-html-languageservice'; -import { - CompletionItem, Location, SignatureHelp, Definition, TextEdit, TextDocument, Diagnostic, DocumentLink, Range, - Hover, DocumentHighlight, CompletionList, Position, FormattingOptions, SymbolInformation, FoldingRange -} from 'vscode-languageserver-types'; -import { ColorInformation, ColorPresentation, Color, WorkspaceFolder } from 'vscode-languageserver'; - +import { getCSSLanguageService } from 'vscode-css-languageservice'; +import { ClientCapabilities, DocumentContext, getLanguageService as getHTMLLanguageService, IHTMLDataProvider, SelectionRange } from 'vscode-html-languageservice'; +import { Color, ColorInformation, ColorPresentation, WorkspaceFolder } from 'vscode-languageserver'; +import { CompletionItem, CompletionList, Definition, Diagnostic, DocumentHighlight, DocumentLink, FoldingRange, FormattingOptions, Hover, Location, Position, Range, SignatureHelp, SymbolInformation, TextDocument, TextEdit } from 'vscode-languageserver-types'; import { getLanguageModelCache, LanguageModelCache } from '../languageModelCache'; -import { getDocumentRegions, HTMLDocumentRegions } from './embeddedSupport'; import { getCSSMode } from './cssMode'; -import { getJavaScriptMode } from './javascriptMode'; +import { getDocumentRegions, HTMLDocumentRegions } from './embeddedSupport'; import { getHTMLMode } from './htmlMode'; +import { getJavaScriptMode } from './javascriptMode'; export { ColorInformation, ColorPresentation, Color }; @@ -31,7 +28,7 @@ export interface Workspace { export interface LanguageMode { getId(): string; - getSelectionRanges?: (document: TextDocument, positions: Position[]) => SelectionRange[][]; + getSelectionRanges?: (document: TextDocument, positions: Position[]) => SelectionRange[]; doValidation?: (document: TextDocument, settings?: Settings) => Diagnostic[]; doComplete?: (document: TextDocument, position: Position, settings?: Settings) => CompletionList; doResolve?: (document: TextDocument, item: CompletionItem) => CompletionItem; @@ -66,8 +63,9 @@ export interface LanguageModeRange extends Range { attributeValue?: boolean; } -export function getLanguageModes(supportedLanguages: { [languageId: string]: boolean; }, workspace: Workspace, customDataProviders?: IHTMLDataProvider[]): LanguageModes { - const htmlLanguageService = getHTMLLanguageService({ customDataProviders }); +export function getLanguageModes(supportedLanguages: { [languageId: string]: boolean; }, workspace: Workspace, clientCapabilities: ClientCapabilities, customDataProviders?: IHTMLDataProvider[]): LanguageModes { + const htmlLanguageService = getHTMLLanguageService({ customDataProviders, clientCapabilities }); + const cssLanguageService = getCSSLanguageService({ clientCapabilities }); let documentRegions = getLanguageModelCache(10, 60, document => getDocumentRegions(htmlLanguageService, document)); @@ -77,7 +75,7 @@ export function getLanguageModes(supportedLanguages: { [languageId: string]: boo let modes = Object.create(null); modes['html'] = getHTMLMode(htmlLanguageService, workspace); if (supportedLanguages['css']) { - modes['css'] = getCSSMode(documentRegions, workspace); + modes['css'] = getCSSMode(cssLanguageService, documentRegions, workspace); } if (supportedLanguages['javascript']) { modes['javascript'] = getJavaScriptMode(documentRegions); diff --git a/extensions/html-language-features/server/src/modes/pathCompletion.ts b/extensions/html-language-features/server/src/modes/pathCompletion.ts index cb3a20f8e..b7d7c1e72 100644 --- a/extensions/html-language-features/server/src/modes/pathCompletion.ts +++ b/extensions/html-language-features/server/src/modes/pathCompletion.ts @@ -7,7 +7,7 @@ import { TextDocument, CompletionItemKind, CompletionItem, TextEdit, Range, Posi import { WorkspaceFolder } from 'vscode-languageserver'; import * as path from 'path'; import * as fs from 'fs'; -import URI from 'vscode-uri'; +import { URI } from 'vscode-uri'; import { ICompletionParticipant } from 'vscode-html-languageservice'; import { startsWith } from '../utils/strings'; import { contains } from '../utils/arrays'; @@ -108,11 +108,12 @@ function pathToSuggestion(p: string, valueBeforeCursor: string, fullValue: strin // Find the last slash before cursor, and calculate the start of replace range from there const valueAfterLastSlash = fullValue.slice(lastIndexOfSlash + 1); const startPos = shiftPosition(range.end, -1 - valueAfterLastSlash.length); - // If whitespace exists, replace until it - const whiteSpaceIndex = valueAfterLastSlash.indexOf(' '); + + // If whitespace exists, replace until there is no more + const whitespaceIndex = valueAfterLastSlash.indexOf(' '); let endPos; - if (whiteSpaceIndex !== -1) { - endPos = shiftPosition(startPos, whiteSpaceIndex); + if (whitespaceIndex !== -1) { + endPos = shiftPosition(startPos, whitespaceIndex); } else { endPos = shiftPosition(range.end, -1); } @@ -160,6 +161,7 @@ function shiftRange(range: Range, startOffset: number, endOffset: number): Range const PATH_TAG_AND_ATTR: { [tag: string]: string | string[] } = { // HTML 4 a: 'href', + area: 'href', body: 'background', del: 'cite', form: 'action', @@ -176,7 +178,7 @@ const PATH_TAG_AND_ATTR: { [tag: string]: string | string[] } = { command: 'icon', embed: 'src', html: 'manifest', - input: 'formaction', + input: ['src', 'formaction'], source: 'src', track: 'src', video: ['src', 'poster'] diff --git a/extensions/html-language-features/server/src/test/completions.test.ts b/extensions/html-language-features/server/src/test/completions.test.ts index c28daf9f0..aaba72add 100644 --- a/extensions/html-language-features/server/src/test/completions.test.ts +++ b/extensions/html-language-features/server/src/test/completions.test.ts @@ -5,10 +5,11 @@ import 'mocha'; import * as assert from 'assert'; import * as path from 'path'; -import Uri from 'vscode-uri'; +import { URI } from 'vscode-uri'; import { TextDocument, CompletionList, CompletionItemKind } from 'vscode-languageserver-types'; import { getLanguageModes } from '../modes/languageModes'; import { WorkspaceFolder } from 'vscode-languageserver'; +import { ClientCapabilities } from 'vscode-html-languageservice'; export interface ItemDescription { label: string; @@ -58,8 +59,8 @@ export function testCompletionFor(value: string, expected: { count?: number, ite let document = TextDocument.create(uri, 'html', 0, value); let position = document.positionAt(offset); - var languageModes = getLanguageModes({ css: true, javascript: true }, workspace); - var mode = languageModes.getModeAtPosition(document, position)!; + const languageModes = getLanguageModes({ css: true, javascript: true }, workspace, ClientCapabilities.LATEST); + const mode = languageModes.getModeAtPosition(document, position)!; let list = mode.doComplete!(document, position); @@ -95,9 +96,9 @@ suite('HTML Path Completion', () => { }; const fixtureRoot = path.resolve(__dirname, '../../src/test/pathCompletionFixtures'); - const fixtureWorkspace = { name: 'fixture', uri: Uri.file(fixtureRoot).toString() }; - const indexHtmlUri = Uri.file(path.resolve(fixtureRoot, 'index.html')).toString(); - const aboutHtmlUri = Uri.file(path.resolve(fixtureRoot, 'about/about.html')).toString(); + const fixtureWorkspace = { name: 'fixture', uri: URI.file(fixtureRoot).toString() }; + const indexHtmlUri = URI.file(path.resolve(fixtureRoot, 'index.html')).toString(); + const aboutHtmlUri = URI.file(path.resolve(fixtureRoot, 'about/about.html')).toString(); test('Basics - Correct label/kind/result/command', () => { testCompletionFor(' - ${this.getStyles(sourceUri, nonce, config, state)} - + data-settings="${escapeAttribute(JSON.stringify(initialData))}" + data-strings="${escapeAttribute(JSON.stringify(previewStrings))}" + data-state="${escapeAttribute(JSON.stringify(state || {}))}"> + + ${this.getStyles(resourceProvider, sourceUri, config, state)} + ${body}
- ${this.getScripts(nonce)} + ${this.getScripts(resourceProvider, nonce)} `; } @@ -103,13 +109,13 @@ export class MarkdownContentProvider { `; } - private extensionResourcePath(mediaFile: string): string { - return vscode.Uri.file(this.context.asAbsolutePath(path.join('media', mediaFile))) - .with({ scheme: 'vscode-resource' }) - .toString(); + private extensionResourcePath(resourceProvider: WebviewResourceProvider, mediaFile: string): string { + const webviewResource = resourceProvider.toWebviewResource( + vscode.Uri.file(this.context.asAbsolutePath(path.join('media', mediaFile)))); + return webviewResource.toString(); } - private fixHref(resource: vscode.Uri, href: string): string { + private fixHref(resourceProvider: WebviewResourceProvider, resource: vscode.Uri, href: string): string { if (!href) { return href; } @@ -120,42 +126,36 @@ export class MarkdownContentProvider { // Assume it must be a local file if (path.isAbsolute(href)) { - return vscode.Uri.file(href) - .with({ scheme: 'vscode-resource' }) - .toString(); + return resourceProvider.toWebviewResource(vscode.Uri.file(href)).toString(); } // Use a workspace relative path if there is a workspace const root = vscode.workspace.getWorkspaceFolder(resource); if (root) { - return vscode.Uri.file(path.join(root.uri.fsPath, href)) - .with({ scheme: 'vscode-resource' }) - .toString(); + return resourceProvider.toWebviewResource(vscode.Uri.file(path.join(root.uri.fsPath, href))).toString(); } // Otherwise look relative to the markdown file - return vscode.Uri.file(path.join(path.dirname(resource.fsPath), href)) - .with({ scheme: 'vscode-resource' }) - .toString(); + return resourceProvider.toWebviewResource(vscode.Uri.file(path.join(path.dirname(resource.fsPath), href))).toString(); } - private computeCustomStyleSheetIncludes(resource: vscode.Uri, config: MarkdownPreviewConfiguration): string { - if (Array.isArray(config.styles)) { - return config.styles.map(style => { - return ``; - }).join('\n'); + private computeCustomStyleSheetIncludes(resourceProvider: WebviewResourceProvider, resource: vscode.Uri, config: MarkdownPreviewConfiguration): string { + if (!Array.isArray(config.styles)) { + return ''; + } + const out: string[] = []; + for (const style of config.styles) { + out.push(``); } - return ''; + return out.join('\n'); } - private getSettingsOverrideStyles(nonce: string, config: MarkdownPreviewConfiguration): string { - return ``; + private getSettingsOverrideStyles(config: MarkdownPreviewConfiguration): string { + return [ + config.fontFamily ? `--vscode-markdown-font-family: ${config.fontFamily};` : '', + isNaN(config.fontSize) ? '' : `--vscode-markdown-font-size: ${config.fontSize}px;`, + isNaN(config.lineHeight) ? '' : `--vscode-markdown-line-height: ${config.lineHeight};`, + ].join(' '); } private getImageStabilizerStyles(state?: any) { @@ -173,37 +173,47 @@ export class MarkdownContentProvider { return ret; } - private getStyles(resource: vscode.Uri, nonce: string, config: MarkdownPreviewConfiguration, state?: any): string { - const baseStyles = this.contributionProvider.contributions.previewStyles - .map(resource => ``) - .join('\n'); + private getStyles(resourceProvider: WebviewResourceProvider, resource: vscode.Uri, config: MarkdownPreviewConfiguration, state?: any): string { + const baseStyles: string[] = []; + for (const resource of this.contributionProvider.contributions.previewStyles) { + baseStyles.push(``); + } - return `${baseStyles} - ${this.getSettingsOverrideStyles(nonce, config)} - ${this.computeCustomStyleSheetIncludes(resource, config)} + return `${baseStyles.join('\n')} + ${this.computeCustomStyleSheetIncludes(resourceProvider, resource, config)} ${this.getImageStabilizerStyles(state)}`; } - private getScripts(nonce: string): string { - return this.contributionProvider.contributions.previewScripts - .map(resource => ``) - .join('\n'); + private getScripts(resourceProvider: WebviewResourceProvider, nonce: string): string { + const out: string[] = []; + for (const resource of this.contributionProvider.contributions.previewScripts) { + out.push(``); + } + return out.join('\n'); } - private getCspForResource(resource: vscode.Uri, nonce: string): string { + private getCsp( + provider: WebviewResourceProvider, + resource: vscode.Uri, + nonce: string + ): string { + const rule = provider.cspSource; switch (this.cspArbiter.getSecurityLevelForResource(resource)) { case MarkdownPreviewSecurityLevel.AllowInsecureContent: - return ``; + return ``; case MarkdownPreviewSecurityLevel.AllowInsecureLocalContent: - return ``; + return ``; case MarkdownPreviewSecurityLevel.AllowScriptsAndAllContent: return ''; case MarkdownPreviewSecurityLevel.Strict: default: - return ``; + return ``; } } } diff --git a/extensions/markdown-language-features/src/features/previewManager.ts b/extensions/markdown-language-features/src/features/previewManager.ts index aed629428..3fc810690 100644 --- a/extensions/markdown-language-features/src/features/previewManager.ts +++ b/extensions/markdown-language-features/src/features/previewManager.ts @@ -6,32 +6,32 @@ import * as vscode from 'vscode'; import { Logger } from '../logger'; import { MarkdownContributionProvider } from '../markdownExtensions'; -import { disposeAll } from '../util/dispose'; +import { disposeAll, Disposable } from '../util/dispose'; import { MarkdownFileTopmostLineMonitor } from '../util/topmostLineMonitor'; import { MarkdownPreview, PreviewSettings } from './preview'; import { MarkdownPreviewConfigurationManager } from './previewConfig'; import { MarkdownContentProvider } from './previewContentProvider'; -export class MarkdownPreviewManager implements vscode.WebviewPanelSerializer { +export class MarkdownPreviewManager extends Disposable implements vscode.WebviewPanelSerializer { private static readonly markdownPreviewActiveContextKey = 'markdownPreviewFocus'; private readonly _topmostLineMonitor = new MarkdownFileTopmostLineMonitor(); private readonly _previewConfigurations = new MarkdownPreviewConfigurationManager(); private readonly _previews: MarkdownPreview[] = []; private _activePreview: MarkdownPreview | undefined = undefined; - private readonly _disposables: vscode.Disposable[] = []; public constructor( private readonly _contentProvider: MarkdownContentProvider, private readonly _logger: Logger, private readonly _contributions: MarkdownContributionProvider ) { - this._disposables.push(vscode.window.registerWebviewPanelSerializer(MarkdownPreview.viewType, this)); + super(); + this._register(vscode.window.registerWebviewPanelSerializer(MarkdownPreview.viewType, this)); } public dispose(): void { - disposeAll(this._disposables); + super.dispose(); disposeAll(this._previews); } @@ -65,6 +65,10 @@ export class MarkdownPreviewManager implements vscode.WebviewPanelSerializer { return this._activePreview && this._activePreview.resource; } + public get activePreviewResourceColumn() { + return this._activePreview && this._activePreview.resourceColumn; + } + public toggleLock() { const preview = this._activePreview; if (preview) { @@ -110,6 +114,7 @@ export class MarkdownPreviewManager implements vscode.WebviewPanelSerializer { const preview = MarkdownPreview.create( resource, previewSettings.previewColumn, + previewSettings.resourceColumn, previewSettings.locked, this._contentProvider, this._previewConfigurations, diff --git a/extensions/markdown-language-features/src/markdownEngine.ts b/extensions/markdown-language-features/src/markdownEngine.ts index 0c10f5540..0cc75bfe8 100644 --- a/extensions/markdown-language-features/src/markdownEngine.ts +++ b/extensions/markdown-language-features/src/markdownEngine.ts @@ -225,7 +225,6 @@ export class MarkdownEngine { return normalizeLink(externalSchemeUri.toString(true)); } - // Assume it must be an relative or absolute file path // Use a fake scheme to avoid parse warnings let uri = vscode.Uri.parse(`vscode-resource:${link}`); @@ -262,7 +261,7 @@ export class MarkdownEngine { const validateLink = md.validateLink; md.validateLink = (link: string) => { // support file:// links - return validateLink(link) || link.indexOf('file:') === 0; + return validateLink(link) || link.startsWith('file:') || /^data:image\/.*?;/.test(link); }; } diff --git a/extensions/markdown-language-features/src/markdownExtensions.ts b/extensions/markdown-language-features/src/markdownExtensions.ts index 65899874f..b03c5df80 100644 --- a/extensions/markdown-language-features/src/markdownExtensions.ts +++ b/extensions/markdown-language-features/src/markdownExtensions.ts @@ -9,8 +9,7 @@ import { Disposable } from './util/dispose'; import * as arrays from './util/arrays'; const resolveExtensionResource = (extension: vscode.Extension, resourcePath: string): vscode.Uri => { - return vscode.Uri.file(path.join(extension.extensionPath, resourcePath)) - .with({ scheme: 'vscode-resource' }); + return vscode.Uri.file(path.join(extension.extensionPath, resourcePath)); }; const resolveExtensionResources = (extension: vscode.Extension, resourcePaths: unknown): vscode.Uri[] => { diff --git a/extensions/markdown-language-features/src/security.ts b/extensions/markdown-language-features/src/security.ts index 7f11d65a1..89a9667e1 100644 --- a/extensions/markdown-language-features/src/security.ts +++ b/extensions/markdown-language-features/src/security.ts @@ -94,7 +94,7 @@ export class PreviewSecuritySelector { private readonly webviewManager: MarkdownPreviewManager ) { } - public async showSecutitySelectorForResource(resource: vscode.Uri): Promise { + public async showSecuritySelectorForResource(resource: vscode.Uri): Promise { interface PreviewSecurityPickItem extends vscode.QuickPickItem { readonly type: 'moreinfo' | 'toggle' | MarkdownPreviewSecurityLevel; } diff --git a/extensions/markdown-language-features/src/test/documentLinkProvider.test.ts b/extensions/markdown-language-features/src/test/documentLinkProvider.test.ts index f6309a027..ba6cfa256 100644 --- a/extensions/markdown-language-features/src/test/documentLinkProvider.test.ts +++ b/extensions/markdown-language-features/src/test/documentLinkProvider.test.ts @@ -72,6 +72,14 @@ suite('markdown.DocumentLinkProvider', () => { assertRangeEqual(link.range, new vscode.Range(0, 6, 0, 25)); }); + // #35245 + test('Should handle links with escaped characters in name', () => { + const links = getLinksForFile('a [b\\]](./file)'); + assert.strictEqual(links.length, 1); + const [link] = links; + assertRangeEqual(link.range, new vscode.Range(0, 8, 0, 14)); + }); + test('Should handle links with balanced parens', () => { { diff --git a/extensions/markdown-language-features/src/util/resources.ts b/extensions/markdown-language-features/src/util/resources.ts new file mode 100644 index 000000000..1def7adcc --- /dev/null +++ b/extensions/markdown-language-features/src/util/resources.ts @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from 'vscode'; + +export interface WebviewResourceProvider { + toWebviewResource(resource: vscode.Uri): vscode.Uri; + + readonly cspSource: string; +} + +export function normalizeResource( + base: vscode.Uri, + resource: vscode.Uri +): vscode.Uri { + // If we have a windows path and are loading a workspace with an authority, + // make sure we use a unc path with an explicit localhost authority. + // + // Otherwise, the `` rule will insert the authority into the resolved resource + // URI incorrectly. + if (base.authority && !resource.authority) { + const driveMatch = resource.path.match(/^\/(\w):\//); + if (driveMatch) { + return vscode.Uri.file(`\\\\localhost\\${driveMatch[1]}$\\${resource.fsPath.replace(/^\w:\\/, '')}`).with({ + fragment: resource.fragment, + query: resource.query + }); + } + } + return resource; +} \ No newline at end of file diff --git a/extensions/markdown-language-features/yarn.lock b/extensions/markdown-language-features/yarn.lock index e85ae950b..a1b876e7d 100644 --- a/extensions/markdown-language-features/yarn.lock +++ b/extensions/markdown-language-features/yarn.lock @@ -29,10 +29,10 @@ resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-0.0.2.tgz#5d9ad19e6e6508cdd2f2596df86fd0aade598660" integrity sha1-XZrRnm5lCM3S8llt+G/Qqt5ZhmA= -"@types/node@^10.12.21": - version "10.12.21" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.21.tgz#7e8a0c34cf29f4e17a36e9bd0ea72d45ba03908e" - integrity sha512-CBgLNk4o3XMnqMc0rhb6lc77IwShMEglz05deDcn2lQxyXEZivfwgYJu7SMha9V5XcrP6qZuevTHV/QrN2vjKQ== +"@types/node@^10.14.8": + version "10.14.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9" + integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw== abbrev@1: version "1.1.1" @@ -2933,10 +2933,10 @@ he@1.1.1: resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0= -highlight.js@9.13.1: - version "9.13.1" - resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.13.1.tgz#054586d53a6863311168488a0f58d6c505ce641e" - integrity sha512-Sc28JNQNDzaH6PORtRLMvif9RSn1mYuOoX3omVjnb0+HbpPygU2ALBI0R/wsiqCb4/fcp07Gdo8g+fhtFrQl6A== +highlight.js@9.15.8: + version "9.15.8" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.15.8.tgz#f344fda123f36f1a65490e932cf90569e4999971" + integrity sha512-RrapkKQWwE+wKdF73VsOa2RQdIoO3mxwJ4P8mhbI6KYJUraUHRKM5w5zQQKXNk0xNL4UVRdulV9SBJcmzJNzVA== hmac-drbg@^1.0.0: version "1.0.1" diff --git a/extensions/merge-conflict/package.json b/extensions/merge-conflict/package.json index efc0ff0cf..2828669b0 100644 --- a/extensions/merge-conflict/package.json +++ b/extensions/merge-conflict/package.json @@ -5,6 +5,7 @@ "description": "%description%", "icon": "resources/icons/merge-conflict.png", "version": "1.0.0", + "license": "MIT", "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", "engines": { "vscode": "^1.5.0" @@ -114,6 +115,21 @@ "type": "boolean", "description": "%config.autoNavigateNextConflictEnabled%", "default": false + }, + "merge-conflict.diffViewPosition": { + "type": "string", + "enum": [ + "Current", + "Beside", + "Below" + ], + "description": "%config.diffViewPosition%", + "enumDescriptions": [ + "%config.diffViewPosition.current%", + "%config.diffViewPosition.beside%", + "%config.diffViewPosition.below%" + ], + "default": "Current" } } } @@ -122,6 +138,6 @@ "vscode-nls": "^4.0.0" }, "devDependencies": { - "@types/node": "8.0.33" + "@types/node": "^10.14.8" } } diff --git a/extensions/merge-conflict/package.nls.json b/extensions/merge-conflict/package.nls.json index 94599bf28..3310dac7e 100644 --- a/extensions/merge-conflict/package.nls.json +++ b/extensions/merge-conflict/package.nls.json @@ -15,5 +15,9 @@ "config.title": "Merge Conflict", "config.autoNavigateNextConflictEnabled": "Whether to automatically navigate to the next merge conflict after resolving a merge conflict.", "config.codeLensEnabled": "Create a Code Lens for merge conflict blocks within editor.", - "config.decoratorsEnabled": "Create decorators for merge conflict blocks within editor." + "config.decoratorsEnabled": "Create decorators for merge conflict blocks within editor.", + "config.diffViewPosition": "Controls where the diff view should be opened when comparing changes in merge conflicts.", + "config.diffViewPosition.current": "Open the diff view in the current editor group.", + "config.diffViewPosition.beside": "Open the diff view next to the current editor group.", + "config.diffViewPosition.below": "Open the diff view below the current editor group." } \ No newline at end of file diff --git a/extensions/merge-conflict/src/commandHandler.ts b/extensions/merge-conflict/src/commandHandler.ts index 3247b592f..f79c6650a 100644 --- a/extensions/merge-conflict/src/commandHandler.ts +++ b/extensions/merge-conflict/src/commandHandler.ts @@ -34,8 +34,8 @@ export default class CommandHandler implements vscode.Disposable { this.registerTextEditorCommand('merge-conflict.accept.incoming', this.acceptIncoming), this.registerTextEditorCommand('merge-conflict.accept.selection', this.acceptSelection), this.registerTextEditorCommand('merge-conflict.accept.both', this.acceptBoth), - this.registerTextEditorCommand('merge-conflict.accept.all-current', this.acceptAllCurrent), - this.registerTextEditorCommand('merge-conflict.accept.all-incoming', this.acceptAllIncoming), + this.registerTextEditorCommand('merge-conflict.accept.all-current', this.acceptAllCurrent, this.acceptAllCurrentResources), + this.registerTextEditorCommand('merge-conflict.accept.all-incoming', this.acceptAllIncoming, this.acceptAllIncomingResources), this.registerTextEditorCommand('merge-conflict.accept.all-both', this.acceptAllBoth), this.registerTextEditorCommand('merge-conflict.next', this.navigateNext), this.registerTextEditorCommand('merge-conflict.previous', this.navigatePrevious), @@ -43,8 +43,11 @@ export default class CommandHandler implements vscode.Disposable { ); } - private registerTextEditorCommand(command: string, cb: (editor: vscode.TextEditor, ...args: any[]) => Promise) { + private registerTextEditorCommand(command: string, cb: (editor: vscode.TextEditor, ...args: any[]) => Promise, resourceCB?: (uris: vscode.Uri[]) => Promise) { return vscode.commands.registerCommand(command, (...args) => { + if (resourceCB && args.length && args.every(arg => arg && arg.resourceUri)) { + return resourceCB.call(this, args.map(arg => arg.resourceUri)); + } const editor = vscode.window.activeTextEditor; return editor && cb.call(this, editor, ...args); }); @@ -70,6 +73,14 @@ export default class CommandHandler implements vscode.Disposable { return this.acceptAll(interfaces.CommitType.Incoming, editor); } + acceptAllCurrentResources(resources: vscode.Uri[]): Promise { + return this.acceptAllResources(interfaces.CommitType.Current, resources); + } + + acceptAllIncomingResources(resources: vscode.Uri[]): Promise { + return this.acceptAllResources(interfaces.CommitType.Incoming, resources); + } + acceptAllBoth(editor: vscode.TextEditor): Promise { return this.acceptAll(interfaces.CommitType.Both, editor); } @@ -88,18 +99,54 @@ export default class CommandHandler implements vscode.Disposable { } } + const conflicts = await this.tracker.getConflicts(editor.document); + + // Still failed to find conflict, warn the user and exit + if (!conflicts) { + vscode.window.showWarningMessage(localize('cursorNotInConflict', 'Editor cursor is not within a merge conflict')); + return; + } + const scheme = editor.document.uri.scheme; let range = conflict.current.content; + let leftRanges = conflicts.map(conflict => [conflict.current.content, conflict.range]); + let rightRanges = conflicts.map(conflict => [conflict.incoming.content, conflict.range]); + const leftUri = editor.document.uri.with({ scheme: ContentProvider.scheme, - query: JSON.stringify({ scheme, range }) + query: JSON.stringify({ scheme, range: range, ranges: leftRanges }) }); + range = conflict.incoming.content; - const rightUri = leftUri.with({ query: JSON.stringify({ scheme, range }) }); + const rightUri = leftUri.with({ query: JSON.stringify({ scheme, ranges: rightRanges }) }); + + let mergeConflictLineOffsets = 0; + for (let nextconflict of conflicts) { + if (nextconflict.range.isEqual(conflict.range)) { + break; + } else { + mergeConflictLineOffsets += (nextconflict.range.end.line - nextconflict.range.start.line) - (nextconflict.incoming.content.end.line - nextconflict.incoming.content.start.line); + } + } + const selection = new vscode.Range( + conflict.range.start.line - mergeConflictLineOffsets, conflict.range.start.character, + conflict.range.start.line - mergeConflictLineOffsets, conflict.range.start.character + ); const title = localize('compareChangesTitle', '{0}: Current Changes ⟷ Incoming Changes', fileName); - vscode.commands.executeCommand('vscode.diff', leftUri, rightUri, title); + const mergeConflictConfig = vscode.workspace.getConfiguration('merge-conflict'); + const openToTheSide = mergeConflictConfig.get('diffViewPosition'); + const opts: vscode.TextDocumentShowOptions = { + viewColumn: openToTheSide === 'Beside' ? vscode.ViewColumn.Beside : vscode.ViewColumn.Active, + selection + }; + + if (openToTheSide === 'Below') { + await vscode.commands.executeCommand('workbench.action.newGroupBelow'); + } + + await vscode.commands.executeCommand('vscode.diff', leftUri, rightUri, title, opts); } navigateNext(editor: vscode.TextEditor): Promise { @@ -223,10 +270,31 @@ export default class CommandHandler implements vscode.Disposable { // Apply all changes as one edit await editor.edit((edit) => conflicts.forEach(conflict => { - conflict.applyEdit(type, editor, edit); + conflict.applyEdit(type, editor.document, edit); })); } + private async acceptAllResources(type: interfaces.CommitType, resources: vscode.Uri[]): Promise { + const documents = await Promise.all(resources.map(resource => vscode.workspace.openTextDocument(resource))); + const edit = new vscode.WorkspaceEdit(); + for (const document of documents) { + const conflicts = await this.tracker.getConflicts(document); + + if (!conflicts || conflicts.length === 0) { + continue; + } + + // For get the current state of the document, as we know we are doing to do a large edit + this.tracker.forget(document); + + // Apply all changes as one edit + conflicts.forEach(conflict => { + conflict.applyEdit(type, document, { replace: (range, newText) => edit.replace(document.uri, range, newText) }); + }); + } + vscode.workspace.applyEdit(edit); + } + private async findConflictContainingSelection(editor: vscode.TextEditor, conflicts?: interfaces.IDocumentMergeConflict[]): Promise { if (!conflicts) { diff --git a/extensions/merge-conflict/src/contentProvider.ts b/extensions/merge-conflict/src/contentProvider.ts index b22ab0a21..d0e2b92a5 100644 --- a/extensions/merge-conflict/src/contentProvider.ts +++ b/extensions/merge-conflict/src/contentProvider.ts @@ -23,11 +23,27 @@ export default class MergeConflictContentProvider implements vscode.TextDocument async provideTextDocumentContent(uri: vscode.Uri): Promise { try { - const { scheme, range } = JSON.parse(uri.query) as { scheme: string; range: { line: number, character: number }[] }; - const [start, end] = range; + const { scheme, ranges } = JSON.parse(uri.query) as { scheme: string, ranges: [{ line: number, character: number }[], { line: number, character: number }[]][] }; + // complete diff const document = await vscode.workspace.openTextDocument(uri.with({ scheme, query: '' })); - const text = document.getText(new vscode.Range(start.line, start.character, end.line, end.character)); + + let text = ''; + let lastPosition = new vscode.Position(0, 0); + + ranges.forEach(rangeObj => { + let [conflictRange, fullRange] = rangeObj; + const [start, end] = conflictRange; + const [fullStart, fullEnd] = fullRange; + + text += document.getText(new vscode.Range(lastPosition.line, lastPosition.character, fullStart.line, fullStart.character)); + text += document.getText(new vscode.Range(start.line, start.character, end.line, end.character)); + lastPosition = new vscode.Position(fullEnd.line, fullEnd.character); + }); + + let documentEnd = document.lineAt(document.lineCount - 1).range.end; + text += document.getText(new vscode.Range(lastPosition.line, lastPosition.character, documentEnd.line, documentEnd.character)); + return text; } catch (ex) { diff --git a/extensions/merge-conflict/src/documentMergeConflict.ts b/extensions/merge-conflict/src/documentMergeConflict.ts index 3bf94a16e..560c7ed8c 100644 --- a/extensions/merge-conflict/src/documentMergeConflict.ts +++ b/extensions/merge-conflict/src/documentMergeConflict.ts @@ -25,14 +25,14 @@ export class DocumentMergeConflict implements interfaces.IDocumentMergeConflict if (edit) { - this.applyEdit(type, editor, edit); + this.applyEdit(type, editor.document, edit); return Promise.resolve(true); } - return editor.edit((edit) => this.applyEdit(type, editor, edit)); + return editor.edit((edit) => this.applyEdit(type, editor.document, edit)); } - public applyEdit(type: interfaces.CommitType, editor: vscode.TextEditor, edit: vscode.TextEditorEdit): void { + public applyEdit(type: interfaces.CommitType, document: vscode.TextDocument, edit: { replace(range: vscode.Range, newText: string): void; }): void { // Each conflict is a set of ranges as follows, note placements or newlines // which may not in in spans @@ -45,24 +45,24 @@ export class DocumentMergeConflict implements interfaces.IDocumentMergeConflict // ] if (type === interfaces.CommitType.Current) { // Replace [ Conflict Range ] with [ Current Content ] - let content = editor.document.getText(this.current.content); + let content = document.getText(this.current.content); this.replaceRangeWithContent(content, edit); } else if (type === interfaces.CommitType.Incoming) { - let content = editor.document.getText(this.incoming.content); + let content = document.getText(this.incoming.content); this.replaceRangeWithContent(content, edit); } else if (type === interfaces.CommitType.Both) { // Replace [ Conflict Range ] with [ Current Content ] + \n + [ Incoming Content ] - const currentContent = editor.document.getText(this.current.content); - const incomingContent = editor.document.getText(this.incoming.content); + const currentContent = document.getText(this.current.content); + const incomingContent = document.getText(this.incoming.content); edit.replace(this.range, currentContent.concat(incomingContent)); } } - private replaceRangeWithContent(content: string, edit: vscode.TextEditorEdit) { + private replaceRangeWithContent(content: string, edit: { replace(range: vscode.Range, newText: string): void; }) { if (this.isNewlineOnly(content)) { edit.replace(this.range, ''); return; diff --git a/extensions/merge-conflict/src/interfaces.ts b/extensions/merge-conflict/src/interfaces.ts index bab96d133..836bb5baa 100644 --- a/extensions/merge-conflict/src/interfaces.ts +++ b/extensions/merge-conflict/src/interfaces.ts @@ -25,7 +25,7 @@ export interface IExtensionConfiguration { export interface IDocumentMergeConflict extends IDocumentMergeConflictDescriptor { commitEdit(type: CommitType, editor: vscode.TextEditor, edit?: vscode.TextEditorEdit): Thenable; - applyEdit(type: CommitType, editor: vscode.TextEditor, edit: vscode.TextEditorEdit): void; + applyEdit(type: CommitType, document: vscode.TextDocument, edit: { replace(range: vscode.Range, newText: string): void; }): void; } export interface IDocumentMergeConflictDescriptor { diff --git a/extensions/merge-conflict/yarn.lock b/extensions/merge-conflict/yarn.lock index 6767cb8d8..e6247e292 100644 --- a/extensions/merge-conflict/yarn.lock +++ b/extensions/merge-conflict/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@types/node@8.0.33": - version "8.0.33" - resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.33.tgz#1126e94374014e54478092830704f6ea89df04cd" - integrity sha512-vmCdO8Bm1ExT+FWfC9sd9r4jwqM7o97gGy2WBshkkXbf/2nLAJQUrZfIhw27yVOtLUev6kSZc4cav/46KbDd8A== +"@types/node@^10.14.8": + version "10.14.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9" + integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw== vscode-nls@^4.0.0: version "4.0.0" diff --git a/extensions/npm/package.json b/extensions/npm/package.json index 43dc6a215..843255c21 100644 --- a/extensions/npm/package.json +++ b/extensions/npm/package.json @@ -4,6 +4,7 @@ "displayName": "%displayName%", "description": "%description%", "version": "1.0.1", + "license": "MIT", "engines": { "vscode": "0.10.x" }, @@ -24,12 +25,13 @@ }, "devDependencies": { "@types/minimatch": "^3.0.3", - "@types/node": "^10.12.21" + "@types/node": "^10.14.8" }, "main": "./out/main", "activationEvents": [ "onCommand:workbench.action.tasks.runTask", "onLanguage:json", + "workspaceContains:package.json", "onView:npm" ], "contributes": { @@ -46,7 +48,7 @@ { "id": "npm", "name": "%view.name%", - "when": "config.npm.enableScriptExplorer" + "when": "npm:showScriptExplorer || config.npm.enableScriptExplorer" } ] }, diff --git a/extensions/npm/resources/dark/continue.svg b/extensions/npm/resources/dark/continue.svg index e6eb60411..8b0a58eca 100644 --- a/extensions/npm/resources/dark/continue.svg +++ b/extensions/npm/resources/dark/continue.svg @@ -1 +1,3 @@ -continue \ No newline at end of file + + + diff --git a/extensions/npm/resources/dark/debug.svg b/extensions/npm/resources/dark/debug.svg index e211df43e..e4c1b7a92 100644 --- a/extensions/npm/resources/dark/debug.svg +++ b/extensions/npm/resources/dark/debug.svg @@ -1,7 +1,5 @@ - - - - - - + + + + diff --git a/extensions/npm/resources/dark/prepostscript.svg b/extensions/npm/resources/dark/prepostscript.svg index cc9bcee71..a8c87f2d8 100644 --- a/extensions/npm/resources/dark/prepostscript.svg +++ b/extensions/npm/resources/dark/prepostscript.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + diff --git a/extensions/npm/resources/dark/refresh.svg b/extensions/npm/resources/dark/refresh.svg index d79fdaa4e..ec0c43f0b 100644 --- a/extensions/npm/resources/dark/refresh.svg +++ b/extensions/npm/resources/dark/refresh.svg @@ -1 +1,4 @@ - \ No newline at end of file + + + + diff --git a/extensions/npm/resources/dark/script.svg b/extensions/npm/resources/dark/script.svg index f90781897..7137a9d7b 100644 --- a/extensions/npm/resources/dark/script.svg +++ b/extensions/npm/resources/dark/script.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + diff --git a/extensions/npm/resources/light/continue.svg b/extensions/npm/resources/light/continue.svg index a4dd1cd3c..2563bfa11 100644 --- a/extensions/npm/resources/light/continue.svg +++ b/extensions/npm/resources/light/continue.svg @@ -1 +1,3 @@ -continue \ No newline at end of file + + + diff --git a/extensions/npm/resources/light/debug.svg b/extensions/npm/resources/light/debug.svg index b8efb1c8f..81a5ffb6b 100644 --- a/extensions/npm/resources/light/debug.svg +++ b/extensions/npm/resources/light/debug.svg @@ -1,7 +1,5 @@ - - - - - - + + + + diff --git a/extensions/npm/resources/light/prepostscript.svg b/extensions/npm/resources/light/prepostscript.svg index e59d80cd3..87eb59e12 100644 --- a/extensions/npm/resources/light/prepostscript.svg +++ b/extensions/npm/resources/light/prepostscript.svg @@ -1 +1,5 @@ - \ No newline at end of file + + + + + diff --git a/extensions/npm/resources/light/refresh.svg b/extensions/npm/resources/light/refresh.svg index e03457481..a5b88123a 100644 --- a/extensions/npm/resources/light/refresh.svg +++ b/extensions/npm/resources/light/refresh.svg @@ -1 +1,4 @@ - \ No newline at end of file + + + + diff --git a/extensions/npm/resources/light/script.svg b/extensions/npm/resources/light/script.svg index fb1c74cf7..60f77501d 100644 --- a/extensions/npm/resources/light/script.svg +++ b/extensions/npm/resources/light/script.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + diff --git a/extensions/npm/src/features/packageJSONContribution.ts b/extensions/npm/src/features/packageJSONContribution.ts index 88cf75342..17e194cad 100644 --- a/extensions/npm/src/features/packageJSONContribution.ts +++ b/extensions/npm/src/features/packageJSONContribution.ts @@ -9,6 +9,7 @@ import { XHRRequest } from 'request-light'; import { Location } from 'jsonc-parser'; import { textToMarkedString } from './markedTextUtil'; +import * as cp from 'child_process'; import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); @@ -73,11 +74,25 @@ export class PackageJSONContribution implements IJSONContribution { let queryUrl: string; if (currentWord.length > 0) { if (currentWord[0] === '@') { - return this.collectScopedPackages(currentWord, addValue, isLast, collector); + if (currentWord.indexOf('/') !== -1) { + return this.collectScopedPackages(currentWord, addValue, isLast, collector); + } + for (let scope of this.knownScopes) { + const proposal = new CompletionItem(scope); + proposal.kind = CompletionItemKind.Property; + proposal.insertText = new SnippetString().appendText(`"${scope}/`).appendTabstop().appendText('"'); + proposal.filterText = JSON.stringify(scope); + proposal.documentation = ''; + proposal.command = { + title: '', + command: 'editor.action.triggerSuggest' + }; + collector.add(proposal); + } + collector.setAsIncomplete(); } - queryUrl = 'https://skimdb.npmjs.com/registry/_design/app/_view/browseAll?group_level=2&limit=' + LIMIT + '&start_key=%5B%22' + encodeURIComponent(currentWord) + '%22%5D&end_key=%5B%22' + encodeURIComponent(currentWord + 'z') + '%22,%7B%7D%5D'; - + queryUrl = `https://api.npms.io/v2/search/suggestions?size=${LIMIT}&q=${encodeURIComponent(currentWord)}`; return this.xhr({ url: queryUrl, agent: USER_AGENT @@ -85,26 +100,10 @@ export class PackageJSONContribution implements IJSONContribution { if (success.status === 200) { try { const obj = JSON.parse(success.responseText); - if (obj && Array.isArray(obj.rows)) { - const results = <{ key: string[]; }[]>obj.rows; + if (obj && Array.isArray(obj)) { + const results = <{ package: SearchPackageInfo; }[]>obj; for (const result of results) { - const keys = result.key; - if (Array.isArray(keys) && keys.length > 0) { - const name = keys[0]; - const insertText = new SnippetString().appendText(JSON.stringify(name)); - if (addValue) { - insertText.appendText(': "').appendTabstop().appendText('"'); - if (!isLast) { - insertText.appendText(','); - } - } - const proposal = new CompletionItem(name); - proposal.kind = CompletionItemKind.Property; - proposal.insertText = insertText; - proposal.filterText = JSON.stringify(name); - proposal.documentation = keys[1]; - collector.add(proposal); - } + this.processPackage(result.package, addValue, isLast, collector); } if (results.length === LIMIT) { collector.setAsIncomplete(); @@ -148,20 +147,7 @@ export class PackageJSONContribution implements IJSONContribution { private collectScopedPackages(currentWord: string, addValue: boolean, isLast: boolean, collector: ISuggestionsCollector): Thenable { let segments = currentWord.split('/'); - if (segments.length === 1) { - for (let scope of this.knownScopes) { - const proposal = new CompletionItem(scope); - proposal.kind = CompletionItemKind.Property; - proposal.insertText = new SnippetString().appendText(`"${scope}/`).appendTabstop().appendText('"'); - proposal.filterText = JSON.stringify(scope); - proposal.documentation = ''; - proposal.command = { - title: '', - command: 'editor.action.triggerSuggest' - }; - collector.add(proposal); - } - } else if (segments.length === 2 && segments[0].length > 1) { + if (segments.length === 2 && segments[0].length > 1) { let scope = segments[0].substr(1); let name = segments[1]; if (name.length < 4) { @@ -176,30 +162,9 @@ export class PackageJSONContribution implements IJSONContribution { try { const obj = JSON.parse(success.responseText); if (obj && Array.isArray(obj.results)) { - const objects = <{ package: { name: string; version: string, description: string; } }[]>obj.results; + const objects = <{ package: SearchPackageInfo }[]>obj.results; for (let object of objects) { - if (object.package && object.package.name) { - const name = object.package.name; - const insertText = new SnippetString().appendText(JSON.stringify(name)); - if (addValue) { - insertText.appendText(': "'); - if (object.package.version) { - insertText.appendVariable('version', object.package.version); - } else { - insertText.appendTabstop(); - } - insertText.appendText('"'); - if (!isLast) { - insertText.appendText(','); - } - } - const proposal = new CompletionItem(name); - proposal.kind = CompletionItemKind.Property; - proposal.insertText = insertText; - proposal.filterText = JSON.stringify(name); - proposal.documentation = object.package.description || ''; - collector.add(proposal); - } + this.processPackage(object.package, addValue, isLast, collector); } if (objects.length === SCOPED_LIMIT) { collector.setAsIncomplete(); @@ -229,38 +194,29 @@ export class PackageJSONContribution implements IJSONContribution { if ((location.matches(['dependencies', '*']) || location.matches(['devDependencies', '*']) || location.matches(['optionalDependencies', '*']) || location.matches(['peerDependencies', '*']))) { const currentKey = location.path[location.path.length - 1]; if (typeof currentKey === 'string') { - const queryUrl = 'https://registry.npmjs.org/' + encodeURIComponent(currentKey).replace(/%40/g, '@'); - return this.xhr({ - url: queryUrl, - agent: USER_AGENT - }).then((success) => { - try { - 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); - proposal.kind = CompletionItemKind.Property; - proposal.insertText = name; - proposal.documentation = localize('json.npm.latestversion', 'The currently latest version of the package'); - result.add(proposal); + return this.npmView(currentKey).then(info => { + const latest = info.distTagsLatest; + if (latest) { + let name = JSON.stringify(latest); + let proposal = new CompletionItem(name); + proposal.kind = CompletionItemKind.Property; + proposal.insertText = name; + proposal.documentation = localize('json.npm.latestversion', 'The currently latest version of the package'); + result.add(proposal); - name = JSON.stringify('^' + latest); - proposal = new CompletionItem(name); - proposal.kind = CompletionItemKind.Property; - proposal.insertText = name; - proposal.documentation = localize('json.npm.majorversion', 'Matches the most recent major version (1.x.x)'); - result.add(proposal); + name = JSON.stringify('^' + latest); + proposal = new CompletionItem(name); + proposal.kind = CompletionItemKind.Property; + proposal.insertText = name; + proposal.documentation = localize('json.npm.majorversion', 'Matches the most recent major version (1.x.x)'); + result.add(proposal); - name = JSON.stringify('~' + latest); - proposal = new CompletionItem(name); - proposal.kind = CompletionItemKind.Property; - proposal.insertText = name; - proposal.documentation = localize('json.npm.minorversion', 'Matches the most recent minor version (1.2.x)'); - result.add(proposal); - } - } catch (e) { - // ignore + name = JSON.stringify('~' + latest); + proposal = new CompletionItem(name); + proposal.kind = CompletionItemKind.Property; + proposal.insertText = name; + proposal.documentation = localize('json.npm.minorversion', 'Matches the most recent minor version (1.2.x)'); + result.add(proposal); } return 0; }, () => { @@ -288,37 +244,38 @@ export class PackageJSONContribution implements IJSONContribution { } private getInfo(pack: string): Thenable { - - const queryUrl = 'https://registry.npmjs.org/' + encodeURIComponent(pack).replace(/%40/g, '@'); - return this.xhr({ - url: queryUrl, - agent: USER_AGENT - }).then((success) => { - try { - const obj = JSON.parse(success.responseText); - if (obj) { - const result: string[] = []; - if (obj.description) { - result.push(obj.description); - } - const latest = obj && obj['dist-tags'] && obj['dist-tags']['latest']; - if (latest) { - result.push(localize('json.npm.version.hover', 'Latest version: {0}', latest)); - } - if (obj.homepage) { - result.push(obj.homepage); - } - return result; - } - } catch (e) { - // ignore - } - return []; + return this.npmView(pack).then(info => { + const result: string[] = []; + result.push(info.description || ''); + result.push(info.distTagsLatest ? localize('json.npm.version.hover', 'Latest version: {0}', info.distTagsLatest) : ''); + result.push(info.homepage || ''); + return result; }, () => { return []; }); } + private npmView(pack: string): Promise { + return new Promise((resolve, reject) => { + const command = 'npm view --json ' + pack + ' description dist-tags.latest homepage'; + cp.exec(command, (error, stdout) => { + if (error) { + return reject(); + } + try { + const content = JSON.parse(stdout); + resolve({ + description: content['description'], + distTagsLatest: content['dist-tags.latest'], + homepage: content['homepage'] + }); + } catch (e) { + reject(); + } + }); + }); + } + public getInfoContribution(_fileName: string, location: Location): Thenable | null { if ((location.matches(['dependencies', '*']) || location.matches(['devDependencies', '*']) || location.matches(['optionalDependencies', '*']) || location.matches(['peerDependencies', '*']))) { const pack = location.path[location.path.length - 1]; @@ -333,4 +290,41 @@ export class PackageJSONContribution implements IJSONContribution { } return null; } + + private processPackage(pack: SearchPackageInfo, addValue: boolean, isLast: boolean, collector: ISuggestionsCollector) { + if (pack && pack.name) { + const name = pack.name; + const insertText = new SnippetString().appendText(JSON.stringify(name)); + if (addValue) { + insertText.appendText(': "'); + if (pack.version) { + insertText.appendVariable('version', pack.version); + } else { + insertText.appendTabstop(); + } + insertText.appendText('"'); + if (!isLast) { + insertText.appendText(','); + } + } + const proposal = new CompletionItem(name); + proposal.kind = CompletionItemKind.Property; + proposal.insertText = insertText; + proposal.filterText = JSON.stringify(name); + proposal.documentation = pack.description || ''; + collector.add(proposal); + } + } +} + +interface SearchPackageInfo { + name: string; + description?: string; + version?: string; } + +interface ViewPackageInfo { + description: string; + distTagsLatest?: string; + homepage?: string; +} \ No newline at end of file diff --git a/extensions/npm/src/main.ts b/extensions/npm/src/main.ts index 640c34933..d32d245b0 100644 --- a/extensions/npm/src/main.ts +++ b/extensions/npm/src/main.ts @@ -7,7 +7,7 @@ import * as httpRequest from 'request-light'; import * as vscode from 'vscode'; import { addJSONProviders } from './features/jsonContributions'; import { NpmScriptsTreeDataProvider } from './npmView'; -import { invalidateTasksCache, NpmTaskProvider } from './tasks'; +import { invalidateTasksCache, NpmTaskProvider, hasPackageJson } from './tasks'; import { invalidateHoverScriptsCache, NpmScriptHoverProvider } from './scriptHover'; import { runSelectedScript } from './commands'; @@ -41,6 +41,10 @@ export async function activate(context: vscode.ExtensionContext): Promise context.subscriptions.push(d); context.subscriptions.push(vscode.commands.registerCommand('npm.runSelectedScript', runSelectedScript)); context.subscriptions.push(addJSONProviders(httpRequest.xhr)); + + if (await hasPackageJson()) { + vscode.commands.executeCommand('setContext', 'npm:showScriptExplorer', true); + } } function registerTaskProvider(context: vscode.ExtensionContext): vscode.Disposable | undefined { diff --git a/extensions/npm/src/tasks.ts b/extensions/npm/src/tasks.ts index bfe9d8cd6..f60f75315 100644 --- a/extensions/npm/src/tasks.ts +++ b/extensions/npm/src/tasks.ts @@ -262,6 +262,22 @@ export function getPackageJsonUriFromTask(task: Task): Uri | null { return null; } +export async function hasPackageJson(): Promise { + let folders = workspace.workspaceFolders; + if (!folders) { + return false; + } + for (const folder of folders) { + if (folder.uri.scheme === 'file') { + let packageJson = path.join(folder.uri.fsPath, 'package.json'); + if (await exists(packageJson)) { + return true; + } + } + } + return false; +} + async function exists(file: string): Promise { return new Promise((resolve, _reject) => { fs.exists(file, (value) => { diff --git a/extensions/npm/yarn.lock b/extensions/npm/yarn.lock index ca339ed81..e80a4ca5a 100644 --- a/extensions/npm/yarn.lock +++ b/extensions/npm/yarn.lock @@ -7,10 +7,10 @@ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== -"@types/node@^10.12.21": - version "10.12.21" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.21.tgz#7e8a0c34cf29f4e17a36e9bd0ea72d45ba03908e" - integrity sha512-CBgLNk4o3XMnqMc0rhb6lc77IwShMEglz05deDcn2lQxyXEZivfwgYJu7SMha9V5XcrP6qZuevTHV/QrN2vjKQ== +"@types/node@^10.14.8": + version "10.14.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9" + integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw== agent-base@4, agent-base@^4.1.0: version "4.2.0" diff --git a/extensions/objective-c/build/update-grammars.js b/extensions/objective-c/build/update-grammars.js new file mode 100644 index 000000000..5518bbcb0 --- /dev/null +++ b/extensions/objective-c/build/update-grammars.js @@ -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. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +var updateGrammar = require('../../../build/npm/update-grammar'); + +updateGrammar.update('jeff-hykin/cpp-textmate-grammar', '/syntaxes/objc.tmLanguage.json', './syntaxes/objective-c.tmLanguage.json', undefined, 'master', 'source/languages/cpp'); +updateGrammar.update('jeff-hykin/cpp-textmate-grammar', '/syntaxes/objcpp.tmLanguage.json', './syntaxes/objective-c++.tmLanguage.json', undefined, 'master', 'source/languages/cpp'); + diff --git a/extensions/objective-c/cgmanifest.json b/extensions/objective-c/cgmanifest.json index 1b54a305d..f33f55aad 100644 --- a/extensions/objective-c/cgmanifest.json +++ b/extensions/objective-c/cgmanifest.json @@ -4,14 +4,14 @@ "component": { "type": "git", "git": { - "name": "atom/language-objective-c", - "repositoryUrl": "https://github.com/atom/language-objective-c", - "commitHash": "7fdf0c40ec1d592a902ed6a7cf5565bdf12e2ae8" + "name": "jeff-hykin/cpp-textmate-grammar", + "repositoryUrl": "https://github.com/jeff-hykin/cpp-textmate-grammar", + "commitHash": "9c4f4b3291538d9f5144f02d3b6af877b84f2cb2" } }, "license": "MIT", - "description": "The files syntaxes/objective-c.tmLanguage.json and syntaxes/objective-c++.tmLanguage.json were derived from the Atom package https://github.com/atom/language-objective-c which was originally converted from the TextMate bundle https://github.com/textmate/objective-c.tmbundle.", - "version": "0.15.0" + "version": "1.12.11", + "description": "The files syntaxes/objective-c.tmLanguage.json and syntaxes/objective-c++.tmLanguage.json were derived from the language package https://github.com/jeff-hykin/cpp-textmate-grammar." } ], "version": 1 diff --git a/extensions/objective-c/package.json b/extensions/objective-c/package.json index 944b68e05..657273ad2 100644 --- a/extensions/objective-c/package.json +++ b/extensions/objective-c/package.json @@ -4,11 +4,12 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "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%2B%2B.cson ./syntaxes/objective-c++.tmLanguage.json" + "update-grammar": "node ./build/update-grammars.js" }, "contributes": { "languages": [ diff --git a/extensions/objective-c/syntaxes/objective-c++.tmLanguage.json b/extensions/objective-c/syntaxes/objective-c++.tmLanguage.json index bd24c9f0d..d9d1cfa55 100644 --- a/extensions/objective-c/syntaxes/objective-c++.tmLanguage.json +++ b/extensions/objective-c/syntaxes/objective-c++.tmLanguage.json @@ -1,18 +1,7098 @@ { "information_for_contributors": [ - "This file has been converted from https://github.com/atom/language-objective-c/blob/master/grammars/objective-c%2B%2B.cson", + "This file has been converted from https://github.com/jeff-hykin/cpp-textmate-grammar/blob/master//syntaxes/objcpp.tmLanguage.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/atom/language-objective-c/commit/7fdf0c40ec1d592a902ed6a7cf5565bdf12e2ae8", + "version": "https://github.com/jeff-hykin/cpp-textmate-grammar/commit/9c4f4b3291538d9f5144f02d3b6af877b84f2cb2", "name": "Objective-C++", "scopeName": "source.objcpp", "patterns": [ { - "include": "source.cpp" + "include": "#cpp_lang" }, { - "include": "source.objc" + "begin": "((@)(interface|protocol))(?!.+;)\\s+([A-Za-z_][A-Za-z0-9_]*)\\s*((:)(?:\\s*)([A-Za-z][A-Za-z0-9]*))?(\\s|\\n)?", + "captures": { + "1": { + "name": "storage.type.objcpp" + }, + "2": { + "name": "punctuation.definition.storage.type.objcpp" + }, + "4": { + "name": "entity.name.type.objcpp" + }, + "6": { + "name": "punctuation.definition.entity.other.inherited-class.objcpp" + }, + "7": { + "name": "entity.other.inherited-class.objcpp" + }, + "8": { + "name": "meta.divider.objcpp" + }, + "9": { + "name": "meta.inherited-class.objcpp" + } + }, + "contentName": "meta.scope.interface.objcpp", + "end": "((@)end)\\b", + "name": "meta.interface-or-protocol.objcpp", + "patterns": [ + { + "include": "#interface_innards" + } + ] + }, + { + "begin": "((@)(implementation))\\s+([A-Za-z_][A-Za-z0-9_]*)\\s*(?::\\s*([A-Za-z][A-Za-z0-9]*))?", + "captures": { + "1": { + "name": "storage.type.objcpp" + }, + "2": { + "name": "punctuation.definition.storage.type.objcpp" + }, + "4": { + "name": "entity.name.type.objcpp" + }, + "5": { + "name": "entity.other.inherited-class.objcpp" + } + }, + "contentName": "meta.scope.implementation.objcpp", + "end": "((@)end)\\b", + "name": "meta.implementation.objcpp", + "patterns": [ + { + "include": "#implementation_innards" + } + ] + }, + { + "begin": "@\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.objcpp" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.objcpp" + } + }, + "name": "string.quoted.double.objcpp", + "patterns": [ + { + "include": "#string_escaped_char" + }, + { + "match": "(?x)%\n\t\t\t\t\t\t(\\d+\\$)? # field (argument #)\n\t\t\t\t\t\t[#0\\- +']* # flags\n\t\t\t\t\t\t((-?\\d+)|\\*(-?\\d+\\$)?)? # minimum field width\n\t\t\t\t\t\t(\\.((-?\\d+)|\\*(-?\\d+\\$)?)?)? # precision\n\t\t\t\t\t\t[@] # conversion type\n\t\t\t\t\t", + "name": "constant.other.placeholder.objcpp" + }, + { + "include": "#string_placeholder" + } + ] + }, + { + "begin": "\\b(id)\\s*(?=<)", + "beginCaptures": { + "1": { + "name": "storage.type.objcpp" + } + }, + "end": "(?<=>)", + "name": "meta.id-with-protocol.objcpp", + "patterns": [ + { + "include": "#protocol_list" + } + ] + }, + { + "match": "\\b(NS_DURING|NS_HANDLER|NS_ENDHANDLER)\\b", + "name": "keyword.control.macro.objcpp" + }, + { + "captures": { + "1": { + "name": "punctuation.definition.keyword.objcpp" + } + }, + "match": "(@)(try|catch|finally|throw)\\b", + "name": "keyword.control.exception.objcpp" + }, + { + "captures": { + "1": { + "name": "punctuation.definition.keyword.objcpp" + } + }, + "match": "(@)(synchronized)\\b", + "name": "keyword.control.synchronize.objcpp" + }, + { + "captures": { + "1": { + "name": "punctuation.definition.keyword.objcpp" + } + }, + "match": "(@)(required|optional)\\b", + "name": "keyword.control.protocol-specification.objcpp" + }, + { + "captures": { + "1": { + "name": "punctuation.definition.keyword.objcpp" + } + }, + "match": "(@)(defs|encode)\\b", + "name": "keyword.other.objcpp" + }, + { + "match": "\\bid\\b", + "name": "storage.type.id.objcpp" + }, + { + "match": "\\b(IBOutlet|IBAction|BOOL|SEL|id|unichar|IMP|Class|instancetype)\\b", + "name": "storage.type.objcpp" + }, + { + "captures": { + "1": { + "name": "punctuation.definition.storage.type.objcpp" + } + }, + "match": "(@)(class|protocol)\\b", + "name": "storage.type.objcpp" + }, + { + "begin": "((@)selector)\\s*(\\()", + "beginCaptures": { + "1": { + "name": "storage.type.objcpp" + }, + "2": { + "name": "punctuation.definition.storage.type.objcpp" + }, + "3": { + "name": "punctuation.definition.storage.type.objcpp" + } + }, + "contentName": "meta.selector.method-name.objcpp", + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.definition.storage.type.objcpp" + } + }, + "name": "meta.selector.objcpp", + "patterns": [ + { + "captures": { + "1": { + "name": "punctuation.separator.arguments.objcpp" + } + }, + "match": "\\b(?:[a-zA-Z_:][\\w]*)+", + "name": "support.function.any-method.name-of-parameter.objcpp" + } + ] + }, + { + "captures": { + "1": { + "name": "punctuation.definition.storage.modifier.objcpp" + } + }, + "match": "(@)(synchronized|public|package|private|protected)\\b", + "name": "storage.modifier.objcpp" + }, + { + "match": "\\b(YES|NO|Nil|nil)\\b", + "name": "constant.language.objcpp" + }, + { + "match": "\\bNSApp\\b", + "name": "support.variable.foundation.objcpp" + }, + { + "captures": { + "1": { + "name": "punctuation.whitespace.support.function.cocoa.leopard.objcpp" + }, + "2": { + "name": "support.function.cocoa.leopard.objcpp" + } + }, + "match": "(\\s*)\\b(NS(Rect(ToCGRect|FromCGRect)|MakeCollectable|S(tringFromProtocol|ize(ToCGSize|FromCGSize))|Draw(NinePartImage|ThreePartImage)|P(oint(ToCGPoint|FromCGPoint)|rotocolFromString)|EventMaskFromType|Value))\\b" + }, + { + "captures": { + "1": { + "name": "punctuation.whitespace.support.function.leading.cocoa.objcpp" + }, + "2": { + "name": "support.function.cocoa.objcpp" + } + }, + "match": "(\\s*)\\b(NS(R(ound(DownToMultipleOfPageSize|UpToMultipleOfPageSize)|un(CriticalAlertPanel(RelativeToWindow)?|InformationalAlertPanel(RelativeToWindow)?|AlertPanel(RelativeToWindow)?)|e(set(MapTable|HashTable)|c(ycleZone|t(Clip(List)?|F(ill(UsingOperation|List(UsingOperation|With(Grays|Colors(UsingOperation)?))?)?|romString))|ordAllocationEvent)|turnAddress|leaseAlertPanel|a(dPixel|l(MemoryAvailable|locateCollectable))|gisterServicesProvider)|angeFromString)|Get(SizeAndAlignment|CriticalAlertPanel|InformationalAlertPanel|UncaughtExceptionHandler|FileType(s)?|WindowServerMemory|AlertPanel)|M(i(n(X|Y)|d(X|Y))|ouseInRect|a(p(Remove|Get|Member|Insert(IfAbsent|KnownAbsent)?)|ke(R(ect|ange)|Size|Point)|x(Range|X|Y)))|B(itsPer(SampleFromDepth|PixelFromDepth)|e(stDepth|ep|gin(CriticalAlertSheet|InformationalAlertSheet|AlertSheet)))|S(ho(uldRetainWithZone|w(sServicesMenuItem|AnimationEffect))|tringFrom(R(ect|ange)|MapTable|S(ize|elector)|HashTable|Class|Point)|izeFromString|e(t(ShowsServicesMenuItem|ZoneName|UncaughtExceptionHandler|FocusRingStyle)|lectorFromString|archPathForDirectoriesInDomains)|wap(Big(ShortToHost|IntToHost|DoubleToHost|FloatToHost|Long(ToHost|LongToHost))|Short|Host(ShortTo(Big|Little)|IntTo(Big|Little)|DoubleTo(Big|Little)|FloatTo(Big|Little)|Long(To(Big|Little)|LongTo(Big|Little)))|Int|Double|Float|L(ittle(ShortToHost|IntToHost|DoubleToHost|FloatToHost|Long(ToHost|LongToHost))|ong(Long)?)))|H(ighlightRect|o(stByteOrder|meDirectory(ForUser)?)|eight|ash(Remove|Get|Insert(IfAbsent|KnownAbsent)?)|FSType(CodeFromFileType|OfFile))|N(umberOfColorComponents|ext(MapEnumeratorPair|HashEnumeratorItem))|C(o(n(tainsRect|vert(GlyphsToPackedGlyphs|Swapped(DoubleToHost|FloatToHost)|Host(DoubleToSwapped|FloatToSwapped)))|unt(MapTable|HashTable|Frames|Windows(ForContext)?)|py(M(emoryPages|apTableWithZone)|Bits|HashTableWithZone|Object)|lorSpaceFromDepth|mpare(MapTables|HashTables))|lassFromString|reate(MapTable(WithZone)?|HashTable(WithZone)?|Zone|File(namePboardType|ContentsPboardType)))|TemporaryDirectory|I(s(ControllerMarker|EmptyRect|FreedObject)|n(setRect|crementExtraRefCount|te(r(sect(sRect|ionR(ect|ange))|faceStyleForKey)|gralRect)))|Zone(Realloc|Malloc|Name|Calloc|Fr(omPointer|ee))|O(penStepRootDirectory|ffsetRect)|D(i(sableScreenUpdates|videRect)|ottedFrameRect|e(c(imal(Round|Multiply|S(tring|ubtract)|Normalize|Co(py|mpa(ct|re))|IsNotANumber|Divide|Power|Add)|rementExtraRefCountWasZero)|faultMallocZone|allocate(MemoryPages|Object))|raw(Gr(oove|ayBezel)|B(itmap|utton)|ColorTiledRects|TiledRects|DarkBezel|W(hiteBezel|indowBackground)|LightBezel))|U(serName|n(ionR(ect|ange)|registerServicesProvider)|pdateDynamicServices)|Java(Bundle(Setup|Cleanup)|Setup(VirtualMachine)?|Needs(ToLoadClasses|VirtualMachine)|ClassesF(orBundle|romPath)|ObjectNamedInPath|ProvidesClasses)|P(oint(InRect|FromString)|erformService|lanarFromDepth|ageSize)|E(n(d(MapTableEnumeration|HashTableEnumeration)|umerate(MapTable|HashTable)|ableScreenUpdates)|qual(R(ects|anges)|Sizes|Points)|raseRect|xtraRefCount)|F(ileTypeForHFSTypeCode|ullUserName|r(ee(MapTable|HashTable)|ame(Rect(WithWidth(UsingOperation)?)?|Address)))|Wi(ndowList(ForContext)?|dth)|Lo(cationInRange|g(v|PageSize)?)|A(ccessibility(R(oleDescription(ForUIElement)?|aiseBadArgumentException)|Unignored(Children(ForOnlyChild)?|Descendant|Ancestor)|PostNotification|ActionDescription)|pplication(Main|Load)|vailableWindowDepths|ll(MapTable(Values|Keys)|HashTableObjects|ocate(MemoryPages|Collectable|Object)))))\\b" + }, + { + "match": "\\bNS(RuleEditor|G(arbageCollector|radient)|MapTable|HashTable|Co(ndition|llectionView(Item)?)|T(oolbarItemGroup|extInputClient|r(eeNode|ackingArea))|InvocationOperation|Operation(Queue)?|D(ictionaryController|ockTile)|P(ointer(Functions|Array)|athC(o(ntrol(Delegate)?|mponentCell)|ell(Delegate)?)|r(intPanelAccessorizing|edicateEditor(RowTemplate)?))|ViewController|FastEnumeration|Animat(ionContext|ablePropertyContainer))\\b", + "name": "support.class.cocoa.leopard.objcpp" + }, + { + "match": "\\bNS(R(u(nLoop|ler(Marker|View))|e(sponder|cursiveLock|lativeSpecifier)|an(domSpecifier|geSpecifier))|G(etCommand|lyph(Generator|Storage|Info)|raphicsContext)|XML(Node|D(ocument|TD(Node)?)|Parser|Element)|M(iddleSpecifier|ov(ie(View)?|eCommand)|utable(S(tring|et)|C(haracterSet|opying)|IndexSet|D(ictionary|ata)|URLRequest|ParagraphStyle|A(ttributedString|rray))|e(ssagePort(NameServer)?|nu(Item(Cell)?|View)?|t(hodSignature|adata(Item|Query(ResultGroup|AttributeValueTuple)?)))|a(ch(BootstrapServer|Port)|trix))|B(itmapImageRep|ox|u(ndle|tton(Cell)?)|ezierPath|rowser(Cell)?)|S(hadow|c(anner|r(ipt(SuiteRegistry|C(o(ercionHandler|mmand(Description)?)|lassDescription)|ObjectSpecifier|ExecutionContext|WhoseTest)|oll(er|View)|een))|t(epper(Cell)?|atus(Bar|Item)|r(ing|eam))|imple(HorizontalTypesetter|CString)|o(cketPort(NameServer)?|und|rtDescriptor)|p(e(cifierTest|ech(Recognizer|Synthesizer)|ll(Server|Checker))|litView)|e(cureTextField(Cell)?|t(Command)?|archField(Cell)?|rializer|gmentedC(ontrol|ell))|lider(Cell)?|avePanel)|H(ost|TTP(Cookie(Storage)?|URLResponse)|elpManager)|N(ib(Con(nector|trolConnector)|OutletConnector)?|otification(Center|Queue)?|u(ll|mber(Formatter)?)|etService(Browser)?|ameSpecifier)|C(ha(ngeSpelling|racterSet)|o(n(stantString|nection|trol(ler)?|ditionLock)|d(ing|er)|unt(Command|edSet)|pying|lor(Space|P(ick(ing(Custom|Default)|er)|anel)|Well|List)?|m(p(oundPredicate|arisonPredicate)|boBox(Cell)?))|u(stomImageRep|rsor)|IImageRep|ell|l(ipView|o(seCommand|neCommand)|assDescription)|a(ched(ImageRep|URLResponse)|lendar(Date)?)|reateCommand)|T(hread|ypesetter|ime(Zone|r)|o(olbar(Item(Validations)?)?|kenField(Cell)?)|ext(Block|Storage|Container|Tab(le(Block)?)?|Input|View|Field(Cell)?|List|Attachment(Cell)?)?|a(sk|b(le(Header(Cell|View)|Column|View)|View(Item)?))|reeController)|I(n(dex(S(pecifier|et)|Path)|put(Manager|S(tream|erv(iceProvider|er(MouseTracker)?)))|vocation)|gnoreMisspelledWords|mage(Rep|Cell|View)?)|O(ut(putStream|lineView)|pen(GL(Context|Pixel(Buffer|Format)|View)|Panel)|bj(CTypeSerializationCallBack|ect(Controller)?))|D(i(st(antObject(Request)?|ributed(NotificationCenter|Lock))|ctionary|rectoryEnumerator)|ocument(Controller)?|e(serializer|cimalNumber(Behaviors|Handler)?|leteCommand)|at(e(Components|Picker(Cell)?|Formatter)?|a)|ra(wer|ggingInfo))|U(ser(InterfaceValidations|Defaults(Controller)?)|RL(Re(sponse|quest)|Handle(Client)?|C(onnection|ache|redential(Storage)?)|Download(Delegate)?|Prot(ocol(Client)?|ectionSpace)|AuthenticationChallenge(Sender)?)?|n(iqueIDSpecifier|doManager|archiver))|P(ipe|o(sitionalSpecifier|pUpButton(Cell)?|rt(Message|NameServer|Coder)?)|ICTImageRep|ersistentDocument|DFImageRep|a(steboard|nel|ragraphStyle|geLayout)|r(int(Info|er|Operation|Panel)|o(cessInfo|tocolChecker|perty(Specifier|ListSerialization)|gressIndicator|xy)|edicate))|E(numerator|vent|PSImageRep|rror|x(ception|istsCommand|pression))|V(iew(Animation)?|al(idated(ToobarItem|UserInterfaceItem)|ue(Transformer)?))|Keyed(Unarchiver|Archiver)|Qui(ckDrawView|tCommand)|F(ile(Manager|Handle|Wrapper)|o(nt(Manager|Descriptor|Panel)?|rm(Cell|atter)))|W(hoseSpecifier|indow(Controller)?|orkspace)|L(o(c(k(ing)?|ale)|gicalTest)|evelIndicator(Cell)?|ayoutManager)|A(ssertionHandler|nimation|ctionCell|ttributedString|utoreleasePool|TSTypesetter|ppl(ication|e(Script|Event(Manager|Descriptor)))|ffineTransform|lert|r(chiver|ray(Controller)?)))\\b", + "name": "support.class.cocoa.objcpp" + }, + { + "match": "\\bNS(R(oundingMode|ule(Editor(RowType|NestingMode)|rOrientation)|e(questUserAttentionType|lativePosition))|G(lyphInscription|radientDrawingOptions)|XML(NodeKind|D(ocumentContentKind|TDNodeKind)|ParserError)|M(ultibyteGlyphPacking|apTableOptions)|B(itmapFormat|oxType|ezierPathElement|ackgroundStyle|rowserDropOperation)|S(tr(ing(CompareOptions|DrawingOptions|EncodingConversionOptions)|eam(Status|Event))|p(eechBoundary|litViewDividerStyle)|e(archPathD(irectory|omainMask)|gmentS(tyle|witchTracking))|liderType|aveOptions)|H(TTPCookieAcceptPolicy|ashTableOptions)|N(otification(SuspensionBehavior|Coalescing)|umberFormatter(RoundingMode|Behavior|Style|PadPosition)|etService(sError|Options))|C(haracterCollection|o(lor(RenderingIntent|SpaceModel|PanelMode)|mp(oundPredicateType|arisonPredicateModifier))|ellStateValue|al(culationError|endarUnit))|T(ypesetterControlCharacterAction|imeZoneNameStyle|e(stComparisonOperation|xt(Block(Dimension|V(erticalAlignment|alueType)|Layer)|TableLayoutAlgorithm|FieldBezelStyle))|ableView(SelectionHighlightStyle|ColumnAutoresizingStyle)|rackingAreaOptions)|I(n(sertionPosition|te(rfaceStyle|ger))|mage(RepLoadStatus|Scaling|CacheMode|FrameStyle|LoadStatus|Alignment))|Ope(nGLPixelFormatAttribute|rationQueuePriority)|Date(Picker(Mode|Style)|Formatter(Behavior|Style))|U(RL(RequestCachePolicy|HandleStatus|C(acheStoragePolicy|redentialPersistence))|Integer)|P(o(stingStyle|int(ingDeviceType|erFunctionsOptions)|pUpArrowPosition)|athStyle|r(int(ing(Orientation|PaginationMode)|erTableStatus|PanelOptions)|opertyList(MutabilityOptions|Format)|edicateOperatorType))|ExpressionType|KeyValue(SetMutationKind|Change)|QTMovieLoopMode|F(indPanel(SubstringMatchType|Action)|o(nt(RenderingMode|FamilyClass)|cusRingPlacement))|W(hoseSubelementIdentifier|ind(ingRule|ow(B(utton|ackingLocation)|SharingType|CollectionBehavior)))|L(ine(MovementDirection|SweepDirection|CapStyle|JoinStyle)|evelIndicatorStyle)|Animation(BlockingMode|Curve))\\b", + "name": "support.type.cocoa.leopard.objcpp" + }, + { + "match": "\\bC(I(Sampler|Co(ntext|lor)|Image(Accumulator)?|PlugIn(Registration)?|Vector|Kernel|Filter(Generator|Shape)?)|A(Renderer|MediaTiming(Function)?|BasicAnimation|ScrollLayer|Constraint(LayoutManager)?|T(iledLayer|extLayer|rans(ition|action))|OpenGLLayer|PropertyAnimation|KeyframeAnimation|Layer|A(nimation(Group)?|ction)))\\b", + "name": "support.class.quartz.objcpp" + }, + { + "match": "\\bC(G(Float|Point|Size|Rect)|IFormat|AConstraintAttribute)\\b", + "name": "support.type.quartz.objcpp" + }, + { + "match": "\\bNS(R(ect(Edge)?|ange)|G(lyph(Relation|LayoutMode)?|radientType)|M(odalSession|a(trixMode|p(Table|Enumerator)))|B(itmapImageFileType|orderType|uttonType|ezelStyle|ackingStoreType|rowserColumnResizingType)|S(cr(oll(er(Part|Arrow)|ArrowPosition)|eenAuxiliaryOpaque)|tringEncoding|ize|ocketNativeHandle|election(Granularity|Direction|Affinity)|wapped(Double|Float)|aveOperationType)|Ha(sh(Table|Enumerator)|ndler(2)?)|C(o(ntrol(Size|Tint)|mp(ositingOperation|arisonResult))|ell(State|Type|ImagePosition|Attribute))|T(hreadPrivate|ypesetterGlyphInfo|i(ckMarkPosition|tlePosition|meInterval)|o(ol(TipTag|bar(SizeMode|DisplayMode))|kenStyle)|IFFCompression|ext(TabType|Alignment)|ab(State|leViewDropOperation|ViewType)|rackingRectTag)|ImageInterpolation|Zone|OpenGL(ContextAuxiliary|PixelFormatAuxiliary)|D(ocumentChangeType|atePickerElementFlags|ra(werState|gOperation))|UsableScrollerParts|P(oint|r(intingPageOrder|ogressIndicator(Style|Th(ickness|readInfo))))|EventType|KeyValueObservingOptions|Fo(nt(SymbolicTraits|TraitMask|Action)|cusRingType)|W(indow(OrderingMode|Depth)|orkspace(IconCreationOptions|LaunchOptions)|ritingDirection)|L(ineBreakMode|ayout(Status|Direction))|A(nimation(Progress|Effect)|ppl(ication(TerminateReply|DelegateReply|PrintReply)|eEventManagerSuspensionID)|ffineTransformStruct|lertStyle))\\b", + "name": "support.type.cocoa.objcpp" + }, + { + "match": "\\bNS(NotFound|Ordered(Ascending|Descending|Same))\\b", + "name": "support.constant.cocoa.objcpp" + }, + { + "match": "\\bNS(MenuDidBeginTracking|ViewDidUpdateTrackingAreas)?Notification\\b", + "name": "support.constant.notification.cocoa.leopard.objcpp" + }, + { + "match": "\\bNS(Menu(Did(RemoveItem|SendAction|ChangeItem|EndTracking|AddItem)|WillSendAction)|S(ystemColorsDidChange|plitView(DidResizeSubviews|WillResizeSubviews))|C(o(nt(extHelpModeDid(Deactivate|Activate)|rolT(intDidChange|extDid(BeginEditing|Change|EndEditing)))|lor(PanelColorDidChange|ListDidChange)|mboBox(Selection(IsChanging|DidChange)|Will(Dismiss|PopUp)))|lassDescriptionNeededForClass)|T(oolbar(DidRemoveItem|WillAddItem)|ext(Storage(DidProcessEditing|WillProcessEditing)|Did(BeginEditing|Change|EndEditing)|View(DidChange(Selection|TypingAttributes)|WillChangeNotifyingTextView))|ableView(Selection(IsChanging|DidChange)|ColumnDid(Resize|Move)))|ImageRepRegistryDidChange|OutlineView(Selection(IsChanging|DidChange)|ColumnDid(Resize|Move)|Item(Did(Collapse|Expand)|Will(Collapse|Expand)))|Drawer(Did(Close|Open)|Will(Close|Open))|PopUpButton(CellWillPopUp|WillPopUp)|View(GlobalFrameDidChange|BoundsDidChange|F(ocusDidChange|rameDidChange))|FontSetChanged|W(indow(Did(Resi(ze|gn(Main|Key))|M(iniaturize|ove)|Become(Main|Key)|ChangeScreen(|Profile)|Deminiaturize|Update|E(ndSheet|xpose))|Will(M(iniaturize|ove)|BeginSheet|Close))|orkspace(SessionDid(ResignActive|BecomeActive)|Did(Mount|TerminateApplication|Unmount|PerformFileOperation|Wake|LaunchApplication)|Will(Sleep|Unmount|PowerOff|LaunchApplication)))|A(ntialiasThresholdChanged|ppl(ication(Did(ResignActive|BecomeActive|Hide|ChangeScreenParameters|U(nhide|pdate)|FinishLaunching)|Will(ResignActive|BecomeActive|Hide|Terminate|U(nhide|pdate)|FinishLaunching))|eEventManagerWillProcessFirstEvent)))Notification\\b", + "name": "support.constant.notification.cocoa.objcpp" + }, + { + "match": "\\bNS(RuleEditor(RowType(Simple|Compound)|NestingMode(Si(ngle|mple)|Compound|List))|GradientDraws(BeforeStartingLocation|AfterEndingLocation)|M(inusSetExpressionType|a(chPortDeallocate(ReceiveRight|SendRight|None)|pTable(StrongMemory|CopyIn|ZeroingWeakMemory|ObjectPointerPersonality)))|B(oxCustom|undleExecutableArchitecture(X86|I386|PPC(64)?)|etweenPredicateOperatorType|ackgroundStyle(Raised|Dark|L(ight|owered)))|S(tring(DrawingTruncatesLastVisibleLine|EncodingConversion(ExternalRepresentation|AllowLossy))|ubqueryExpressionType|p(e(ech(SentenceBoundary|ImmediateBoundary|WordBoundary)|llingState(GrammarFlag|SpellingFlag))|litViewDividerStyleThi(n|ck))|e(rvice(RequestTimedOutError|M(iscellaneousError|alformedServiceDictionaryError)|InvalidPasteboardDataError|ErrorM(inimum|aximum)|Application(NotFoundError|LaunchFailedError))|gmentStyle(Round(Rect|ed)|SmallSquare|Capsule|Textured(Rounded|Square)|Automatic)))|H(UDWindowMask|ashTable(StrongMemory|CopyIn|ZeroingWeakMemory|ObjectPointerPersonality))|N(oModeColorPanel|etServiceNoAutoRename)|C(hangeRedone|o(ntainsPredicateOperatorType|l(orRenderingIntent(RelativeColorimetric|Saturation|Default|Perceptual|AbsoluteColorimetric)|lectorDisabledOption))|ellHit(None|ContentArea|TrackableArea|EditableTextArea))|T(imeZoneNameStyle(S(hort(Standard|DaylightSaving)|tandard)|DaylightSaving)|extFieldDatePickerStyle|ableViewSelectionHighlightStyle(Regular|SourceList)|racking(Mouse(Moved|EnteredAndExited)|CursorUpdate|InVisibleRect|EnabledDuringMouseDrag|A(ssumeInside|ctive(In(KeyWindow|ActiveApp)|WhenFirstResponder|Always))))|I(n(tersectSetExpressionType|dexedColorSpaceModel)|mageScale(None|Proportionally(Down|UpOrDown)|AxesIndependently))|Ope(nGLPFAAllowOfflineRenderers|rationQueue(DefaultMaxConcurrentOperationCount|Priority(High|Normal|Very(High|Low)|Low)))|D(iacriticInsensitiveSearch|ownloadsDirectory)|U(nionSetExpressionType|TF(16(BigEndianStringEncoding|StringEncoding|LittleEndianStringEncoding)|32(BigEndianStringEncoding|StringEncoding|LittleEndianStringEncoding)))|P(ointerFunctions(Ma(chVirtualMemory|llocMemory)|Str(ongMemory|uctPersonality)|C(StringPersonality|opyIn)|IntegerPersonality|ZeroingWeakMemory|O(paque(Memory|Personality)|bjectP(ointerPersonality|ersonality)))|at(hStyle(Standard|NavigationBar|PopUp)|ternColorSpaceModel)|rintPanelShows(Scaling|Copies|Orientation|P(a(perSize|ge(Range|SetupAccessory))|review)))|Executable(RuntimeMismatchError|NotLoadableError|ErrorM(inimum|aximum)|L(inkError|oadError)|ArchitectureMismatchError)|KeyValueObservingOption(Initial|Prior)|F(i(ndPanelSubstringMatchType(StartsWith|Contains|EndsWith|FullWord)|leRead(TooLargeError|UnknownStringEncodingError))|orcedOrderingSearch)|Wi(ndow(BackingLocation(MainMemory|Default|VideoMemory)|Sharing(Read(Only|Write)|None)|CollectionBehavior(MoveToActiveSpace|CanJoinAllSpaces|Default))|dthInsensitiveSearch)|AggregateExpressionType)\\b", + "name": "support.constant.cocoa.leopard.objcpp" + }, + { + "match": "\\bNS(R(GB(ModeColorPanel|ColorSpaceModel)|ight(Mouse(D(own(Mask)?|ragged(Mask)?)|Up(Mask)?)|T(ext(Movement|Alignment)|ab(sBezelBorder|StopType))|ArrowFunctionKey)|ound(RectBezelStyle|Bankers|ed(BezelStyle|TokenStyle|DisclosureBezelStyle)|Down|Up|Plain|Line(CapStyle|JoinStyle))|un(StoppedResponse|ContinuesResponse|AbortedResponse)|e(s(izableWindowMask|et(CursorRectsRunLoopOrdering|FunctionKey))|ce(ssedBezelStyle|iver(sCantHandleCommandScriptError|EvaluationScriptError))|turnTextMovement|doFunctionKey|quiredArgumentsMissingScriptError|l(evancyLevelIndicatorStyle|ative(Before|After))|gular(SquareBezelStyle|ControlSize)|moveTraitFontAction)|a(n(domSubelement|geDateMode)|tingLevelIndicatorStyle|dio(ModeMatrix|Button)))|G(IFFileType|lyph(Below|Inscribe(B(elow|ase)|Over(strike|Below)|Above)|Layout(WithPrevious|A(tAPoint|gainstAPoint))|A(ttribute(BidiLevel|Soft|Inscribe|Elastic)|bove))|r(ooveBorder|eaterThan(Comparison|OrEqualTo(Comparison|PredicateOperatorType)|PredicateOperatorType)|a(y(ModeColorPanel|ColorSpaceModel)|dient(None|Con(cave(Strong|Weak)|vex(Strong|Weak)))|phiteControlTint)))|XML(N(o(tationDeclarationKind|de(CompactEmptyElement|IsCDATA|OptionsNone|Use(SingleQuotes|DoubleQuotes)|Pre(serve(NamespaceOrder|C(haracterReferences|DATA)|DTD|Prefixes|E(ntities|mptyElements)|Quotes|Whitespace|A(ttributeOrder|ll))|ttyPrint)|ExpandEmptyElement))|amespaceKind)|CommentKind|TextKind|InvalidKind|D(ocument(X(MLKind|HTMLKind|Include)|HTMLKind|T(idy(XML|HTML)|extKind)|IncludeContentTypeDeclaration|Validate|Kind)|TDKind)|P(arser(GTRequiredError|XMLDeclNot(StartedError|FinishedError)|Mi(splaced(XMLDeclarationError|CDATAEndStringError)|xedContentDeclNot(StartedError|FinishedError))|S(t(andaloneValueError|ringNot(StartedError|ClosedError))|paceRequiredError|eparatorRequiredError)|N(MTOKENRequiredError|o(t(ationNot(StartedError|FinishedError)|WellBalancedError)|DTDError)|amespaceDeclarationError|AMERequiredError)|C(haracterRef(In(DTDError|PrologError|EpilogError)|AtEOFError)|o(nditionalSectionNot(StartedError|FinishedError)|mment(NotFinishedError|ContainsDoubleHyphenError))|DATANotFinishedError)|TagNameMismatchError|In(ternalError|valid(HexCharacterRefError|C(haracter(RefError|InEntityError|Error)|onditionalSectionError)|DecimalCharacterRefError|URIError|Encoding(NameError|Error)))|OutOfMemoryError|D(ocumentStartError|elegateAbortedParseError|OCTYPEDeclNotFinishedError)|U(RI(RequiredError|FragmentError)|n(declaredEntityError|parsedEntityError|knownEncodingError|finishedTagError))|P(CDATARequiredError|ublicIdentifierRequiredError|arsedEntityRef(MissingSemiError|NoNameError|In(Internal(SubsetError|Error)|PrologError|EpilogError)|AtEOFError)|r(ocessingInstructionNot(StartedError|FinishedError)|ematureDocumentEndError))|E(n(codingNotSupportedError|tity(Ref(In(DTDError|PrologError|EpilogError)|erence(MissingSemiError|WithoutNameError)|LoopError|AtEOFError)|BoundaryError|Not(StartedError|FinishedError)|Is(ParameterError|ExternalError)|ValueRequiredError))|qualExpectedError|lementContentDeclNot(StartedError|FinishedError)|xt(ernalS(tandaloneEntityError|ubsetNotFinishedError)|raContentError)|mptyDocumentError)|L(iteralNot(StartedError|FinishedError)|T(RequiredError|SlashRequiredError)|essThanSymbolInAttributeError)|Attribute(RedefinedError|HasNoValueError|Not(StartedError|FinishedError)|ListNot(StartedError|FinishedError)))|rocessingInstructionKind)|E(ntity(GeneralKind|DeclarationKind|UnparsedKind|P(ar(sedKind|ameterKind)|redefined))|lement(Declaration(MixedKind|UndefinedKind|E(lementKind|mptyKind)|Kind|AnyKind)|Kind))|Attribute(N(MToken(sKind|Kind)|otationKind)|CDATAKind|ID(Ref(sKind|Kind)|Kind)|DeclarationKind|En(tit(yKind|iesKind)|umerationKind)|Kind))|M(i(n(XEdge|iaturizableWindowMask|YEdge|uteCalendarUnit)|terLineJoinStyle|ddleSubelement|xedState)|o(nthCalendarUnit|deSwitchFunctionKey|use(Moved(Mask)?|E(ntered(Mask)?|ventSubtype|xited(Mask)?))|veToBezierPathElement|mentary(ChangeButton|Push(Button|InButton)|Light(Button)?))|enuFunctionKey|a(c(intoshInterfaceStyle|OSRomanStringEncoding)|tchesPredicateOperatorType|ppedRead|x(XEdge|YEdge))|ACHOperatingSystem)|B(MPFileType|o(ttomTabsBezelBorder|ldFontMask|rderlessWindowMask|x(Se(condary|parator)|OldStyle|Primary))|uttLineCapStyle|e(zelBorder|velLineJoinStyle|low(Bottom|Top)|gin(sWith(Comparison|PredicateOperatorType)|FunctionKey))|lueControlTint|ack(spaceCharacter|tabTextMovement|ingStore(Retained|Buffered|Nonretained)|TabCharacter|wardsSearch|groundTab)|r(owser(NoColumnResizing|UserColumnResizing|AutoColumnResizing)|eakFunctionKey))|S(h(ift(JISStringEncoding|KeyMask)|ow(ControlGlyphs|InvisibleGlyphs)|adowlessSquareBezelStyle)|y(s(ReqFunctionKey|tem(D(omainMask|efined(Mask)?)|FunctionKey))|mbolStringEncoding)|c(a(nnedOption|le(None|ToFit|Proportionally))|r(oll(er(NoPart|Increment(Page|Line|Arrow)|Decrement(Page|Line|Arrow)|Knob(Slot)?|Arrows(M(inEnd|axEnd)|None|DefaultSetting))|Wheel(Mask)?|LockFunctionKey)|eenChangedEventType))|t(opFunctionKey|r(ingDrawing(OneShot|DisableScreenFontSubstitution|Uses(DeviceMetrics|FontLeading|LineFragmentOrigin))|eam(Status(Reading|NotOpen|Closed|Open(ing)?|Error|Writing|AtEnd)|Event(Has(BytesAvailable|SpaceAvailable)|None|OpenCompleted|E(ndEncountered|rrorOccurred)))))|i(ngle(DateMode|UnderlineStyle)|ze(DownFontAction|UpFontAction))|olarisOperatingSystem|unOSOperatingSystem|pecialPageOrder|e(condCalendarUnit|lect(By(Character|Paragraph|Word)|i(ng(Next|Previous)|onAffinity(Downstream|Upstream))|edTab|FunctionKey)|gmentSwitchTracking(Momentary|Select(One|Any)))|quareLineCapStyle|witchButton|ave(ToOperation|Op(tions(Yes|No|Ask)|eration)|AsOperation)|mall(SquareBezelStyle|C(ontrolSize|apsFontMask)|IconButtonBezelStyle))|H(ighlightModeMatrix|SBModeColorPanel|o(ur(Minute(SecondDatePickerElementFlag|DatePickerElementFlag)|CalendarUnit)|rizontalRuler|meFunctionKey)|TTPCookieAcceptPolicy(Never|OnlyFromMainDocumentDomain|Always)|e(lp(ButtonBezelStyle|KeyMask|FunctionKey)|avierFontAction)|PUXOperatingSystem)|Year(MonthDa(yDatePickerElementFlag|tePickerElementFlag)|CalendarUnit)|N(o(n(StandardCharacterSetFontMask|ZeroWindingRule|activatingPanelMask|LossyASCIIStringEncoding)|Border|t(ification(SuspensionBehavior(Hold|Coalesce|D(eliverImmediately|rop))|NoCoalescing|CoalescingOn(Sender|Name)|DeliverImmediately|PostToAllSessions)|PredicateType|EqualToPredicateOperatorType)|S(cr(iptError|ollerParts)|ubelement|pecifierError)|CellMask|T(itle|opLevelContainersSpecifierError|abs(BezelBorder|NoBorder|LineBorder))|I(nterfaceStyle|mage)|UnderlineStyle|FontChangeAction)|u(ll(Glyph|CellType)|m(eric(Search|PadKeyMask)|berFormatter(Round(Half(Down|Up|Even)|Ceiling|Down|Up|Floor)|Behavior(10|Default)|S(cientificStyle|pellOutStyle)|NoStyle|CurrencyStyle|DecimalStyle|P(ercentStyle|ad(Before(Suffix|Prefix)|After(Suffix|Prefix))))))|e(t(Services(BadArgumentError|NotFoundError|C(ollisionError|ancelledError)|TimeoutError|InvalidError|UnknownError|ActivityInProgress)|workDomainMask)|wlineCharacter|xt(StepInterfaceStyle|FunctionKey))|EXTSTEPStringEncoding|a(t(iveShortGlyphPacking|uralTextAlignment)|rrowFontMask))|C(hange(ReadOtherContents|GrayCell(Mask)?|BackgroundCell(Mask)?|Cleared|Done|Undone|Autosaved)|MYK(ModeColorPanel|ColorSpaceModel)|ircular(BezelStyle|Slider)|o(n(stantValueExpressionType|t(inuousCapacityLevelIndicatorStyle|entsCellMask|ain(sComparison|erSpecifierError)|rol(Glyph|KeyMask))|densedFontMask)|lor(Panel(RGBModeMask|GrayModeMask|HSBModeMask|C(MYKModeMask|olorListModeMask|ustomPaletteModeMask|rayonModeMask)|WheelModeMask|AllModesMask)|ListModeColorPanel)|reServiceDirectory|m(p(osite(XOR|Source(In|O(ut|ver)|Atop)|Highlight|C(opy|lear)|Destination(In|O(ut|ver)|Atop)|Plus(Darker|Lighter))|ressedFontMask)|mandKeyMask))|u(stom(SelectorPredicateOperatorType|PaletteModeColorPanel)|r(sor(Update(Mask)?|PointingDevice)|veToBezierPathElement))|e(nterT(extAlignment|abStopType)|ll(State|H(ighlighted|as(Image(Horizontal|OnLeftOrBottom)|OverlappingImage))|ChangesContents|Is(Bordered|InsetButton)|Disabled|Editable|LightsBy(Gray|Background|Contents)|AllowsMixedState))|l(ipPagination|o(s(ePathBezierPathElement|ableWindowMask)|ckAndCalendarDatePickerStyle)|ear(ControlTint|DisplayFunctionKey|LineFunctionKey))|a(seInsensitive(Search|PredicateOption)|n(notCreateScriptCommandError|cel(Button|TextMovement))|chesDirectory|lculation(NoError|Overflow|DivideByZero|Underflow|LossOfPrecision)|rriageReturnCharacter)|r(itical(Request|AlertStyle)|ayonModeColorPanel))|T(hick(SquareBezelStyle|erSquareBezelStyle)|ypesetter(Behavior|HorizontalTabAction|ContainerBreakAction|ZeroAdvancementAction|OriginalBehavior|ParagraphBreakAction|WhitespaceAction|L(ineBreakAction|atestBehavior))|i(ckMark(Right|Below|Left|Above)|tledWindowMask|meZoneDatePickerElementFlag)|o(olbarItemVisibilityPriority(Standard|High|User|Low)|pTabsBezelBorder|ggleButton)|IFF(Compression(N(one|EXT)|CCITTFAX(3|4)|OldJPEG|JPEG|PackBits|LZW)|FileType)|e(rminate(Now|Cancel|Later)|xt(Read(InapplicableDocumentTypeError|WriteErrorM(inimum|aximum))|Block(M(i(nimum(Height|Width)|ddleAlignment)|a(rgin|ximum(Height|Width)))|B(o(ttomAlignment|rder)|aselineAlignment)|Height|TopAlignment|P(ercentageValueType|adding)|Width|AbsoluteValueType)|StorageEdited(Characters|Attributes)|CellType|ured(RoundedBezelStyle|BackgroundWindowMask|SquareBezelStyle)|Table(FixedLayoutAlgorithm|AutomaticLayoutAlgorithm)|Field(RoundedBezel|SquareBezel|AndStepperDatePickerStyle)|WriteInapplicableDocumentTypeError|ListPrependEnclosingMarker))|woByteGlyphPacking|ab(Character|TextMovement|le(tP(oint(Mask|EventSubtype)?|roximity(Mask|EventSubtype)?)|Column(NoResizing|UserResizingMask|AutoresizingMask)|View(ReverseSequentialColumnAutoresizingStyle|GridNone|S(olid(HorizontalGridLineMask|VerticalGridLineMask)|equentialColumnAutoresizingStyle)|NoColumnAutoresizing|UniformColumnAutoresizingStyle|FirstColumnOnlyAutoresizingStyle|LastColumnOnlyAutoresizingStyle)))|rackModeMatrix)|I(n(sert(CharFunctionKey|FunctionKey|LineFunctionKey)|t(Type|ernalS(criptError|pecifierError))|dexSubelement|validIndexSpecifierError|formational(Request|AlertStyle)|PredicateOperatorType)|talicFontMask|SO(2022JPStringEncoding|Latin(1StringEncoding|2StringEncoding))|dentityMappingCharacterCollection|llegalTextMovement|mage(R(ight|ep(MatchesDevice|LoadStatus(ReadingHeader|Completed|InvalidData|Un(expectedEOF|knownType)|WillNeedAllData)))|Below|C(ellType|ache(BySize|Never|Default|Always))|Interpolation(High|None|Default|Low)|O(nly|verlaps)|Frame(Gr(oove|ayBezel)|Button|None|Photo)|L(oadStatus(ReadError|C(ompleted|ancelled)|InvalidData|UnexpectedEOF)|eft)|A(lign(Right|Bottom(Right|Left)?|Center|Top(Right|Left)?|Left)|bove)))|O(n(State|eByteGlyphPacking|OffButton|lyScrollerArrows)|ther(Mouse(D(own(Mask)?|ragged(Mask)?)|Up(Mask)?)|TextMovement)|SF1OperatingSystem|pe(n(GL(GO(Re(setLibrary|tainRenderers)|ClearFormatCache|FormatCacheSize)|PFA(R(obust|endererID)|M(inimumPolicy|ulti(sample|Screen)|PSafe|aximumPolicy)|BackingStore|S(creenMask|te(ncilSize|reo)|ingleRenderer|upersample|ample(s|Buffers|Alpha))|NoRecovery|C(o(lor(Size|Float)|mpliant)|losestPolicy)|OffScreen|D(oubleBuffer|epthSize)|PixelBuffer|VirtualScreenCount|FullScreen|Window|A(cc(umSize|elerated)|ux(Buffers|DepthStencil)|l(phaSize|lRenderers))))|StepUnicodeReservedBase)|rationNotSupportedForKeyS(criptError|pecifierError))|ffState|KButton|rPredicateType|bjC(B(itfield|oolType)|S(hortType|tr(ingType|uctType)|electorType)|NoType|CharType|ObjectType|DoubleType|UnionType|PointerType|VoidType|FloatType|Long(Type|longType)|ArrayType))|D(i(s(c(losureBezelStyle|reteCapacityLevelIndicatorStyle)|playWindowRunLoopOrdering)|acriticInsensitivePredicateOption|rect(Selection|PredicateModifier))|o(c(ModalWindowMask|ument(Directory|ationDirectory))|ubleType|wn(TextMovement|ArrowFunctionKey))|e(s(cendingPageOrder|ktopDirectory)|cimalTabStopType|v(ice(NColorSpaceModel|IndependentModifierFlagsMask)|eloper(Directory|ApplicationDirectory))|fault(ControlTint|TokenStyle)|lete(Char(acter|FunctionKey)|FunctionKey|LineFunctionKey)|moApplicationDirectory)|a(yCalendarUnit|teFormatter(MediumStyle|Behavior(10|Default)|ShortStyle|NoStyle|FullStyle|LongStyle))|ra(wer(Clos(ingState|edState)|Open(ingState|State))|gOperation(Generic|Move|None|Copy|Delete|Private|Every|Link|All)))|U(ser(CancelledError|D(irectory|omainMask)|FunctionKey)|RL(Handle(NotLoaded|Load(Succeeded|InProgress|Failed))|CredentialPersistence(None|Permanent|ForSession))|n(scaledWindowMask|cachedRead|i(codeStringEncoding|talicFontMask|fiedTitleAndToolbarWindowMask)|d(o(CloseGroupingRunLoopOrdering|FunctionKey)|e(finedDateComponent|rline(Style(Single|None|Thick|Double)|Pattern(Solid|D(ot|ash(Dot(Dot)?)?)))))|known(ColorSpaceModel|P(ointingDevice|ageOrder)|KeyS(criptError|pecifierError))|boldFontMask)|tilityWindowMask|TF8StringEncoding|p(dateWindowsRunLoopOrdering|TextMovement|ArrowFunctionKey))|J(ustifiedTextAlignment|PEG(2000FileType|FileType)|apaneseEUC(GlyphPacking|StringEncoding))|P(o(s(t(Now|erFontMask|WhenIdle|ASAP)|iti(on(Replace|Be(fore|ginning)|End|After)|ve(IntType|DoubleType|FloatType)))|pUp(NoArrow|ArrowAt(Bottom|Center))|werOffEventType|rtraitOrientation)|NGFileType|ush(InCell(Mask)?|OnPushOffButton)|e(n(TipMask|UpperSideMask|PointingDevice|LowerSideMask)|riodic(Mask)?)|P(S(caleField|tatus(Title|Field)|aveButton)|N(ote(Title|Field)|ame(Title|Field))|CopiesField|TitleField|ImageButton|OptionsButton|P(a(perFeedButton|ge(Range(To|From)|ChoiceMatrix))|reviewButton)|LayoutButton)|lainTextTokenStyle|a(useFunctionKey|ragraphSeparatorCharacter|ge(DownFunctionKey|UpFunctionKey))|r(int(ing(ReplyLater|Success|Cancelled|Failure)|ScreenFunctionKey|erTable(NotFound|OK|Error)|FunctionKey)|o(p(ertyList(XMLFormat|MutableContainers(AndLeaves)?|BinaryFormat|Immutable|OpenStepFormat)|rietaryStringEncoding)|gressIndicator(BarStyle|SpinningStyle|Preferred(SmallThickness|Thickness|LargeThickness|AquaThickness)))|e(ssedTab|vFunctionKey))|L(HeightForm|CancelButton|TitleField|ImageButton|O(KButton|rientationMatrix)|UnitsButton|PaperNameButton|WidthForm))|E(n(terCharacter|d(sWith(Comparison|PredicateOperatorType)|FunctionKey))|v(e(nOddWindingRule|rySubelement)|aluatedObjectExpressionType)|qualTo(Comparison|PredicateOperatorType)|ra(serPointingDevice|CalendarUnit|DatePickerElementFlag)|x(clude(10|QuickDrawElementsIconCreationOption)|pandedFontMask|ecuteFunctionKey))|V(i(ew(M(in(XMargin|YMargin)|ax(XMargin|YMargin))|HeightSizable|NotSizable|WidthSizable)|aPanelFontAction)|erticalRuler|a(lidationErrorM(inimum|aximum)|riableExpressionType))|Key(SpecifierEvaluationScriptError|Down(Mask)?|Up(Mask)?|PathExpressionType|Value(MinusSetMutation|SetSetMutation|Change(Re(placement|moval)|Setting|Insertion)|IntersectSetMutation|ObservingOption(New|Old)|UnionSetMutation|ValidationError))|QTMovie(NormalPlayback|Looping(BackAndForthPlayback|Playback))|F(1(1FunctionKey|7FunctionKey|2FunctionKey|8FunctionKey|3FunctionKey|9FunctionKey|4FunctionKey|5FunctionKey|FunctionKey|0FunctionKey|6FunctionKey)|7FunctionKey|i(nd(PanelAction(Replace(A(ndFind|ll(InSelection)?))?|S(howFindPanel|e(tFindString|lectAll(InSelection)?))|Next|Previous)|FunctionKey)|tPagination|le(Read(No(SuchFileError|PermissionError)|CorruptFileError|In(validFileNameError|applicableStringEncodingError)|Un(supportedSchemeError|knownError))|HandlingPanel(CancelButton|OKButton)|NoSuchFileError|ErrorM(inimum|aximum)|Write(NoPermissionError|In(validFileNameError|applicableStringEncodingError)|OutOfSpaceError|Un(supportedSchemeError|knownError))|LockingError)|xedPitchFontMask)|2(1FunctionKey|7FunctionKey|2FunctionKey|8FunctionKey|3FunctionKey|9FunctionKey|4FunctionKey|5FunctionKey|FunctionKey|0FunctionKey|6FunctionKey)|o(nt(Mo(noSpaceTrait|dernSerifsClass)|BoldTrait|S(ymbolicClass|criptsClass|labSerifsClass|ansSerifClass)|C(o(ndensedTrait|llectionApplicationOnlyMask)|larendonSerifsClass)|TransitionalSerifsClass|I(ntegerAdvancementsRenderingMode|talicTrait)|O(ldStyleSerifsClass|rnamentalsClass)|DefaultRenderingMode|U(nknownClass|IOptimizedTrait)|Panel(S(hadowEffectModeMask|t(andardModesMask|rikethroughEffectModeMask)|izeModeMask)|CollectionModeMask|TextColorEffectModeMask|DocumentColorEffectModeMask|UnderlineEffectModeMask|FaceModeMask|All(ModesMask|EffectsModeMask))|ExpandedTrait|VerticalTrait|F(amilyClassMask|reeformSerifsClass)|Antialiased(RenderingMode|IntegerAdvancementsRenderingMode))|cusRing(Below|Type(None|Default|Exterior)|Only|Above)|urByteGlyphPacking|rm(attingError(M(inimum|aximum))?|FeedCharacter))|8FunctionKey|unction(ExpressionType|KeyMask)|3(1FunctionKey|2FunctionKey|3FunctionKey|4FunctionKey|5FunctionKey|FunctionKey|0FunctionKey)|9FunctionKey|4FunctionKey|P(RevertButton|S(ize(Title|Field)|etButton)|CurrentField|Preview(Button|Field))|l(oat(ingPointSamplesBitmapFormat|Type)|agsChanged(Mask)?)|axButton|5FunctionKey|6FunctionKey)|W(heelModeColorPanel|indow(s(NTOperatingSystem|CP125(1StringEncoding|2StringEncoding|3StringEncoding|4StringEncoding|0StringEncoding)|95(InterfaceStyle|OperatingSystem))|M(iniaturizeButton|ovedEventType)|Below|CloseButton|ToolbarButton|ZoomButton|Out|DocumentIconButton|ExposedEventType|Above)|orkspaceLaunch(NewInstance|InhibitingBackgroundOnly|Default|PreferringClassic|WithoutA(ctivation|ddingToRecents)|A(sync|nd(Hide(Others)?|Print)|llowingClassicStartup))|eek(day(CalendarUnit|OrdinalCalendarUnit)|CalendarUnit)|a(ntsBidiLevels|rningAlertStyle)|r(itingDirection(RightToLeft|Natural|LeftToRight)|apCalendarComponents))|L(i(stModeMatrix|ne(Moves(Right|Down|Up|Left)|B(order|reakBy(C(harWrapping|lipping)|Truncating(Middle|Head|Tail)|WordWrapping))|S(eparatorCharacter|weep(Right|Down|Up|Left))|ToBezierPathElement|DoesntMove|arSlider)|teralSearch|kePredicateOperatorType|ghterFontAction|braryDirectory)|ocalDomainMask|e(ssThan(Comparison|OrEqualTo(Comparison|PredicateOperatorType)|PredicateOperatorType)|ft(Mouse(D(own(Mask)?|ragged(Mask)?)|Up(Mask)?)|T(ext(Movement|Alignment)|ab(sBezelBorder|StopType))|ArrowFunctionKey))|a(yout(RightToLeft|NotDone|CantFit|OutOfGlyphs|Done|LeftToRight)|ndscapeOrientation)|ABColorSpaceModel)|A(sc(iiWithDoubleByteEUCGlyphPacking|endingPageOrder)|n(y(Type|PredicateModifier|EventMask)|choredSearch|imation(Blocking|Nonblocking(Threaded)?|E(ffect(DisappearingItemDefault|Poof)|ase(In(Out)?|Out))|Linear)|dPredicateType)|t(Bottom|tachmentCharacter|omicWrite|Top)|SCIIStringEncoding|d(obe(GB1CharacterCollection|CNS1CharacterCollection|Japan(1CharacterCollection|2CharacterCollection)|Korea1CharacterCollection)|dTraitFontAction|minApplicationDirectory)|uto(saveOperation|Pagination)|pp(lication(SupportDirectory|D(irectory|e(fined(Mask)?|legateReply(Success|Cancel|Failure)|activatedEventType))|ActivatedEventType)|KitDefined(Mask)?)|l(ternateKeyMask|pha(ShiftKeyMask|NonpremultipliedBitmapFormat|FirstBitmapFormat)|ert(SecondButtonReturn|ThirdButtonReturn|OtherReturn|DefaultReturn|ErrorReturn|FirstButtonReturn|AlternateReturn)|l(ScrollerParts|DomainsMask|PredicateModifier|LibrariesDirectory|ApplicationsDirectory))|rgument(sWrongScriptError|EvaluationScriptError)|bove(Bottom|Top)|WTEventType))\\b", + "name": "support.constant.cocoa.objcpp" + }, + { + "include": "#c_lang" + }, + { + "include": "#bracketed_content" + } + ], + "repository": { + "c_lang": { + "patterns": [ + { + "include": "#preprocessor-rule-enabled" + }, + { + "include": "#preprocessor-rule-disabled" + }, + { + "include": "#preprocessor-rule-conditional" + }, + { + "include": "#comments" + }, + { + "include": "#switch_statement" + }, + { + "match": "\\b(break|continue|do|else|for|goto|if|_Pragma|return|while)\\b", + "name": "keyword.control.objcpp" + }, + { + "include": "#storage_types" + }, + { + "match": "typedef", + "name": "keyword.other.typedef.objcpp" + }, + { + "match": "\\b(const|extern|register|restrict|static|volatile|inline)\\b", + "name": "storage.modifier.objcpp" + }, + { + "match": "\\bk[A-Z]\\w*\\b", + "name": "constant.other.variable.mac-classic.objcpp" + }, + { + "match": "\\bg[A-Z]\\w*\\b", + "name": "variable.other.readwrite.global.mac-classic.objcpp" + }, + { + "match": "\\bs[A-Z]\\w*\\b", + "name": "variable.other.readwrite.static.mac-classic.objcpp" + }, + { + "match": "\\b(NULL|true|false|TRUE|FALSE)\\b", + "name": "constant.language.objcpp" + }, + { + "include": "#operators" + }, + { + "include": "#numbers" + }, + { + "include": "#strings" + }, + { + "begin": "(?x)\n^\\s* ((\\#)\\s*define) \\s+\t# define\n((?[a-zA-Z_$][\\w$]*))\t # macro name\n(?:\n (\\()\n\t(\n\t \\s* \\g \\s*\t\t # first argument\n\t ((,) \\s* \\g \\s*)* # additional arguments\n\t (?:\\.\\.\\.)?\t\t\t# varargs ellipsis?\n\t)\n (\\))\n)?", + "beginCaptures": { + "1": { + "name": "keyword.control.directive.define.objcpp" + }, + "2": { + "name": "punctuation.definition.directive.objcpp" + }, + "3": { + "name": "entity.name.function.preprocessor.objcpp" + }, + "5": { + "name": "punctuation.definition.parameters.begin.objcpp" + }, + "6": { + "name": "variable.parameter.preprocessor.objcpp" + }, + "8": { + "name": "punctuation.separator.parameters.objcpp" + }, + "9": { + "name": "punctuation.definition.parameters.end.objcpp" + } + }, + "end": "(?=(?://|/\\*))|(?", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.objcpp" + } + }, + "name": "string.quoted.other.lt-gt.include.objcpp" + } + ] + }, + { + "include": "#pragma-mark" + }, + { + "begin": "^\\s*((#)\\s*line)\\b", + "beginCaptures": { + "1": { + "name": "keyword.control.directive.line.objcpp" + }, + "2": { + "name": "punctuation.definition.directive.objcpp" + } + }, + "end": "(?=(?://|/\\*))|(?\\]\\)]))\\s*([a-zA-Z_]\\w*)\\s*(?=(?:\\[\\]\\s*)?(?:,|\\)))", + "captures": { + "1": { + "name": "variable.parameter.probably.objcpp" + } + } + }, + "access-method": { + "name": "meta.function-call.member.objcpp", + "begin": "([a-zA-Z_][a-zA-Z_0-9]*|(?<=[\\]\\)]))\\s*(?:(\\.)|(->))((?:(?:[a-zA-Z_][a-zA-Z_0-9]*)\\s*(?:(?:\\.)|(?:->)))*)\\s*([a-zA-Z_][a-zA-Z_0-9]*)(\\()", + "beginCaptures": { + "1": { + "name": "variable.object.objcpp" + }, + "2": { + "name": "punctuation.separator.dot-access.objcpp" + }, + "3": { + "name": "punctuation.separator.pointer-access.objcpp" + }, + "4": { + "patterns": [ + { + "match": "\\.", + "name": "punctuation.separator.dot-access.objcpp" + }, + { + "match": "->", + "name": "punctuation.separator.pointer-access.objcpp" + }, + { + "match": "[a-zA-Z_][a-zA-Z_0-9]*", + "name": "variable.object.objcpp" + }, + { + "name": "everything.else.objcpp", + "match": ".+" + } + ] + }, + "5": { + "name": "entity.name.function.member.objcpp" + }, + "6": { + "name": "punctuation.section.arguments.begin.bracket.round.function.member.objcpp" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.arguments.end.bracket.round.function.member.objcpp" + } + }, + "patterns": [ + { + "include": "#function-call-innards" + } + ] + }, + "block": { + "patterns": [ + { + "begin": "{", + "beginCaptures": { + "0": { + "name": "punctuation.section.block.begin.bracket.curly.objcpp" + } + }, + "end": "}|(?=\\s*#\\s*(?:elif|else|endif)\\b)", + "endCaptures": { + "0": { + "name": "punctuation.section.block.end.bracket.curly.objcpp" + } + }, + "name": "meta.block.objcpp", + "patterns": [ + { + "include": "#block_innards" + } + ] + } + ] + }, + "block_innards": { + "patterns": [ + { + "include": "#preprocessor-rule-enabled-block" + }, + { + "include": "#preprocessor-rule-disabled-block" + }, + { + "include": "#preprocessor-rule-conditional-block" + }, + { + "include": "#method_access" + }, + { + "include": "#member_access" + }, + { + "include": "#c_function_call" + }, + { + "name": "meta.initialization.objcpp", + "begin": "(?x)\n(?:\n (?:\n\t(?=\\s)(?=+!]+ | \\(\\) | \\[\\]))\n)\n\\s*(\\() # opening bracket", + "beginCaptures": { + "1": { + "name": "variable.other.objcpp" + }, + "2": { + "name": "punctuation.section.parens.begin.bracket.round.initialization.objcpp" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.parens.end.bracket.round.initialization.objcpp" + } + }, + "patterns": [ + { + "include": "#function-call-innards" + } + ] + }, + { + "begin": "{", + "beginCaptures": { + "0": { + "name": "punctuation.section.block.begin.bracket.curly.objcpp" + } + }, + "end": "}|(?=\\s*#\\s*(?:elif|else|endif)\\b)", + "endCaptures": { + "0": { + "name": "punctuation.section.block.end.bracket.curly.objcpp" + } + }, + "patterns": [ + { + "include": "#block_innards" + } + ] + }, + { + "include": "#parens-block" + }, + { + "include": "$base" + } + ] + }, + "c_function_call": { + "begin": "(?x)\n(?!(?:while|for|do|if|else|switch|catch|enumerate|return|typeid|alignof|alignas|sizeof|[cr]?iterate|and|and_eq|bitand|bitor|compl|not|not_eq|or|or_eq|typeid|xor|xor_eq|alignof|alignas)\\s*\\()\n(?=\n(?:[A-Za-z_][A-Za-z0-9_]*+|::)++\\s*\\( # actual name\n|\n(?:(?<=operator)(?:[-*&<>=+!]+|\\(\\)|\\[\\]))\\s*\\(\n)", + "end": "(?<=\\))(?!\\w)", + "name": "meta.function-call.objcpp", + "patterns": [ + { + "include": "#function-call-innards" + } + ] + }, + "comments": { + "patterns": [ + { + "captures": { + "1": { + "name": "meta.toc-list.banner.block.objcpp" + } + }, + "match": "^/\\* =(\\s*.*?)\\s*= \\*/$\\n?", + "name": "comment.block.objcpp" + }, + { + "begin": "/\\*", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.begin.objcpp" + } + }, + "end": "\\*/", + "endCaptures": { + "0": { + "name": "punctuation.definition.comment.end.objcpp" + } + }, + "name": "comment.block.objcpp" + }, + { + "captures": { + "1": { + "name": "meta.toc-list.banner.line.objcpp" + } + }, + "match": "^// =(\\s*.*?)\\s*=\\s*$\\n?", + "name": "comment.line.banner.objcpp" + }, + { + "begin": "(^[ \\t]+)?(?=//)", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.comment.leading.objcpp" + } + }, + "end": "(?!\\G)", + "patterns": [ + { + "begin": "//", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.objcpp" + } + }, + "end": "(?=\\n)", + "name": "comment.line.double-slash.objcpp", + "patterns": [ + { + "include": "#line_continuation_character" + } + ] + } + ] + } + ] + }, + "disabled": { + "begin": "^\\s*#\\s*if(n?def)?\\b.*$", + "end": "^\\s*#\\s*endif\\b", + "patterns": [ + { + "include": "#disabled" + }, + { + "include": "#pragma-mark" + } + ] + }, + "line_continuation_character": { + "patterns": [ + { + "match": "(\\\\)\\n", + "captures": { + "1": { + "name": "constant.character.escape.line-continuation.objcpp" + } + } + } + ] + }, + "parens": { + "name": "meta.parens.objcpp", + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.section.parens.begin.bracket.round.objcpp" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.parens.end.bracket.round.objcpp" + } + }, + "patterns": [ + { + "include": "$base" + } + ] + }, + "parens-block": { + "name": "meta.parens.block.objcpp", + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.section.parens.begin.bracket.round.objcpp" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.parens.end.bracket.round.objcpp" + } + }, + "patterns": [ + { + "include": "#block_innards" + }, + { + "match": "(?-mix:(?>=|\\|=", + "name": "keyword.operator.assignment.compound.bitwise.objcpp" + }, + { + "match": "<<|>>", + "name": "keyword.operator.bitwise.shift.objcpp" + }, + { + "match": "!=|<=|>=|==|<|>", + "name": "keyword.operator.comparison.objcpp" + }, + { + "match": "&&|!|\\|\\|", + "name": "keyword.operator.logical.objcpp" + }, + { + "match": "&|\\||\\^|~", + "name": "keyword.operator.objcpp" + }, + { + "match": "=", + "name": "keyword.operator.assignment.objcpp" + }, + { + "match": "%|\\*|/|-|\\+", + "name": "keyword.operator.objcpp" + }, + { + "begin": "(\\?)", + "beginCaptures": { + "1": { + "name": "keyword.operator.ternary.objcpp" + } + }, + "end": "(:)", + "endCaptures": { + "1": { + "name": "keyword.operator.ternary.objcpp" + } + }, + "patterns": [ + { + "include": "#function-call-innards" + }, + { + "include": "$base" + } + ] + } + ] + }, + "strings": { + "patterns": [ + { + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.objcpp" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.objcpp" + } + }, + "name": "string.quoted.double.objcpp", + "patterns": [ + { + "include": "#string_escaped_char" + }, + { + "include": "#string_placeholder" + }, + { + "include": "#line_continuation_character" + } + ] + }, + { + "begin": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.objcpp" + } + }, + "end": "'", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.objcpp" + } + }, + "name": "string.quoted.single.objcpp", + "patterns": [ + { + "include": "#string_escaped_char" + }, + { + "include": "#line_continuation_character" + } + ] + } + ] + }, + "string_escaped_char": { + "patterns": [ + { + "match": "(?x)\\\\ (\n\\\\\t\t\t |\n[abefnprtv'\"?] |\n[0-3]\\d{,2}\t |\n[4-7]\\d?\t\t|\nx[a-fA-F0-9]{,2} |\nu[a-fA-F0-9]{,4} |\nU[a-fA-F0-9]{,8} )", + "name": "constant.character.escape.objcpp" + }, + { + "match": "\\\\.", + "name": "invalid.illegal.unknown-escape.objcpp" + } + ] + }, + "string_placeholder": { + "patterns": [ + { + "match": "(?x) %\n(\\d+\\$)?\t\t\t\t\t\t # field (argument #)\n[#0\\- +']*\t\t\t\t\t\t # flags\n[,;:_]?\t\t\t\t\t\t\t # separator character (AltiVec)\n((-?\\d+)|\\*(-?\\d+\\$)?)?\t\t # minimum field width\n(\\.((-?\\d+)|\\*(-?\\d+\\$)?)?)?\t# precision\n(hh|h|ll|l|j|t|z|q|L|vh|vl|v|hv|hl)? # length modifier\n[diouxXDOUeEfFgGaACcSspn%]\t\t # conversion type", + "name": "constant.other.placeholder.objcpp" + }, + { + "match": "(%)(?!\"\\s*(PRI|SCN))", + "captures": { + "1": { + "name": "invalid.illegal.placeholder.objcpp" + } + } + } + ] + }, + "storage_types": { + "patterns": [ + { + "match": "(?-mix:(?=+!]+|\\(\\)|\\[\\]))\\s*\\(\n)", + "end": "(?<=\\))(?!\\w)|(?=+!]+|\\(\\)|\\[\\]))\n)\n\\s*(\\()", + "beginCaptures": { + "1": { + "name": "entity.name.function.objcpp" + }, + "2": { + "name": "punctuation.section.arguments.begin.bracket.round.objcpp" + } + }, + "end": "(\\))|(?=+!]+|\\(\\)|\\[\\]))\n)\n\\s*(\\()", + "beginCaptures": { + "1": { + "name": "entity.name.function.objcpp" + }, + "2": { + "name": "punctuation.section.parameters.begin.bracket.round.objcpp" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.parameters.end.bracket.round.objcpp" + } + }, + "patterns": [ + { + "include": "#probably_a_parameter" + }, + { + "include": "#function-innards" + } + ] + }, + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.section.parens.begin.bracket.round.objcpp" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.parens.end.bracket.round.objcpp" + } + }, + "patterns": [ + { + "include": "#function-innards" + } + ] + }, + { + "include": "$base" + } + ] + }, + "function-call-innards": { + "patterns": [ + { + "include": "#comments" + }, + { + "include": "#storage_types" + }, + { + "include": "#method_access" + }, + { + "include": "#member_access" + }, + { + "include": "#operators" + }, + { + "begin": "(?x)\n(?!(?:while|for|do|if|else|switch|catch|enumerate|return|typeid|alignof|alignas|sizeof|[cr]?iterate|and|and_eq|bitand|bitor|compl|not|not_eq|or|or_eq|typeid|xor|xor_eq|alignof|alignas)\\s*\\()\n(\n(?:[A-Za-z_][A-Za-z0-9_]*+|::)++ # actual name\n|\n(?:(?<=operator)(?:[-*&<>=+!]+|\\(\\)|\\[\\]))\n)\n\\s*(\\()", + "beginCaptures": { + "1": { + "name": "entity.name.function.objcpp" + }, + "2": { + "name": "punctuation.section.arguments.begin.bracket.round.objcpp" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.arguments.end.bracket.round.objcpp" + } + }, + "patterns": [ + { + "include": "#function-call-innards" + } + ] + }, + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.section.parens.begin.bracket.round.objcpp" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.parens.end.bracket.round.objcpp" + } + }, + "patterns": [ + { + "include": "#function-call-innards" + } + ] + }, + { + "include": "#block_innards" + } + ] + }, + "default_statement": { + "name": "meta.conditional.case.objcpp", + "begin": "((?\\[\\]=]))", + "patterns": [ + { + "name": "meta.head.switch.objcpp", + "begin": "\\G ?", + "end": "((?:\\{|(?=;)))", + "endCaptures": { + "1": { + "name": "punctuation.section.block.begin.bracket.curly.switch.objcpp" + } + }, + "patterns": [ + { + "include": "#switch_conditional_parentheses" + }, + { + "include": "$base" + } + ] + }, + { + "name": "meta.body.switch.objcpp", + "begin": "(?<=\\{)", + "end": "(\\})", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.switch.objcpp" + } + }, + "patterns": [ + { + "include": "#default_statement" + }, + { + "include": "#case_statement" + }, + { + "include": "$base" + }, + { + "include": "#block_innards" + } + ] + }, + { + "name": "meta.tail.switch.objcpp", + "begin": "(?<=})[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "include": "$base" + } + ] + } + ] + }, + "switch_conditional_parentheses": { + "name": "meta.conditional.switch.objcpp", + "begin": "(\\()", + "beginCaptures": { + "1": { + "name": "punctuation.section.parens.begin.bracket.round.conditional.switch.objcpp" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.parens.end.bracket.round.conditional.switch.objcpp" + } + }, + "patterns": [ + { + "include": "#conditional_context" + } + ] + }, + "static_assert": { + "begin": "(static_assert|_Static_assert)\\s*(\\()", + "beginCaptures": { + "1": { + "name": "keyword.other.static_assert.objcpp" + }, + "2": { + "name": "punctuation.section.arguments.begin.bracket.round.objcpp" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.arguments.end.bracket.round.objcpp" + } + }, + "patterns": [ + { + "name": "meta.static_assert.message.objcpp", + "begin": "(,)\\s*(?=(?:L|u8|u|U\\s*\\\")?)", + "beginCaptures": { + "1": { + "name": "punctuation.separator.delimiter.objcpp" + } + }, + "end": "(?=\\))", + "patterns": [ + { + "include": "#string_context" + }, + { + "include": "#string_context_c" + } + ] + }, + { + "include": "#function_call_context" + } + ] + }, + "conditional_context": { + "patterns": [ + { + "include": "$base" + }, + { + "include": "#block_innards" + } + ] + }, + "member_access": { + "match": "((?:[a-zA-Z_]\\w*|(?<=\\]|\\)))\\s*)(?:((?:\\.\\*|\\.))|((?:->\\*|->)))((?:[a-zA-Z_]\\w*\\s*(?-mix:(?:(?:\\.\\*|\\.))|(?:(?:->\\*|->)))\\s*)*)\\s*(\\b(?!(?:void|char|short|int|signed|unsigned|long|float|double|bool|_Bool|_Complex|_Imaginary|u_char|u_short|u_int|u_long|ushort|uint|u_quad_t|quad_t|qaddr_t|caddr_t|daddr_t|div_t|dev_t|fixpt_t|blkcnt_t|blksize_t|gid_t|in_addr_t|in_port_t|ino_t|key_t|mode_t|nlink_t|id_t|pid_t|off_t|segsz_t|swblk_t|uid_t|id_t|clock_t|size_t|ssize_t|time_t|useconds_t|suseconds_t|pthread_attr_t|pthread_cond_t|pthread_condattr_t|pthread_mutex_t|pthread_mutexattr_t|pthread_once_t|pthread_rwlock_t|pthread_rwlockattr_t|pthread_t|pthread_key_t|int8_t|int16_t|int32_t|int64_t|uint8_t|uint16_t|uint32_t|uint64_t|int_least8_t|int_least16_t|int_least32_t|int_least64_t|uint_least8_t|uint_least16_t|uint_least32_t|uint_least64_t|int_fast8_t|int_fast16_t|int_fast32_t|int_fast64_t|uint_fast8_t|uint_fast16_t|uint_fast32_t|uint_fast64_t|intptr_t|uintptr_t|intmax_t|intmax_t|uintmax_t|uintmax_t|memory_order|atomic_bool|atomic_char|atomic_schar|atomic_uchar|atomic_short|atomic_ushort|atomic_int|atomic_uint|atomic_long|atomic_ulong|atomic_llong|atomic_ullong|atomic_char16_t|atomic_char32_t|atomic_wchar_t|atomic_int_least8_t|atomic_uint_least8_t|atomic_int_least16_t|atomic_uint_least16_t|atomic_int_least32_t|atomic_uint_least32_t|atomic_int_least64_t|atomic_uint_least64_t|atomic_int_fast8_t|atomic_uint_fast8_t|atomic_int_fast16_t|atomic_uint_fast16_t|atomic_int_fast32_t|atomic_uint_fast32_t|atomic_int_fast64_t|atomic_uint_fast64_t|atomic_intptr_t|atomic_uintptr_t|atomic_size_t|atomic_ptrdiff_t|atomic_intmax_t|atomic_uintmax_t))[a-zA-Z_]\\w*\\b(?!\\())", + "captures": { + "1": { + "name": "variable.other.object.access.objcpp" + }, + "2": { + "name": "punctuation.separator.dot-access.objcpp" + }, + "3": { + "name": "punctuation.separator.pointer-access.objcpp" + }, + "4": { + "patterns": [ + { + "include": "#member_access" + }, + { + "include": "#method_access" + }, + { + "match": "((?:[a-zA-Z_]\\w*|(?<=\\]|\\)))\\s*)(?:((?:\\.\\*|\\.))|((?:->\\*|->)))", + "captures": { + "1": { + "name": "variable.other.object.access.objcpp" + }, + "2": { + "name": "punctuation.separator.dot-access.objcpp" + }, + "3": { + "name": "punctuation.separator.pointer-access.objcpp" + } + } + } + ] + }, + "5": { + "name": "variable.other.member.objcpp" + } + } + }, + "method_access": { + "contentName": "meta.function-call.member.objcpp", + "begin": "((?:[a-zA-Z_]\\w*|(?<=\\]|\\)))\\s*)(?:((?:\\.\\*|\\.))|((?:->\\*|->)))((?:[a-zA-Z_]\\w*\\s*(?-mix:(?:(?:\\.\\*|\\.))|(?:(?:->\\*|->)))\\s*)*)\\s*([a-zA-Z_]\\w*)(\\()", + "beginCaptures": { + "1": { + "name": "variable.other.object.access.objcpp" + }, + "2": { + "name": "punctuation.separator.dot-access.objcpp" + }, + "3": { + "name": "punctuation.separator.pointer-access.objcpp" + }, + "4": { + "patterns": [ + { + "include": "#member_access" + }, + { + "include": "#method_access" + }, + { + "match": "((?:[a-zA-Z_]\\w*|(?<=\\]|\\)))\\s*)(?:((?:\\.\\*|\\.))|((?:->\\*|->)))", + "captures": { + "1": { + "name": "variable.other.object.access.objcpp" + }, + "2": { + "name": "punctuation.separator.dot-access.objcpp" + }, + "3": { + "name": "punctuation.separator.pointer-access.objcpp" + } + } + } + ] + }, + "5": { + "name": "entity.name.function.member.objcpp" + }, + "6": { + "name": "punctuation.section.arguments.begin.bracket.round.function.member.objcpp" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.arguments.end.bracket.round.function.member.objcpp" + } + }, + "patterns": [ + { + "include": "#function-call-innards" + } + ] + }, + "numbers": { + "begin": "(?", + "endCaptures": { + "0": { + "name": "meta.template.angle-brackets.end.objcpp" + } + }, + "name": "template.definition.objcpp", + "patterns": [ + { + "include": "#template_definition_argument" + } + ] + }, + "template_definition_argument": { + "match": "\\s*(?:([a-zA-Z_][a-zA-Z_0-9]*\\s*)|((?:[a-zA-Z_][a-zA-Z_0-9]*\\s+)*)([a-zA-Z_][a-zA-Z_0-9]*)|([a-zA-Z_][a-zA-Z_0-9]*)\\s*(\\.\\.\\.)\\s*([a-zA-Z_][a-zA-Z_0-9]*)|((?:[a-zA-Z_][a-zA-Z_0-9]*\\s+)*)([a-zA-Z_][a-zA-Z_0-9]*)\\s*(=)\\s*(\\w+))(,|(?=>))", + "captures": { + "1": { + "name": "storage.type.template.objcpp" + }, + "2": { + "name": "storage.type.template.objcpp" + }, + "3": { + "name": "entity.name.type.template.objcpp" + }, + "4": { + "name": "storage.type.template.objcpp" + }, + "5": { + "name": "meta.template.operator.ellipsis.objcpp" + }, + "6": { + "name": "entity.name.type.template.objcpp" + }, + "7": { + "name": "storage.type.template.objcpp" + }, + "8": { + "name": "entity.name.type.template.objcpp" + }, + "9": { + "name": "keyword.operator.assignment.objcpp" + }, + "10": { + "name": "constant.language.objcpp" + }, + "11": { + "name": "meta.template.operator.comma.objcpp" + } + } + }, + "angle_brackets": { + "begin": "<", + "end": ">", + "name": "meta.angle-brackets.objcpp", + "patterns": [ + { + "include": "#angle_brackets" + }, + { + "include": "$base" + } + ] + }, + "block": { + "begin": "\\{", + "beginCaptures": { + "0": { + "name": "punctuation.section.block.begin.bracket.curly.objcpp" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.section.block.end.bracket.curly.objcpp" + } + }, + "name": "meta.block.objcpp", + "patterns": [ + { + "captures": { + "1": { + "name": "support.function.any-method.objcpp" + }, + "2": { + "name": "punctuation.definition.parameters.objcpp" + } + }, + "match": "(?x)\n(\n (?!while|for|do|if|else|switch|catch|enumerate|return|r?iterate)\n (?:\\b[A-Za-z_][A-Za-z0-9_]*+\\b|::)*+ # actual name\n)\n\\s*(\\() # opening bracket", + "name": "meta.function-call.objcpp" + }, + { + "include": "$base" + } + ] + }, + "constructor": { + "patterns": [ + { + "begin": "(?x)\n(?:^\\s*) # beginning of line\n((?!while|for|do|if|else|switch|catch|enumerate|r?iterate)[A-Za-z_][A-Za-z0-9_:]*) # actual name\n\\s*(\\() # opening bracket", + "beginCaptures": { + "1": { + "name": "entity.name.function.constructor.objcpp" + }, + "2": { + "name": "punctuation.definition.parameters.begin.objcpp" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.parameters.end.objcpp" + } + }, + "name": "meta.function.constructor.objcpp", + "patterns": [ + { + "include": "#probably_a_parameter" + }, + { + "include": "#function-innards" + } + ] + }, + { + "begin": "(?x)\n(:)\n(\n (?=\n \\s*[A-Za-z_][A-Za-z0-9_:]* # actual name\n \\s* (\\() # opening bracket\n )\n)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.parameters.objcpp" + } + }, + "end": "(?=\\{)", + "name": "meta.function.constructor.initializer-list.objcpp", + "patterns": [ + { + "include": "$base" + } + ] + } + ] + }, + "special_block": { + "patterns": [ + { + "begin": "\\b(using)\\b\\s*(namespace)\\b\\s*((?:[_A-Za-z][_A-Za-z0-9]*\\b(::)?)*)", + "beginCaptures": { + "1": { + "name": "keyword.control.objcpp" + }, + "2": { + "name": "storage.type.namespace.objcpp" + }, + "3": { + "name": "entity.name.type.objcpp" + } + }, + "end": ";", + "endCaptures": { + "0": { + "name": "punctuation.terminator.statement.objcpp" + } + }, + "name": "meta.using-namespace-declaration.objcpp" + }, + { + "begin": "\\b(namespace)\\b\\s*([_A-Za-z][_A-Za-z0-9]*\\b)?+", + "beginCaptures": { + "1": { + "name": "storage.type.namespace.objcpp" + }, + "2": { + "name": "entity.name.type.objcpp" + } + }, + "captures": { + "1": { + "name": "keyword.control.namespace.$2.objcpp" + } + }, + "end": "(?<=\\})|(?=(;|,|\\(|\\)|>|\\[|\\]|=))", + "name": "meta.namespace-block.objcpp", + "patterns": [ + { + "begin": "\\{", + "beginCaptures": { + "0": { + "name": "punctuation.definition.scope.objcpp" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.definition.scope.objcpp" + } + }, + "patterns": [ + { + "include": "#special_block" + }, + { + "include": "#constructor" + }, + { + "include": "$base" + } + ] + }, + { + "include": "$base" + } + ] + }, + { + "begin": "\\b(?:(class)|(struct))\\b\\s*([_A-Za-z][_A-Za-z0-9]*\\b)?+(\\s*:\\s*(public|protected|private)\\s*([_A-Za-z][_A-Za-z0-9]*\\b)((\\s*,\\s*(public|protected|private)\\s*[_A-Za-z][_A-Za-z0-9]*\\b)*))?", + "beginCaptures": { + "1": { + "name": "storage.type.class.objcpp" + }, + "2": { + "name": "storage.type.struct.objcpp" + }, + "3": { + "name": "entity.name.type.objcpp" + }, + "5": { + "name": "storage.type.modifier.access.objcpp" + }, + "6": { + "name": "entity.name.type.inherited.objcpp" + }, + "7": { + "patterns": [ + { + "match": "(public|protected|private)", + "name": "storage.type.modifier.access.objcpp" + }, + { + "match": "[_A-Za-z][_A-Za-z0-9]*", + "name": "entity.name.type.inherited.objcpp" + } + ] + } + }, + "end": "(?<=\\})|(?=(;|\\(|\\)|>|\\[|\\]|=))", + "name": "meta.class-struct-block.objcpp", + "patterns": [ + { + "include": "#angle_brackets" + }, + { + "begin": "\\{", + "beginCaptures": { + "0": { + "name": "punctuation.section.block.begin.bracket.curly.objcpp" + } + }, + "end": "(\\})(\\s*\\n)?", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.objcpp" + }, + "2": { + "name": "invalid.illegal.you-forgot-semicolon.objcpp" + } + }, + "patterns": [ + { + "include": "#special_block" + }, + { + "include": "#constructor" + }, + { + "include": "$base" + } + ] + }, + { + "include": "$base" + } + ] + }, + { + "begin": "\\b(extern)(?=\\s*\")", + "beginCaptures": { + "1": { + "name": "storage.modifier.objcpp" + } + }, + "end": "(?<=\\})|(?=\\w)|(?=\\s*#\\s*endif\\b)", + "name": "meta.extern-block.objcpp", + "patterns": [ + { + "begin": "\\{", + "beginCaptures": { + "0": { + "name": "punctuation.section.block.begin.bracket.curly.objcpp" + } + }, + "end": "\\}|(?=\\s*#\\s*endif\\b)", + "endCaptures": { + "0": { + "name": "punctuation.section.block.end.bracket.curly.objcpp" + } + }, + "patterns": [ + { + "include": "#special_block" + }, + { + "include": "$base" + } + ] + }, + { + "include": "$base" + } + ] + } + ] + }, + "strings": { + "patterns": [ + { + "begin": "(u|u8|U|L)?\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.objcpp" + }, + "1": { + "name": "meta.encoding.objcpp" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.objcpp" + } + }, + "name": "string.quoted.double.objcpp", + "patterns": [ + { + "match": "\\\\u\\h{4}|\\\\U\\h{8}", + "name": "constant.character.escape.objcpp" + }, + { + "match": "\\\\['\"?\\\\abfnrtv]", + "name": "constant.character.escape.objcpp" + }, + { + "match": "\\\\[0-7]{1,3}", + "name": "constant.character.escape.objcpp" + }, + { + "match": "\\\\x\\h+", + "name": "constant.character.escape.objcpp" + }, + { + "include": "#string_placeholder" + } + ] + }, + { + "begin": "(u|u8|U|L)?R\"(?:([^ ()\\\\\\t]{0,16})|([^ ()\\\\\\t]*))\\(", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.objcpp" + }, + "1": { + "name": "meta.encoding.objcpp" + }, + "3": { + "name": "invalid.illegal.delimiter-too-long.objcpp" + } + }, + "end": "\\)\\2(\\3)\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.objcpp" + }, + "1": { + "name": "invalid.illegal.delimiter-too-long.objcpp" + } + }, + "name": "string.quoted.double.raw.objcpp" + } + ] + } + } + }, + "cpp_lang_newish": { + "patterns": [ + { + "include": "#special_block" + }, + { + "match": "(?-mix:##[a-zA-Z_]\\w*(?!\\w))", + "name": "variable.other.macro.argument.objcpp" + }, + { + "include": "#strings" + }, + { + "match": "(?[a-zA-Z_$][\\w$]*))\t # macro name\n(?:\n (\\()\n\t(\n\t \\s* \\g \\s*\t\t # first argument\n\t ((,) \\s* \\g \\s*)* # additional arguments\n\t (?:\\.\\.\\.)?\t\t\t# varargs ellipsis?\n\t)\n (\\))\n)?", + "beginCaptures": { + "1": { + "name": "keyword.control.directive.define.objcpp" + }, + "2": { + "name": "punctuation.definition.directive.objcpp" + }, + "3": { + "name": "entity.name.function.preprocessor.objcpp" + }, + "5": { + "name": "punctuation.definition.parameters.begin.objcpp" + }, + "6": { + "name": "variable.parameter.preprocessor.objcpp" + }, + "8": { + "name": "punctuation.separator.parameters.objcpp" + }, + "9": { + "name": "punctuation.definition.parameters.end.objcpp" + } + }, + "end": "(?=(?://|/\\*))|(?", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.objcpp" + } + }, + "name": "string.quoted.other.lt-gt.include.objcpp" + } + ] + }, + { + "include": "#pragma-mark" + }, + { + "begin": "^\\s*((#)\\s*line)\\b", + "beginCaptures": { + "1": { + "name": "keyword.control.directive.line.objcpp" + }, + "2": { + "name": "punctuation.definition.directive.objcpp" + } + }, + "end": "(?=(?://|/\\*))|(?,\\w])*>\\s*", + "captures": { + "0": { + "name": "meta.template.call.objcpp", + "patterns": [ + { + "include": "#storage_types_c" + }, + { + "include": "#constants" + }, + { + "include": "#scope_resolution" + }, + { + "match": "(?))", + "endCaptures": { + "1": { + "name": "punctuation.section.angle-brackets.end.template.definition.objcpp" + } + }, + "patterns": [ + { + "include": "#scope_resolution" + }, + { + "include": "#template_definition_argument" + }, + { + "include": "#template_call_innards" + } + ] + }, + "template_definition_argument": { + "match": "((?:(?:(?:(?:(?:(?:\\s*([a-zA-Z_]\\w*)|((?:[a-zA-Z_]\\w*\\s+)+)([a-zA-Z_]\\w*)))|([a-zA-Z_]\\w*)\\s*(\\.\\.\\.)\\s*([a-zA-Z_]\\w*)))|((?:[a-zA-Z_]\\w*\\s+)*)([a-zA-Z_]\\w*)\\s*([=])\\s*(\\w+)))\\s*(?:(?:(,)|(?=>))))", + "captures": { + "2": { + "name": "storage.type.template.argument.$1.objcpp" + }, + "3": { + "name": "storage.type.template.argument.$2.objcpp" + }, + "4": { + "name": "entity.name.type.template.objcpp" + }, + "5": { + "name": "storage.type.template.objcpp" + }, + "6": { + "name": "keyword.operator.ellipsis.template.definition.objcpp" + }, + "7": { + "name": "entity.name.type.template.objcpp" + }, + "8": { + "name": "storage.type.template.objcpp" + }, + "9": { + "name": "entity.name.type.template.objcpp" + }, + "10": { + "name": "keyword.operator.assignment.objcpp" + }, + "11": { + "name": "constant.other.objcpp" + }, + "12": { + "name": "punctuation.separator.comma.template.argument.objcpp" + } + } + }, + "scope_resolution": { + "match": "((?:[a-zA-Z_]\\w*\\s*(?:(?:<(?:[\\s<>,\\w])*>\\s*))?::)*\\s*)([a-zA-Z_]\\w*)\\s*((?:<(?:[\\s<>,\\w])*>\\s*))?(::)", + "captures": { + "1": { + "patterns": [ + { + "include": "#scope_resolution" + } + ] + }, + "2": { + "name": "entity.name.namespace.scope-resolution.objcpp" + }, + "3": { + "patterns": [ + { + "include": "#template_call_innards" + } + ] + }, + "4": { + "name": "punctuation.separator.namespace.access.objcpp" + } + }, + "name": "meta.scope-resolution.objcpp" + }, + "angle_brackets": { + "begin": "<", + "end": ">", + "name": "meta.angle-brackets.objcpp", + "patterns": [ + { + "include": "#angle_brackets" + }, + { + "include": "$base" + } + ] + }, + "block": { + "begin": "\\{", + "beginCaptures": { + "0": { + "name": "punctuation.section.block.begin.bracket.curly.objcpp" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.section.block.end.bracket.curly.objcpp" + } + }, + "name": "meta.block.objcpp", + "patterns": [ + { + "captures": { + "1": { + "name": "support.function.any-method.objcpp" + }, + "2": { + "name": "punctuation.definition.parameters.objcpp" + } + }, + "match": "(?x)\n(\n (?!while|for|do|if|else|switch|catch|return)\n (?:\\b[A-Za-z_][A-Za-z0-9_]*+\\b|::)*+ # actual name\n)\n\\s*(\\() # opening bracket", + "name": "meta.function-call.objcpp" + }, + { + "include": "$base" + } + ] + }, + "constructor": { + "patterns": [ + { + "begin": "(?x)\n(?:^\\s*) # beginning of line\n((?!while|for|do|if|else|switch|catch)[A-Za-z_][A-Za-z0-9_:]*) # actual name\n\\s*(\\() # opening bracket", + "beginCaptures": { + "1": { + "name": "entity.name.function.constructor.objcpp" + }, + "2": { + "name": "punctuation.definition.parameters.begin.constructor.objcpp" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.definition.parameters.end.constructor.objcpp" + } + }, + "name": "meta.function.constructor.objcpp", + "patterns": [ + { + "include": "#probably_a_parameter" + }, + { + "include": "#function-innards-c" + } + ] + }, + { + "begin": "(?x)\n(:)\n(\n (?=\n \\s*[A-Za-z_][A-Za-z0-9_:]* # actual name\n \\s* (\\() # opening bracket\n )\n)", + "beginCaptures": { + "1": { + "name": "punctuation.definition.initializer-list.parameters.objcpp" + } + }, + "end": "(?=\\{)", + "name": "meta.function.constructor.initializer-list.objcpp", + "patterns": [ + { + "include": "$base" + } + ] + } + ] + }, + "special_block": { + "patterns": [ + { + "comment": "https://en.cppreference.com/w/cpp/language/namespace", + "begin": "\\b(using)\\s+(namespace)\\s+(?:((?:[a-zA-Z_]\\w*\\s*(?:(?:<(?:[\\s<>,\\w])*>\\s*))?::)*)\\s*)?((?,\\w])*>\\s*))?::)*[a-zA-Z_]\\w*)|(?={)))", + "beginCaptures": { + "1": { + "name": "keyword.other.namespace.definition.objcpp storage.type.namespace.definition.objcpp" + }, + "2": { + "patterns": [ + { + "match": "(?-mix:(?|\\[|\\]|=))", + "name": "meta.namespace-block.objcpp", + "patterns": [ + { + "begin": "\\{", + "beginCaptures": { + "0": { + "name": "punctuation.definition.scope.objcpp" + } + }, + "end": "\\}", + "endCaptures": { + "0": { + "name": "punctuation.definition.scope.objcpp" + } + }, + "patterns": [ + { + "include": "#special_block" + }, + { + "include": "#constructor" + }, + { + "include": "$base" + } + ] + }, + { + "include": "$base" + } + ] + }, + { + "begin": "\\b(?:(class)|(struct))\\b\\s*([_A-Za-z][_A-Za-z0-9]*\\b)?+(\\s*:\\s*(public|protected|private)\\s*([_A-Za-z][_A-Za-z0-9]*\\b)((\\s*,\\s*(public|protected|private)\\s*[_A-Za-z][_A-Za-z0-9]*\\b)*))?", + "beginCaptures": { + "1": { + "name": "storage.type.class.objcpp" + }, + "2": { + "name": "storage.type.struct.objcpp" + }, + "3": { + "name": "entity.name.type.objcpp" + }, + "5": { + "name": "storage.type.modifier.access.objcpp" + }, + "6": { + "name": "entity.name.type.inherited.objcpp" + }, + "7": { + "patterns": [ + { + "match": "(public|protected|private)", + "name": "storage.type.modifier.access.objcpp" + }, + { + "match": "[_A-Za-z][_A-Za-z0-9]*", + "name": "entity.name.type.inherited.objcpp" + } + ] + } + }, + "end": "(?<=\\})|(;)|(?=(\\(|\\)|>|\\[|\\]|=))", + "endCaptures": { + "1": { + "name": "punctuation.terminator.statement.objcpp" + } + }, + "name": "meta.class-struct-block.objcpp", + "patterns": [ + { + "include": "#angle_brackets" + }, + { + "begin": "\\{", + "beginCaptures": { + "0": { + "name": "punctuation.section.block.begin.bracket.curly.objcpp" + } + }, + "end": "(\\})(\\s*\\n)?", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.objcpp" + }, + "2": { + "name": "invalid.illegal.you-forgot-semicolon.objcpp" + } + }, + "patterns": [ + { + "include": "#special_block" + }, + { + "include": "#constructor" + }, + { + "include": "$base" + } + ] + }, + { + "include": "$base" + } + ] + }, + { + "begin": "\\b(extern)(?=\\s*\")", + "beginCaptures": { + "1": { + "name": "storage.modifier.objcpp" + } + }, + "end": "(?<=\\})|(?=\\w)|(?=\\s*#\\s*endif\\b)", + "name": "meta.extern-block.objcpp", + "patterns": [ + { + "begin": "\\{", + "beginCaptures": { + "0": { + "name": "punctuation.section.block.begin.bracket.curly.objcpp" + } + }, + "end": "\\}|(?=\\s*#\\s*endif\\b)", + "endCaptures": { + "0": { + "name": "punctuation.section.block.end.bracket.curly.objcpp" + } + }, + "patterns": [ + { + "include": "#special_block" + }, + { + "include": "$base" + } + ] + }, + { + "include": "$base" + } + ] + } + ] + }, + "strings": { + "patterns": [ + { + "begin": "(u|u8|U|L)?\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.objcpp" + }, + "1": { + "name": "meta.encoding.objcpp" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.objcpp" + } + }, + "name": "string.quoted.double.objcpp", + "patterns": [ + { + "match": "\\\\u\\h{4}|\\\\U\\h{8}", + "name": "constant.character.escape.objcpp" + }, + { + "match": "\\\\['\"?\\\\abfnrtv]", + "name": "constant.character.escape.objcpp" + }, + { + "match": "\\\\[0-7]{1,3}", + "name": "constant.character.escape.objcpp" + }, + { + "match": "\\\\x\\h+", + "name": "constant.character.escape.objcpp" + }, + { + "include": "#string_placeholder-c" + } + ] + }, + { + "begin": "(u|u8|U|L)?R\"(?:([^ ()\\\\\\t]{0,16})|([^ ()\\\\\\t]*))\\(", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.objcpp" + }, + "1": { + "name": "meta.encoding.objcpp" + }, + "3": { + "name": "invalid.illegal.delimiter-too-long.objcpp" + } + }, + "end": "\\)\\2(\\3)\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.objcpp" + }, + "1": { + "name": "invalid.illegal.delimiter-too-long.objcpp" + } + }, + "name": "string.quoted.double.raw.objcpp" + } + ] + }, + "probably_a_parameter": { + "match": "(?:(?:([a-zA-Z_]\\w*)\\s*(?==)|(?<=\\w\\s|\\*\\/|[&*>\\]\\)])\\s*([a-zA-Z_]\\w*)\\s*(?=(?:\\[\\]\\s*)?(?:(?:,|\\))))))", + "captures": { + "1": { + "name": "variable.parameter.probably.defaulted.objcpp" + }, + "2": { + "name": "variable.parameter.probably.objcpp" + } + } + }, + "operator_overload": { + "begin": "((?:[a-zA-Z_]\\w*\\s*(?:(?:<(?:[\\s<>,\\w])*>\\s*))?::)*)\\s*(operator)((?:(?:\\s*(?:\\+\\+|\\-\\-|\\(\\)|\\[\\]|\\->|\\+\\+|\\-\\-|\\+|\\-|!|~|\\*|&|\\->\\*|\\*|\\/|%|\\+|\\-|<<|>>|<=>|<|<=|>|>=|==|!=|&|\\^|\\||&&|\\|\\||=|\\+=|\\-=|\\*=|\\/=|%=|<<=|>>=|&=|\\^=|\\|=|,)|\\s+(?:(?:(?:new|new\\[\\]|delete|delete\\[\\])|(?:[a-zA-Z_]\\w*\\s*(?:(?:<(?:[\\s<>,\\w])*>\\s*))?::)*[a-zA-Z_]\\w*\\s*(?:&)?)))))\\s*(\\()", + "beginCaptures": { + "1": { + "name": "entity.scope.objcpp" + }, + "2": { + "name": "keyword.other.operator.overload.objcpp" + }, + "3": { + "name": "entity.name.operator.overloadee.objcpp" + }, + "4": { + "name": "punctuation.section.parameters.begin.bracket.round.objcpp" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.parameters.end.bracket.round.objcpp" + } + }, + "name": "meta.function.definition.parameters.operator-overload.objcpp", + "patterns": [ + { + "include": "#probably_a_parameter" + }, + { + "include": "#function-innards-c" + } + ] + }, + "access-method": { + "name": "meta.function-call.member.objcpp", + "begin": "([a-zA-Z_][a-zA-Z_0-9]*|(?<=[\\]\\)]))\\s*(?:(\\.)|(->))((?:(?:[a-zA-Z_][a-zA-Z_0-9]*)\\s*(?:(?:\\.)|(?:->)))*)\\s*([a-zA-Z_][a-zA-Z_0-9]*)(\\()", + "beginCaptures": { + "1": { + "name": "variable.other.object.objcpp" + }, + "2": { + "name": "punctuation.separator.dot-access.objcpp" + }, + "3": { + "name": "punctuation.separator.pointer-access.objcpp" + }, + "4": { + "patterns": [ + { + "match": "\\.", + "name": "punctuation.separator.dot-access.objcpp" + }, + { + "match": "->", + "name": "punctuation.separator.pointer-access.objcpp" + }, + { + "match": "[a-zA-Z_][a-zA-Z_0-9]*", + "name": "variable.other.object.objcpp" + }, + { + "name": "everything.else.objcpp", + "match": ".+" + } + ] + }, + "5": { + "name": "entity.name.function.member.objcpp" + }, + "6": { + "name": "punctuation.section.arguments.begin.bracket.round.function.member.objcpp" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.arguments.end.bracket.round.function.member.objcpp" + } + }, + "patterns": [ + { + "include": "#function-call-innards-c" + } + ] + }, + "access-member": { + "name": "variable.other.object.access.objcpp", + "match": "(?:(?:([a-zA-Z_]\\w*)|(?<=\\]|\\))))\\s*(?:(?:((?:(?:\\.|\\.\\*)))|((?:(?:->|->\\*)))))\\s*((?:[a-zA-Z_]\\w*\\s*(?:(?:\\.|->))\\s*)*)\\b(?!(?:auto|void|char|short|int|signed|unsigned|long|float|double|bool|wchar_t|u_char|u_short|u_int|u_long|ushort|uint|u_quad_t|quad_t|qaddr_t|caddr_t|daddr_t|div_t|dev_t|fixpt_t|blkcnt_t|blksize_t|gid_t|in_addr_t|in_port_t|ino_t|key_t|mode_t|nlink_t|id_t|pid_t|off_t|segsz_t|swblk_t|uid_t|id_t|clock_t|size_t|ssize_t|time_t|useconds_t|suseconds_t|pthread_attr_t|pthread_cond_t|pthread_condattr_t|pthread_mutex_t|pthread_mutexattr_t|pthread_once_t|pthread_rwlock_t|pthread_rwlockattr_t|pthread_t|pthread_key_t|int8_t|int16_t|int32_t|int64_t|uint8_t|uint16_t|uint32_t|uint64_t|int_least8_t|int_least16_t|int_least32_t|int_least64_t|uint_least8_t|uint_least16_t|uint_least32_t|uint_least64_t|int_fast8_t|int_fast16_t|int_fast32_t|int_fast64_t|uint_fast8_t|uint_fast16_t|uint_fast32_t|uint_fast64_t|intptr_t|uintptr_t|intmax_t|intmax_t|uintmax_t|uintmax_t))([a-zA-Z_]\\w*)\\b(?!\\()", + "captures": { + "1": { + "name": "variable.other.object.objcpp" + }, + "2": { + "name": "punctuation.separator.dot-access.objcpp" + }, + "3": { + "name": "punctuation.separator.pointer-access.objcpp" + }, + "4": { + "patterns": [ + { + "match": "\\.", + "name": "punctuation.separator.dot-access.objcpp" + }, + { + "match": "->", + "name": "punctuation.separator.pointer-access.objcpp" + }, + { + "match": "[a-zA-Z_]\\w*", + "name": "variable.other.object.objcpp" + }, + { + "match": ".+", + "name": "everything.else.objcpp" + } + ] + }, + "5": { + "name": "variable.other.member.objcpp" + } + } + }, + "block-c": { + "patterns": [ + { + "begin": "{", + "beginCaptures": { + "0": { + "name": "punctuation.section.block.begin.bracket.curly.objcpp" + } + }, + "end": "}|(?=\\s*#\\s*(?:elif|else|endif)\\b)", + "endCaptures": { + "0": { + "name": "punctuation.section.block.end.bracket.curly.objcpp" + } + }, + "name": "meta.block.objcpp", + "patterns": [ + { + "include": "#block_innards-c" + } + ] + } + ] + }, + "block_innards-c": { + "patterns": [ + { + "include": "#preprocessor-rule-enabled-block" + }, + { + "include": "#preprocessor-rule-disabled-block" + }, + { + "include": "#preprocessor-rule-conditional-block" + }, + { + "include": "#access-method" + }, + { + "include": "#access-member" + }, + { + "include": "#c_function_call" + }, + { + "name": "meta.initialization.objcpp", + "begin": "(?x)\n(?:\n (?:\n\t(?=\\s)(?=+!]+ | \\(\\) | \\[\\]))\n)\n\\s*(\\() # opening bracket", + "beginCaptures": { + "1": { + "name": "variable.other.objcpp" + }, + "2": { + "name": "punctuation.section.parens.begin.bracket.round.initialization.objcpp" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.parens.end.bracket.round.initialization.objcpp" + } + }, + "patterns": [ + { + "include": "#function-call-innards-c" + } + ] + }, + { + "begin": "{", + "beginCaptures": { + "0": { + "name": "punctuation.section.block.begin.bracket.curly.objcpp" + } + }, + "end": "}|(?=\\s*#\\s*(?:elif|else|endif)\\b)", + "endCaptures": { + "0": { + "name": "punctuation.section.block.end.bracket.curly.objcpp" + } + }, + "patterns": [ + { + "include": "#block_innards-c" + } + ] + }, + { + "include": "#parens-block-c" + }, + { + "include": "$base" + } + ] + }, + "c_function_call": { + "begin": "(?x)\n(?!(?:while|for|do|if|else|switch|catch|return|typeid|alignof|alignas|sizeof|and|and_eq|bitand|bitor|compl|not|not_eq|or|or_eq|typeid|xor|xor_eq|alignof|alignas)\\s*\\()\n(?=\n(?:[A-Za-z_][A-Za-z0-9_]*+|::)++\\s*(?:(?:<(?:[\\s<>,\\w])*>\\s*))?\\( # actual name\n|\n(?:(?<=operator)(?:[-*&<>=+!]+|\\(\\)|\\[\\]))\\s*\\(\n)", + "end": "(?<=\\))(?!\\w)", + "name": "meta.function-call.objcpp", + "patterns": [ + { + "include": "#function-call-innards-c" + } + ] + }, + "comments-c": { + "patterns": [ + { + "captures": { + "1": { + "name": "meta.toc-list.banner.block.objcpp" + } + }, + "match": "^/\\* =(\\s*.*?)\\s*= \\*/$\\n?", + "name": "comment.block.objcpp" + }, + { + "begin": "/\\*", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.begin.objcpp" + } + }, + "end": "\\*/", + "endCaptures": { + "0": { + "name": "punctuation.definition.comment.end.objcpp" + } + }, + "name": "comment.block.objcpp" + }, + { + "captures": { + "1": { + "name": "meta.toc-list.banner.line.objcpp" + } + }, + "match": "^// =(\\s*.*?)\\s*=\\s*$\\n?", + "name": "comment.line.banner.objcpp" + }, + { + "begin": "(^[ \\t]+)?(?=//)", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.comment.leading.objcpp" + } + }, + "end": "(?!\\G)", + "patterns": [ + { + "begin": "//", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.objcpp" + } + }, + "end": "(?=\\n)", + "name": "comment.line.double-slash.objcpp", + "patterns": [ + { + "include": "#line_continuation_character" + } + ] + } + ] + } + ] + }, + "disabled": { + "begin": "^\\s*#\\s*if(n?def)?\\b.*$", + "end": "^\\s*#\\s*endif\\b", + "patterns": [ + { + "include": "#disabled" + }, + { + "include": "#pragma-mark" + } + ] + }, + "line_continuation_character": { + "patterns": [ + { + "match": "(\\\\)\\n", + "captures": { + "1": { + "name": "constant.character.escape.line-continuation.objcpp" + } + } + } + ] + }, + "parens-c": { + "name": "punctuation.section.parens-c\b.objcpp", + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.section.parens.begin.bracket.round.objcpp" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.parens.end.bracket.round.objcpp" + } + }, + "patterns": [ + { + "include": "$base" + } + ] + }, + "parens-block-c": { + "name": "meta.block.parens.objcpp", + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.section.parens.begin.bracket.round.objcpp" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.parens.end.bracket.round.objcpp" + } + }, + "patterns": [ + { + "include": "#block_innards-c" + }, + { + "match": "(?>=|\\|=", + "name": "keyword.operator.assignment.compound.bitwise.objcpp" + }, + { + "match": "<<|>>", + "name": "keyword.operator.bitwise.shift.objcpp" + }, + { + "match": "!=|<=|>=|==|<|>", + "name": "keyword.operator.comparison.objcpp" + }, + { + "match": "&&|!|\\|\\|", + "name": "keyword.operator.logical.objcpp" + }, + { + "match": "&|\\||\\^|~", + "name": "keyword.operator.objcpp" + }, + { + "match": "=", + "name": "keyword.operator.assignment.objcpp" + }, + { + "match": "%|\\*|/|-|\\+", + "name": "keyword.operator.objcpp" + }, + { + "begin": "\\?", + "beginCaptures": { + "0": { + "name": "keyword.operator.ternary.objcpp" + } + }, + "end": ":", + "applyEndPatternLast": true, + "endCaptures": { + "0": { + "name": "keyword.operator.ternary.objcpp" + } + }, + "patterns": [ + { + "include": "#access-method" + }, + { + "include": "#access-member" + }, + { + "include": "#c_function_call" + }, + { + "include": "$base" + } + ] + } + ] + }, + "strings-c": { + "patterns": [ + { + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.objcpp" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.objcpp" + } + }, + "name": "string.quoted.double.objcpp", + "patterns": [ + { + "include": "#string_escaped_char-c" + }, + { + "include": "#string_placeholder-c" + }, + { + "include": "#line_continuation_character" + } + ] + }, + { + "begin": "(?-mix:(?=+!]+|\\(\\)|\\[\\]))\\s*\\(\n)", + "end": "(?<=\\))(?!\\w)|(?=+!]+|\\(\\)|\\[\\]))\n)\n\\s*(\\()", + "beginCaptures": { + "1": { + "name": "entity.name.function.objcpp" + }, + "2": { + "name": "punctuation.section.arguments.begin.bracket.round.objcpp" + } + }, + "end": "(\\))|(?=+!]+|\\(\\)|\\[\\]))\n)\n\\s*(\\()", + "beginCaptures": { + "1": { + "name": "entity.name.function.objcpp" + }, + "2": { + "name": "punctuation.section.parameters.begin.bracket.round.objcpp" + } + }, + "end": "\\)|:", + "endCaptures": { + "0": { + "name": "punctuation.section.parameters.end.bracket.round.objcpp" + } + }, + "patterns": [ + { + "include": "#probably_a_parameter" + }, + { + "include": "#function-innards-c" + } + ] + }, + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.section.parens.begin.bracket.round.objcpp" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.parens.end.bracket.round.objcpp" + } + }, + "patterns": [ + { + "include": "#function-innards-c" + } + ] + }, + { + "include": "$base" + } + ] + }, + "function-call-innards-c": { + "patterns": [ + { + "include": "#comments-c" + }, + { + "include": "#storage_types_c" + }, + { + "include": "#access-method" + }, + { + "include": "#access-member" + }, + { + "include": "#operators" + }, + { + "begin": "(?x)\n(?!(?:while|for|do|if|else|switch|catch|return|typeid|alignof|alignas|sizeof|and|and_eq|bitand|bitor|compl|not|not_eq|or|or_eq|typeid|xor|xor_eq|alignof|alignas)\\s*\\()\n(\n(?:new)\\s*((?:(?:<(?:[\\s<>,\\w])*>\\s*))?) # actual name\n|\n(?:(?<=operator)(?:[-*&<>=+!]+|\\(\\)|\\[\\]))\n)\n\\s*(\\()", + "beginCaptures": { + "1": { + "name": "keyword.operator.memory.new.objcpp" + }, + "2": { + "patterns": [ + { + "include": "#template_call_innards" + } + ] + }, + "3": { + "name": "punctuation.section.arguments.begin.bracket.round.objcpp" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.arguments.end.bracket.round.objcpp" + } + }, + "patterns": [ + { + "include": "#function-call-innards-c" + } + ] + }, + { + "begin": "(?,\\w])*>\\s*))?::)*)\\s*([a-zA-Z_]\\w*)\\s*(?:((?:<(?:[\\s<>,\\w])*>\\s*)))?(\\()", + "beginCaptures": { + "1": { + "patterns": [ + { + "include": "#scope_resolution" + } + ] + }, + "2": { + "name": "entity.name.function.call.objcpp" + }, + "3": { + "patterns": [ + { + "include": "#template_call_innards" + } + ] + }, + "4": { + "name": "punctuation.section.arguments.begin.bracket.round.objcpp" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.arguments.end.bracket.round.objcpp" + } + }, + "patterns": [ + { + "include": "#function-call-innards-c" + } + ] + }, + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.section.parens.begin.bracket.round.objcpp" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.parens.end.bracket.round.objcpp" + } + }, + "patterns": [ + { + "include": "#function-call-innards-c" + } + ] + }, + { + "include": "#block_innards-c" + } + ] + } + } + }, + "string_escaped_char": { + "patterns": [ + { + "match": "(?x)\\\\ (\n\\\\\t\t\t |\n[abefnprtv'\"?] |\n[0-3]\\d{,2}\t |\n[4-7]\\d?\t\t|\nx[a-fA-F0-9]{,2} |\nu[a-fA-F0-9]{,4} |\nU[a-fA-F0-9]{,8} )", + "name": "constant.character.escape.objcpp" + }, + { + "match": "\\\\.", + "name": "invalid.illegal.unknown-escape.objcpp" + } + ] + }, + "string_placeholder": { + "patterns": [ + { + "match": "(?x) %\n(\\d+\\$)?\t\t\t\t\t\t # field (argument #)\n[#0\\- +']*\t\t\t\t\t\t # flags\n[,;:_]?\t\t\t\t\t\t\t # separator character (AltiVec)\n((-?\\d+)|\\*(-?\\d+\\$)?)?\t\t # minimum field width\n(\\.((-?\\d+)|\\*(-?\\d+\\$)?)?)?\t# precision\n(hh|h|ll|l|j|t|z|q|L|vh|vl|v|hv|hl)? # length modifier\n[diouxXDOUeEfFgGaACcSspn%]\t\t # conversion type", + "name": "constant.other.placeholder.objcpp" + }, + { + "match": "(%)(?!\"\\s*(PRI|SCN))", + "captures": { + "1": { + "name": "invalid.illegal.placeholder.objcpp" + } + } + } + ] + }, + "bracketed_content": { + "begin": "\\[", + "beginCaptures": { + "0": { + "name": "punctuation.section.scope.begin.objcpp" + } + }, + "end": "\\]", + "endCaptures": { + "0": { + "name": "punctuation.section.scope.end.objcpp" + } + }, + "name": "meta.bracketed.objcpp", + "patterns": [ + { + "begin": "(?=predicateWithFormat:)(?<=NSPredicate )(predicateWithFormat:)", + "beginCaptures": { + "1": { + "name": "support.function.any-method.objcpp" + }, + "2": { + "name": "punctuation.separator.arguments.objcpp" + } + }, + "end": "(?=\\])", + "name": "meta.function-call.predicate.objcpp", + "patterns": [ + { + "captures": { + "1": { + "name": "punctuation.separator.arguments.objcpp" + } + }, + "match": "\\bargument(Array|s)(:)", + "name": "support.function.any-method.name-of-parameter.objcpp" + }, + { + "captures": { + "1": { + "name": "punctuation.separator.arguments.objcpp" + } + }, + "match": "\\b\\w+(:)", + "name": "invalid.illegal.unknown-method.objcpp" + }, + { + "begin": "@\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.objcpp" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.objcpp" + } + }, + "name": "string.quoted.double.objcpp", + "patterns": [ + { + "match": "\\b(AND|OR|NOT|IN)\\b", + "name": "keyword.operator.logical.predicate.cocoa.objcpp" + }, + { + "match": "\\b(ALL|ANY|SOME|NONE)\\b", + "name": "constant.language.predicate.cocoa.objcpp" + }, + { + "match": "\\b(NULL|NIL|SELF|TRUE|YES|FALSE|NO|FIRST|LAST|SIZE)\\b", + "name": "constant.language.predicate.cocoa.objcpp" + }, + { + "match": "\\b(MATCHES|CONTAINS|BEGINSWITH|ENDSWITH|BETWEEN)\\b", + "name": "keyword.operator.comparison.predicate.cocoa.objcpp" + }, + { + "match": "\\bC(ASEINSENSITIVE|I)\\b", + "name": "keyword.other.modifier.predicate.cocoa.objcpp" + }, + { + "match": "\\b(ANYKEY|SUBQUERY|CAST|TRUEPREDICATE|FALSEPREDICATE)\\b", + "name": "keyword.other.predicate.cocoa.objcpp" + }, + { + "match": "\\\\(\\\\|[abefnrtv'\"?]|[0-3]\\d{,2}|[4-7]\\d?|x[a-zA-Z0-9]+)", + "name": "constant.character.escape.objcpp" + }, + { + "match": "\\\\.", + "name": "invalid.illegal.unknown-escape.objcpp" + } + ] + }, + { + "include": "#special_variables" + }, + { + "include": "#c_functions" + }, + { + "include": "$base" + } + ] + }, + { + "begin": "(?=\\w)(?<=[\\w\\])\"] )(\\w+(?:(:)|(?=\\])))", + "beginCaptures": { + "1": { + "name": "support.function.any-method.objcpp" + }, + "2": { + "name": "punctuation.separator.arguments.objcpp" + } + }, + "end": "(?=\\])", + "name": "meta.function-call.objcpp", + "patterns": [ + { + "captures": { + "1": { + "name": "punctuation.separator.arguments.objcpp" + } + }, + "match": "\\b\\w+(:)", + "name": "support.function.any-method.name-of-parameter.objcpp" + }, + { + "include": "#special_variables" + }, + { + "include": "#c_functions" + }, + { + "include": "$base" + } + ] + }, + { + "include": "#special_variables" + }, + { + "include": "#c_functions" + }, + { + "include": "$self" + } + ] + }, + "c_functions": { + "patterns": [ + { + "captures": { + "1": { + "name": "punctuation.whitespace.support.function.leading.objcpp" + }, + "2": { + "name": "support.function.C99.objcpp" + } + }, + "match": "(\\s*)\\b(hypot(f|l)?|s(scanf|ystem|nprintf|ca(nf|lb(n(f|l)?|ln(f|l)?))|i(n(h(f|l)?|f|l)?|gn(al|bit))|tr(s(tr|pn)|nc(py|at|mp)|c(spn|hr|oll|py|at|mp)|to(imax|d|u(l(l)?|max)|k|f|l(d|l)?)|error|pbrk|ftime|len|rchr|xfrm)|printf|et(jmp|vbuf|locale|buf)|qrt(f|l)?|w(scanf|printf)|rand)|n(e(arbyint(f|l)?|xt(toward(f|l)?|after(f|l)?))|an(f|l)?)|c(s(in(h(f|l)?|f|l)?|qrt(f|l)?)|cos(h(f)?|f|l)?|imag(f|l)?|t(ime|an(h(f|l)?|f|l)?)|o(s(h(f|l)?|f|l)?|nj(f|l)?|pysign(f|l)?)|p(ow(f|l)?|roj(f|l)?)|e(il(f|l)?|xp(f|l)?)|l(o(ck|g(f|l)?)|earerr)|a(sin(h(f|l)?|f|l)?|cos(h(f|l)?|f|l)?|tan(h(f|l)?|f|l)?|lloc|rg(f|l)?|bs(f|l)?)|real(f|l)?|brt(f|l)?)|t(ime|o(upper|lower)|an(h(f|l)?|f|l)?|runc(f|l)?|gamma(f|l)?|mp(nam|file))|i(s(space|n(ormal|an)|cntrl|inf|digit|u(nordered|pper)|p(unct|rint)|finite|w(space|c(ntrl|type)|digit|upper|p(unct|rint)|lower|al(num|pha)|graph|xdigit|blank)|l(ower|ess(equal|greater)?)|al(num|pha)|gr(eater(equal)?|aph)|xdigit|blank)|logb(f|l)?|max(div|abs))|di(v|fftime)|_Exit|unget(c|wc)|p(ow(f|l)?|ut(s|c(har)?|wc(har)?)|error|rintf)|e(rf(c(f|l)?|f|l)?|x(it|p(2(f|l)?|f|l|m1(f|l)?)?))|v(s(scanf|nprintf|canf|printf|w(scanf|printf))|printf|f(scanf|printf|w(scanf|printf))|w(scanf|printf)|a_(start|copy|end|arg))|qsort|f(s(canf|e(tpos|ek))|close|tell|open|dim(f|l)?|p(classify|ut(s|c|w(s|c))|rintf)|e(holdexcept|set(e(nv|xceptflag)|round)|clearexcept|testexcept|of|updateenv|r(aiseexcept|ror)|get(e(nv|xceptflag)|round))|flush|w(scanf|ide|printf|rite)|loor(f|l)?|abs(f|l)?|get(s|c|pos|w(s|c))|re(open|e|ad|xp(f|l)?)|m(in(f|l)?|od(f|l)?|a(f|l|x(f|l)?)?))|l(d(iv|exp(f|l)?)|o(ngjmp|cal(time|econv)|g(1(p(f|l)?|0(f|l)?)|2(f|l)?|f|l|b(f|l)?)?)|abs|l(div|abs|r(int(f|l)?|ound(f|l)?))|r(int(f|l)?|ound(f|l)?)|gamma(f|l)?)|w(scanf|c(s(s(tr|pn)|nc(py|at|mp)|c(spn|hr|oll|py|at|mp)|to(imax|d|u(l(l)?|max)|k|f|l(d|l)?|mbs)|pbrk|ftime|len|r(chr|tombs)|xfrm)|to(b|mb)|rtomb)|printf|mem(set|c(hr|py|mp)|move))|a(s(sert|ctime|in(h(f|l)?|f|l)?)|cos(h(f|l)?|f|l)?|t(o(i|f|l(l)?)|exit|an(h(f|l)?|2(f|l)?|f|l)?)|b(s|ort))|g(et(s|c(har)?|env|wc(har)?)|mtime)|r(int(f|l)?|ound(f|l)?|e(name|alloc|wind|m(ove|quo(f|l)?|ainder(f|l)?))|a(nd|ise))|b(search|towc)|m(odf(f|l)?|em(set|c(hr|py|mp)|move)|ktime|alloc|b(s(init|towcs|rtowcs)|towc|len|r(towc|len))))\\b" + }, + { + "captures": { + "1": { + "name": "punctuation.whitespace.function-call.leading.objcpp" + }, + "2": { + "name": "support.function.any-method.objcpp" + }, + "3": { + "name": "punctuation.definition.parameters.objcpp" + } + }, + "match": "(?x) (?: (?= \\s ) (?:(?<=else|new|return) | (?\\\\\\s*\\n)", + "name": "punctuation.separator.continuation.objcpp" + } + ] + } + ] + } + ] + }, + "disabled": { + "begin": "^\\s*#\\s*if(n?def)?\\b.*$", + "comment": "eat nested preprocessor if(def)s", + "end": "^\\s*#\\s*endif\\b.*$", + "patterns": [ + { + "include": "#disabled" + }, + { + "include": "#pragma-mark" + } + ] + }, + "implementation_innards": { + "patterns": [ + { + "include": "#preprocessor-rule-enabled-implementation" + }, + { + "include": "#preprocessor-rule-disabled-implementation" + }, + { + "include": "#preprocessor-rule-other-implementation" + }, + { + "include": "#property_directive" + }, + { + "include": "#special_variables" + }, + { + "include": "#method_super" + }, + { + "include": "$base" + } + ] + }, + "interface_innards": { + "patterns": [ + { + "include": "#preprocessor-rule-enabled-interface" + }, + { + "include": "#preprocessor-rule-disabled-interface" + }, + { + "include": "#preprocessor-rule-other-interface" + }, + { + "include": "#properties" + }, + { + "include": "#protocol_list" + }, + { + "include": "#method" + }, + { + "include": "$base" + } + ] + }, + "method": { + "begin": "^(-|\\+)\\s*", + "end": "(?=\\{|#)|;", + "name": "meta.function.objcpp", + "patterns": [ + { + "begin": "(\\()", + "beginCaptures": { + "1": { + "name": "punctuation.definition.type.begin.objcpp" + } + }, + "end": "(\\))\\s*(\\w+\\b)", + "endCaptures": { + "1": { + "name": "punctuation.definition.type.end.objcpp" + }, + "2": { + "name": "entity.name.function.objcpp" + } + }, + "name": "meta.return-type.objcpp", + "patterns": [ + { + "include": "#protocol_list" + }, + { + "include": "#protocol_type_qualifier" + }, + { + "include": "$base" + } + ] + }, + { + "match": "\\b\\w+(?=:)", + "name": "entity.name.function.name-of-parameter.objcpp" + }, + { + "begin": "((:))\\s*(\\()", + "beginCaptures": { + "1": { + "name": "entity.name.function.name-of-parameter.objcpp" + }, + "2": { + "name": "punctuation.separator.arguments.objcpp" + }, + "3": { + "name": "punctuation.definition.type.begin.objcpp" + } + }, + "end": "(\\))\\s*(\\w+\\b)?", + "endCaptures": { + "1": { + "name": "punctuation.definition.type.end.objcpp" + }, + "2": { + "name": "variable.parameter.function.objcpp" + } + }, + "name": "meta.argument-type.objcpp", + "patterns": [ + { + "include": "#protocol_list" + }, + { + "include": "#protocol_type_qualifier" + }, + { + "include": "$base" + } + ] + }, + { + "include": "#comment" + } + ] + }, + "method_super": { + "begin": "^(?=-|\\+)", + "end": "(?<=\\})|(?=#)", + "name": "meta.function-with-body.objcpp", + "patterns": [ + { + "include": "#method" + }, + { + "include": "$base" + } + ] + }, + "pragma-mark": { + "captures": { + "1": { + "name": "meta.preprocessor.objcpp" + }, + "2": { + "name": "keyword.control.import.pragma.objcpp" + }, + "3": { + "name": "meta.toc-list.pragma-mark.objcpp" + } + }, + "match": "^\\s*(#\\s*(pragma\\s+mark)\\s+(.*))", + "name": "meta.section.objcpp" + }, + "preprocessor-rule-disabled-implementation": { + "begin": "^\\s*(#(if)\\s+(0)\\b).*", + "captures": { + "1": { + "name": "meta.preprocessor.objcpp" + }, + "2": { + "name": "keyword.control.import.if.objcpp" + }, + "3": { + "name": "constant.numeric.preprocessor.objcpp" + } + }, + "end": "^\\s*(#\\s*(endif)\\b.*?(?:(?=(?://|/\\*))|$))", + "patterns": [ + { + "begin": "^\\s*(#\\s*(else)\\b)", + "captures": { + "1": { + "name": "meta.preprocessor.objcpp" + }, + "2": { + "name": "keyword.control.import.else.objcpp" + } + }, + "end": "(?=^\\s*#\\s*endif\\b.*?(?:(?=(?://|/\\*))|$))", + "patterns": [ + { + "include": "#interface_innards" + } + ] + }, + { + "begin": "", + "end": "(?=^\\s*#\\s*(else|endif)\\b.*?(?:(?=(?://|/\\*))|$))", + "name": "comment.block.preprocessor.if-branch.objcpp", + "patterns": [ + { + "include": "#disabled" + }, + { + "include": "#pragma-mark" + } + ] + } + ] + }, + "preprocessor-rule-disabled-interface": { + "begin": "^\\s*(#(if)\\s+(0)\\b).*", + "captures": { + "1": { + "name": "meta.preprocessor.objcpp" + }, + "2": { + "name": "keyword.control.import.if.objcpp" + }, + "3": { + "name": "constant.numeric.preprocessor.objcpp" + } + }, + "end": "^\\s*(#\\s*(endif)\\b.*?(?:(?=(?://|/\\*))|$))", + "patterns": [ + { + "begin": "^\\s*(#\\s*(else)\\b)", + "captures": { + "1": { + "name": "meta.preprocessor.objcpp" + }, + "2": { + "name": "keyword.control.import.else.objcpp" + } + }, + "end": "(?=^\\s*#\\s*endif\\b.*?(?:(?=(?://|/\\*))|$))", + "patterns": [ + { + "include": "#interface_innards" + } + ] + }, + { + "begin": "", + "end": "(?=^\\s*#\\s*(else|endif)\\b.*?(?:(?=(?://|/\\*))|$))", + "name": "comment.block.preprocessor.if-branch.objcpp", + "patterns": [ + { + "include": "#disabled" + }, + { + "include": "#pragma-mark" + } + ] + } + ] + }, + "preprocessor-rule-enabled-implementation": { + "begin": "^\\s*(#(if)\\s+(0*1)\\b)", + "captures": { + "1": { + "name": "meta.preprocessor.objcpp" + }, + "2": { + "name": "keyword.control.import.if.objcpp" + }, + "3": { + "name": "constant.numeric.preprocessor.objcpp" + } + }, + "end": "^\\s*(#\\s*(endif)\\b.*?(?:(?=(?://|/\\*))|$))", + "patterns": [ + { + "begin": "^\\s*(#\\s*(else)\\b).*", + "captures": { + "1": { + "name": "meta.preprocessor.objcpp" + }, + "2": { + "name": "keyword.control.import.else.objcpp" + } + }, + "contentName": "comment.block.preprocessor.else-branch.objcpp", + "end": "(?=^\\s*#\\s*endif\\b.*?(?:(?=(?://|/\\*))|$))", + "patterns": [ + { + "include": "#disabled" + }, + { + "include": "#pragma-mark" + } + ] + }, + { + "begin": "", + "end": "(?=^\\s*#\\s*(else|endif)\\b.*?(?:(?=(?://|/\\*))|$))", + "patterns": [ + { + "include": "#implementation_innards" + } + ] + } + ] + }, + "preprocessor-rule-enabled-interface": { + "begin": "^\\s*(#(if)\\s+(0*1)\\b)", + "captures": { + "1": { + "name": "meta.preprocessor.objcpp" + }, + "2": { + "name": "keyword.control.import.if.objcpp" + }, + "3": { + "name": "constant.numeric.preprocessor.objcpp" + } + }, + "end": "^\\s*(#\\s*(endif)\\b.*?(?:(?=(?://|/\\*))|$))", + "patterns": [ + { + "begin": "^\\s*(#\\s*(else)\\b).*", + "captures": { + "1": { + "name": "meta.preprocessor.objcpp" + }, + "2": { + "name": "keyword.control.import.else.objcpp" + } + }, + "contentName": "comment.block.preprocessor.else-branch.objcpp", + "end": "(?=^\\s*#\\s*endif\\b.*?(?:(?=(?://|/\\*))|$))", + "patterns": [ + { + "include": "#disabled" + }, + { + "include": "#pragma-mark" + } + ] + }, + { + "begin": "", + "end": "(?=^\\s*#\\s*(else|endif)\\b.*?(?:(?=(?://|/\\*))|$))", + "patterns": [ + { + "include": "#interface_innards" + } + ] + } + ] + }, + "preprocessor-rule-other-implementation": { + "begin": "^\\s*(#\\s*(if(n?def)?)\\b.*?(?:(?=(?://|/\\*))|$))", + "captures": { + "1": { + "name": "meta.preprocessor.objcpp" + }, + "2": { + "name": "keyword.control.import.objcpp" + } + }, + "end": "^\\s*(#\\s*(endif)\\b).*?(?:(?=(?://|/\\*))|$)", + "patterns": [ + { + "include": "#implementation_innards" + } + ] + }, + "preprocessor-rule-other-interface": { + "begin": "^\\s*(#\\s*(if(n?def)?)\\b.*?(?:(?=(?://|/\\*))|$))", + "captures": { + "1": { + "name": "meta.preprocessor.objcpp" + }, + "2": { + "name": "keyword.control.import.objcpp" + } + }, + "end": "^\\s*(#\\s*(endif)\\b).*?(?:(?=(?://|/\\*))|$)", + "patterns": [ + { + "include": "#interface_innards" + } + ] + }, + "properties": { + "patterns": [ + { + "begin": "((@)property)\\s*(\\()", + "beginCaptures": { + "1": { + "name": "keyword.other.property.objcpp" + }, + "2": { + "name": "punctuation.definition.keyword.objcpp" + }, + "3": { + "name": "punctuation.section.scope.begin.objcpp" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.scope.end.objcpp" + } + }, + "name": "meta.property-with-attributes.objcpp", + "patterns": [ + { + "match": "\\b(getter|setter|readonly|readwrite|assign|retain|copy|nonatomic|strong|weak)\\b", + "name": "keyword.other.property.attribute.objcpp" + } + ] + }, + { + "captures": { + "1": { + "name": "keyword.other.property.objcpp" + }, + "2": { + "name": "punctuation.definition.keyword.objcpp" + } + }, + "match": "((@)property)\\b", + "name": "meta.property.objcpp" + } + ] + }, + "property_directive": { + "captures": { + "1": { + "name": "punctuation.definition.keyword.objcpp" + } + }, + "match": "(@)(dynamic|synthesize)\\b", + "name": "keyword.other.property.directive.objcpp" + }, + "protocol_list": { + "begin": "(<)", + "beginCaptures": { + "1": { + "name": "punctuation.section.scope.begin.objcpp" + } + }, + "end": "(>)", + "endCaptures": { + "1": { + "name": "punctuation.section.scope.end.objcpp" + } + }, + "name": "meta.protocol-list.objcpp", + "patterns": [ + { + "match": "\\bNS(GlyphStorage|M(utableCopying|enuItem)|C(hangeSpelling|o(ding|pying|lorPicking(Custom|Default)))|T(oolbarItemValidations|ext(Input|AttachmentCell))|I(nputServ(iceProvider|erMouseTracker)|gnoreMisspelledWords)|Obj(CTypeSerializationCallBack|ect)|D(ecimalNumberBehaviors|raggingInfo)|U(serInterfaceValidations|RL(HandleClient|DownloadDelegate|ProtocolClient|AuthenticationChallengeSender))|Validated(ToobarItem|UserInterfaceItem)|Locking)\\b", + "name": "support.other.protocol.objcpp" + } + ] + }, + "protocol_type_qualifier": { + "match": "\\b(in|out|inout|oneway|bycopy|byref)\\b", + "name": "storage.modifier.protocol.objcpp" + }, + "special_variables": { + "patterns": [ + { + "match": "\\b_cmd\\b", + "name": "variable.other.selector.objcpp" + }, + { + "match": "\\b(self|super)\\b", + "name": "variable.language.objcpp" + } + ] } - ] + } } \ No newline at end of file diff --git a/extensions/objective-c/syntaxes/objective-c.tmLanguage.json b/extensions/objective-c/syntaxes/objective-c.tmLanguage.json index b88ebab9e..e08731bb1 100644 --- a/extensions/objective-c/syntaxes/objective-c.tmLanguage.json +++ b/extensions/objective-c/syntaxes/objective-c.tmLanguage.json @@ -1,10 +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/jeff-hykin/cpp-textmate-grammar/blob/master//syntaxes/objc.tmLanguage.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/atom/language-objective-c/commit/0727e04544f3414c1c339cf15a39a05ea3938cb4", + "version": "https://github.com/jeff-hykin/cpp-textmate-grammar/commit/9c4f4b3291538d9f5144f02d3b6af877b84f2cb2", "name": "Objective-C", "scopeName": "source.objc", "patterns": [ @@ -83,14 +83,14 @@ "name": "string.quoted.double.objc", "patterns": [ { - "include": "source.c#string_escaped_char" + "include": "#string_escaped_char" }, { "match": "(?x)%\n\t\t\t\t\t\t(\\d+\\$)? # field (argument #)\n\t\t\t\t\t\t[#0\\- +']* # flags\n\t\t\t\t\t\t((-?\\d+)|\\*(-?\\d+\\$)?)? # minimum field width\n\t\t\t\t\t\t(\\.((-?\\d+)|\\*(-?\\d+\\$)?)?)? # precision\n\t\t\t\t\t\t[@] # conversion type\n\t\t\t\t\t", "name": "constant.other.placeholder.objc" }, { - "include": "source.c#string_placeholder" + "include": "#string_placeholder" } ] }, @@ -214,15 +214,15 @@ }, { "match": "\\bNSApp\\b", - "name": "support.variable.foundation" + "name": "support.variable.foundation.objc" }, { "captures": { "1": { - "name": "punctuation.whitespace.support.function.cocoa.leopard" + "name": "punctuation.whitespace.support.function.cocoa.leopard.objc" }, "2": { - "name": "support.function.cocoa.leopard" + "name": "support.function.cocoa.leopard.objc" } }, "match": "(\\s*)\\b(NS(Rect(ToCGRect|FromCGRect)|MakeCollectable|S(tringFromProtocol|ize(ToCGSize|FromCGSize))|Draw(NinePartImage|ThreePartImage)|P(oint(ToCGPoint|FromCGPoint)|rotocolFromString)|EventMaskFromType|Value))\\b" @@ -230,66 +230,2677 @@ { "captures": { "1": { - "name": "punctuation.whitespace.support.function.leading.cocoa" + "name": "punctuation.whitespace.support.function.leading.cocoa.objc" }, "2": { - "name": "support.function.cocoa" + "name": "support.function.cocoa.objc" } }, "match": "(\\s*)\\b(NS(R(ound(DownToMultipleOfPageSize|UpToMultipleOfPageSize)|un(CriticalAlertPanel(RelativeToWindow)?|InformationalAlertPanel(RelativeToWindow)?|AlertPanel(RelativeToWindow)?)|e(set(MapTable|HashTable)|c(ycleZone|t(Clip(List)?|F(ill(UsingOperation|List(UsingOperation|With(Grays|Colors(UsingOperation)?))?)?|romString))|ordAllocationEvent)|turnAddress|leaseAlertPanel|a(dPixel|l(MemoryAvailable|locateCollectable))|gisterServicesProvider)|angeFromString)|Get(SizeAndAlignment|CriticalAlertPanel|InformationalAlertPanel|UncaughtExceptionHandler|FileType(s)?|WindowServerMemory|AlertPanel)|M(i(n(X|Y)|d(X|Y))|ouseInRect|a(p(Remove|Get|Member|Insert(IfAbsent|KnownAbsent)?)|ke(R(ect|ange)|Size|Point)|x(Range|X|Y)))|B(itsPer(SampleFromDepth|PixelFromDepth)|e(stDepth|ep|gin(CriticalAlertSheet|InformationalAlertSheet|AlertSheet)))|S(ho(uldRetainWithZone|w(sServicesMenuItem|AnimationEffect))|tringFrom(R(ect|ange)|MapTable|S(ize|elector)|HashTable|Class|Point)|izeFromString|e(t(ShowsServicesMenuItem|ZoneName|UncaughtExceptionHandler|FocusRingStyle)|lectorFromString|archPathForDirectoriesInDomains)|wap(Big(ShortToHost|IntToHost|DoubleToHost|FloatToHost|Long(ToHost|LongToHost))|Short|Host(ShortTo(Big|Little)|IntTo(Big|Little)|DoubleTo(Big|Little)|FloatTo(Big|Little)|Long(To(Big|Little)|LongTo(Big|Little)))|Int|Double|Float|L(ittle(ShortToHost|IntToHost|DoubleToHost|FloatToHost|Long(ToHost|LongToHost))|ong(Long)?)))|H(ighlightRect|o(stByteOrder|meDirectory(ForUser)?)|eight|ash(Remove|Get|Insert(IfAbsent|KnownAbsent)?)|FSType(CodeFromFileType|OfFile))|N(umberOfColorComponents|ext(MapEnumeratorPair|HashEnumeratorItem))|C(o(n(tainsRect|vert(GlyphsToPackedGlyphs|Swapped(DoubleToHost|FloatToHost)|Host(DoubleToSwapped|FloatToSwapped)))|unt(MapTable|HashTable|Frames|Windows(ForContext)?)|py(M(emoryPages|apTableWithZone)|Bits|HashTableWithZone|Object)|lorSpaceFromDepth|mpare(MapTables|HashTables))|lassFromString|reate(MapTable(WithZone)?|HashTable(WithZone)?|Zone|File(namePboardType|ContentsPboardType)))|TemporaryDirectory|I(s(ControllerMarker|EmptyRect|FreedObject)|n(setRect|crementExtraRefCount|te(r(sect(sRect|ionR(ect|ange))|faceStyleForKey)|gralRect)))|Zone(Realloc|Malloc|Name|Calloc|Fr(omPointer|ee))|O(penStepRootDirectory|ffsetRect)|D(i(sableScreenUpdates|videRect)|ottedFrameRect|e(c(imal(Round|Multiply|S(tring|ubtract)|Normalize|Co(py|mpa(ct|re))|IsNotANumber|Divide|Power|Add)|rementExtraRefCountWasZero)|faultMallocZone|allocate(MemoryPages|Object))|raw(Gr(oove|ayBezel)|B(itmap|utton)|ColorTiledRects|TiledRects|DarkBezel|W(hiteBezel|indowBackground)|LightBezel))|U(serName|n(ionR(ect|ange)|registerServicesProvider)|pdateDynamicServices)|Java(Bundle(Setup|Cleanup)|Setup(VirtualMachine)?|Needs(ToLoadClasses|VirtualMachine)|ClassesF(orBundle|romPath)|ObjectNamedInPath|ProvidesClasses)|P(oint(InRect|FromString)|erformService|lanarFromDepth|ageSize)|E(n(d(MapTableEnumeration|HashTableEnumeration)|umerate(MapTable|HashTable)|ableScreenUpdates)|qual(R(ects|anges)|Sizes|Points)|raseRect|xtraRefCount)|F(ileTypeForHFSTypeCode|ullUserName|r(ee(MapTable|HashTable)|ame(Rect(WithWidth(UsingOperation)?)?|Address)))|Wi(ndowList(ForContext)?|dth)|Lo(cationInRange|g(v|PageSize)?)|A(ccessibility(R(oleDescription(ForUIElement)?|aiseBadArgumentException)|Unignored(Children(ForOnlyChild)?|Descendant|Ancestor)|PostNotification|ActionDescription)|pplication(Main|Load)|vailableWindowDepths|ll(MapTable(Values|Keys)|HashTableObjects|ocate(MemoryPages|Collectable|Object)))))\\b" }, { "match": "\\bNS(RuleEditor|G(arbageCollector|radient)|MapTable|HashTable|Co(ndition|llectionView(Item)?)|T(oolbarItemGroup|extInputClient|r(eeNode|ackingArea))|InvocationOperation|Operation(Queue)?|D(ictionaryController|ockTile)|P(ointer(Functions|Array)|athC(o(ntrol(Delegate)?|mponentCell)|ell(Delegate)?)|r(intPanelAccessorizing|edicateEditor(RowTemplate)?))|ViewController|FastEnumeration|Animat(ionContext|ablePropertyContainer))\\b", - "name": "support.class.cocoa.leopard" + "name": "support.class.cocoa.leopard.objc" }, { "match": "\\bNS(R(u(nLoop|ler(Marker|View))|e(sponder|cursiveLock|lativeSpecifier)|an(domSpecifier|geSpecifier))|G(etCommand|lyph(Generator|Storage|Info)|raphicsContext)|XML(Node|D(ocument|TD(Node)?)|Parser|Element)|M(iddleSpecifier|ov(ie(View)?|eCommand)|utable(S(tring|et)|C(haracterSet|opying)|IndexSet|D(ictionary|ata)|URLRequest|ParagraphStyle|A(ttributedString|rray))|e(ssagePort(NameServer)?|nu(Item(Cell)?|View)?|t(hodSignature|adata(Item|Query(ResultGroup|AttributeValueTuple)?)))|a(ch(BootstrapServer|Port)|trix))|B(itmapImageRep|ox|u(ndle|tton(Cell)?)|ezierPath|rowser(Cell)?)|S(hadow|c(anner|r(ipt(SuiteRegistry|C(o(ercionHandler|mmand(Description)?)|lassDescription)|ObjectSpecifier|ExecutionContext|WhoseTest)|oll(er|View)|een))|t(epper(Cell)?|atus(Bar|Item)|r(ing|eam))|imple(HorizontalTypesetter|CString)|o(cketPort(NameServer)?|und|rtDescriptor)|p(e(cifierTest|ech(Recognizer|Synthesizer)|ll(Server|Checker))|litView)|e(cureTextField(Cell)?|t(Command)?|archField(Cell)?|rializer|gmentedC(ontrol|ell))|lider(Cell)?|avePanel)|H(ost|TTP(Cookie(Storage)?|URLResponse)|elpManager)|N(ib(Con(nector|trolConnector)|OutletConnector)?|otification(Center|Queue)?|u(ll|mber(Formatter)?)|etService(Browser)?|ameSpecifier)|C(ha(ngeSpelling|racterSet)|o(n(stantString|nection|trol(ler)?|ditionLock)|d(ing|er)|unt(Command|edSet)|pying|lor(Space|P(ick(ing(Custom|Default)|er)|anel)|Well|List)?|m(p(oundPredicate|arisonPredicate)|boBox(Cell)?))|u(stomImageRep|rsor)|IImageRep|ell|l(ipView|o(seCommand|neCommand)|assDescription)|a(ched(ImageRep|URLResponse)|lendar(Date)?)|reateCommand)|T(hread|ypesetter|ime(Zone|r)|o(olbar(Item(Validations)?)?|kenField(Cell)?)|ext(Block|Storage|Container|Tab(le(Block)?)?|Input|View|Field(Cell)?|List|Attachment(Cell)?)?|a(sk|b(le(Header(Cell|View)|Column|View)|View(Item)?))|reeController)|I(n(dex(S(pecifier|et)|Path)|put(Manager|S(tream|erv(iceProvider|er(MouseTracker)?)))|vocation)|gnoreMisspelledWords|mage(Rep|Cell|View)?)|O(ut(putStream|lineView)|pen(GL(Context|Pixel(Buffer|Format)|View)|Panel)|bj(CTypeSerializationCallBack|ect(Controller)?))|D(i(st(antObject(Request)?|ributed(NotificationCenter|Lock))|ctionary|rectoryEnumerator)|ocument(Controller)?|e(serializer|cimalNumber(Behaviors|Handler)?|leteCommand)|at(e(Components|Picker(Cell)?|Formatter)?|a)|ra(wer|ggingInfo))|U(ser(InterfaceValidations|Defaults(Controller)?)|RL(Re(sponse|quest)|Handle(Client)?|C(onnection|ache|redential(Storage)?)|Download(Delegate)?|Prot(ocol(Client)?|ectionSpace)|AuthenticationChallenge(Sender)?)?|n(iqueIDSpecifier|doManager|archiver))|P(ipe|o(sitionalSpecifier|pUpButton(Cell)?|rt(Message|NameServer|Coder)?)|ICTImageRep|ersistentDocument|DFImageRep|a(steboard|nel|ragraphStyle|geLayout)|r(int(Info|er|Operation|Panel)|o(cessInfo|tocolChecker|perty(Specifier|ListSerialization)|gressIndicator|xy)|edicate))|E(numerator|vent|PSImageRep|rror|x(ception|istsCommand|pression))|V(iew(Animation)?|al(idated(ToobarItem|UserInterfaceItem)|ue(Transformer)?))|Keyed(Unarchiver|Archiver)|Qui(ckDrawView|tCommand)|F(ile(Manager|Handle|Wrapper)|o(nt(Manager|Descriptor|Panel)?|rm(Cell|atter)))|W(hoseSpecifier|indow(Controller)?|orkspace)|L(o(c(k(ing)?|ale)|gicalTest)|evelIndicator(Cell)?|ayoutManager)|A(ssertionHandler|nimation|ctionCell|ttributedString|utoreleasePool|TSTypesetter|ppl(ication|e(Script|Event(Manager|Descriptor)))|ffineTransform|lert|r(chiver|ray(Controller)?)))\\b", - "name": "support.class.cocoa" + "name": "support.class.cocoa.objc" }, { "match": "\\bNS(R(oundingMode|ule(Editor(RowType|NestingMode)|rOrientation)|e(questUserAttentionType|lativePosition))|G(lyphInscription|radientDrawingOptions)|XML(NodeKind|D(ocumentContentKind|TDNodeKind)|ParserError)|M(ultibyteGlyphPacking|apTableOptions)|B(itmapFormat|oxType|ezierPathElement|ackgroundStyle|rowserDropOperation)|S(tr(ing(CompareOptions|DrawingOptions|EncodingConversionOptions)|eam(Status|Event))|p(eechBoundary|litViewDividerStyle)|e(archPathD(irectory|omainMask)|gmentS(tyle|witchTracking))|liderType|aveOptions)|H(TTPCookieAcceptPolicy|ashTableOptions)|N(otification(SuspensionBehavior|Coalescing)|umberFormatter(RoundingMode|Behavior|Style|PadPosition)|etService(sError|Options))|C(haracterCollection|o(lor(RenderingIntent|SpaceModel|PanelMode)|mp(oundPredicateType|arisonPredicateModifier))|ellStateValue|al(culationError|endarUnit))|T(ypesetterControlCharacterAction|imeZoneNameStyle|e(stComparisonOperation|xt(Block(Dimension|V(erticalAlignment|alueType)|Layer)|TableLayoutAlgorithm|FieldBezelStyle))|ableView(SelectionHighlightStyle|ColumnAutoresizingStyle)|rackingAreaOptions)|I(n(sertionPosition|te(rfaceStyle|ger))|mage(RepLoadStatus|Scaling|CacheMode|FrameStyle|LoadStatus|Alignment))|Ope(nGLPixelFormatAttribute|rationQueuePriority)|Date(Picker(Mode|Style)|Formatter(Behavior|Style))|U(RL(RequestCachePolicy|HandleStatus|C(acheStoragePolicy|redentialPersistence))|Integer)|P(o(stingStyle|int(ingDeviceType|erFunctionsOptions)|pUpArrowPosition)|athStyle|r(int(ing(Orientation|PaginationMode)|erTableStatus|PanelOptions)|opertyList(MutabilityOptions|Format)|edicateOperatorType))|ExpressionType|KeyValue(SetMutationKind|Change)|QTMovieLoopMode|F(indPanel(SubstringMatchType|Action)|o(nt(RenderingMode|FamilyClass)|cusRingPlacement))|W(hoseSubelementIdentifier|ind(ingRule|ow(B(utton|ackingLocation)|SharingType|CollectionBehavior)))|L(ine(MovementDirection|SweepDirection|CapStyle|JoinStyle)|evelIndicatorStyle)|Animation(BlockingMode|Curve))\\b", - "name": "support.type.cocoa.leopard" + "name": "support.type.cocoa.leopard.objc" }, { "match": "\\bC(I(Sampler|Co(ntext|lor)|Image(Accumulator)?|PlugIn(Registration)?|Vector|Kernel|Filter(Generator|Shape)?)|A(Renderer|MediaTiming(Function)?|BasicAnimation|ScrollLayer|Constraint(LayoutManager)?|T(iledLayer|extLayer|rans(ition|action))|OpenGLLayer|PropertyAnimation|KeyframeAnimation|Layer|A(nimation(Group)?|ction)))\\b", - "name": "support.class.quartz" + "name": "support.class.quartz.objc" }, { "match": "\\bC(G(Float|Point|Size|Rect)|IFormat|AConstraintAttribute)\\b", - "name": "support.type.quartz" + "name": "support.type.quartz.objc" }, { "match": "\\bNS(R(ect(Edge)?|ange)|G(lyph(Relation|LayoutMode)?|radientType)|M(odalSession|a(trixMode|p(Table|Enumerator)))|B(itmapImageFileType|orderType|uttonType|ezelStyle|ackingStoreType|rowserColumnResizingType)|S(cr(oll(er(Part|Arrow)|ArrowPosition)|eenAuxiliaryOpaque)|tringEncoding|ize|ocketNativeHandle|election(Granularity|Direction|Affinity)|wapped(Double|Float)|aveOperationType)|Ha(sh(Table|Enumerator)|ndler(2)?)|C(o(ntrol(Size|Tint)|mp(ositingOperation|arisonResult))|ell(State|Type|ImagePosition|Attribute))|T(hreadPrivate|ypesetterGlyphInfo|i(ckMarkPosition|tlePosition|meInterval)|o(ol(TipTag|bar(SizeMode|DisplayMode))|kenStyle)|IFFCompression|ext(TabType|Alignment)|ab(State|leViewDropOperation|ViewType)|rackingRectTag)|ImageInterpolation|Zone|OpenGL(ContextAuxiliary|PixelFormatAuxiliary)|D(ocumentChangeType|atePickerElementFlags|ra(werState|gOperation))|UsableScrollerParts|P(oint|r(intingPageOrder|ogressIndicator(Style|Th(ickness|readInfo))))|EventType|KeyValueObservingOptions|Fo(nt(SymbolicTraits|TraitMask|Action)|cusRingType)|W(indow(OrderingMode|Depth)|orkspace(IconCreationOptions|LaunchOptions)|ritingDirection)|L(ineBreakMode|ayout(Status|Direction))|A(nimation(Progress|Effect)|ppl(ication(TerminateReply|DelegateReply|PrintReply)|eEventManagerSuspensionID)|ffineTransformStruct|lertStyle))\\b", - "name": "support.type.cocoa" + "name": "support.type.cocoa.objc" }, { "match": "\\bNS(NotFound|Ordered(Ascending|Descending|Same))\\b", - "name": "support.constant.cocoa" + "name": "support.constant.cocoa.objc" }, { "match": "\\bNS(MenuDidBeginTracking|ViewDidUpdateTrackingAreas)?Notification\\b", - "name": "support.constant.notification.cocoa.leopard" + "name": "support.constant.notification.cocoa.leopard.objc" }, { "match": "\\bNS(Menu(Did(RemoveItem|SendAction|ChangeItem|EndTracking|AddItem)|WillSendAction)|S(ystemColorsDidChange|plitView(DidResizeSubviews|WillResizeSubviews))|C(o(nt(extHelpModeDid(Deactivate|Activate)|rolT(intDidChange|extDid(BeginEditing|Change|EndEditing)))|lor(PanelColorDidChange|ListDidChange)|mboBox(Selection(IsChanging|DidChange)|Will(Dismiss|PopUp)))|lassDescriptionNeededForClass)|T(oolbar(DidRemoveItem|WillAddItem)|ext(Storage(DidProcessEditing|WillProcessEditing)|Did(BeginEditing|Change|EndEditing)|View(DidChange(Selection|TypingAttributes)|WillChangeNotifyingTextView))|ableView(Selection(IsChanging|DidChange)|ColumnDid(Resize|Move)))|ImageRepRegistryDidChange|OutlineView(Selection(IsChanging|DidChange)|ColumnDid(Resize|Move)|Item(Did(Collapse|Expand)|Will(Collapse|Expand)))|Drawer(Did(Close|Open)|Will(Close|Open))|PopUpButton(CellWillPopUp|WillPopUp)|View(GlobalFrameDidChange|BoundsDidChange|F(ocusDidChange|rameDidChange))|FontSetChanged|W(indow(Did(Resi(ze|gn(Main|Key))|M(iniaturize|ove)|Become(Main|Key)|ChangeScreen(|Profile)|Deminiaturize|Update|E(ndSheet|xpose))|Will(M(iniaturize|ove)|BeginSheet|Close))|orkspace(SessionDid(ResignActive|BecomeActive)|Did(Mount|TerminateApplication|Unmount|PerformFileOperation|Wake|LaunchApplication)|Will(Sleep|Unmount|PowerOff|LaunchApplication)))|A(ntialiasThresholdChanged|ppl(ication(Did(ResignActive|BecomeActive|Hide|ChangeScreenParameters|U(nhide|pdate)|FinishLaunching)|Will(ResignActive|BecomeActive|Hide|Terminate|U(nhide|pdate)|FinishLaunching))|eEventManagerWillProcessFirstEvent)))Notification\\b", - "name": "support.constant.notification.cocoa" + "name": "support.constant.notification.cocoa.objc" }, { "match": "\\bNS(RuleEditor(RowType(Simple|Compound)|NestingMode(Si(ngle|mple)|Compound|List))|GradientDraws(BeforeStartingLocation|AfterEndingLocation)|M(inusSetExpressionType|a(chPortDeallocate(ReceiveRight|SendRight|None)|pTable(StrongMemory|CopyIn|ZeroingWeakMemory|ObjectPointerPersonality)))|B(oxCustom|undleExecutableArchitecture(X86|I386|PPC(64)?)|etweenPredicateOperatorType|ackgroundStyle(Raised|Dark|L(ight|owered)))|S(tring(DrawingTruncatesLastVisibleLine|EncodingConversion(ExternalRepresentation|AllowLossy))|ubqueryExpressionType|p(e(ech(SentenceBoundary|ImmediateBoundary|WordBoundary)|llingState(GrammarFlag|SpellingFlag))|litViewDividerStyleThi(n|ck))|e(rvice(RequestTimedOutError|M(iscellaneousError|alformedServiceDictionaryError)|InvalidPasteboardDataError|ErrorM(inimum|aximum)|Application(NotFoundError|LaunchFailedError))|gmentStyle(Round(Rect|ed)|SmallSquare|Capsule|Textured(Rounded|Square)|Automatic)))|H(UDWindowMask|ashTable(StrongMemory|CopyIn|ZeroingWeakMemory|ObjectPointerPersonality))|N(oModeColorPanel|etServiceNoAutoRename)|C(hangeRedone|o(ntainsPredicateOperatorType|l(orRenderingIntent(RelativeColorimetric|Saturation|Default|Perceptual|AbsoluteColorimetric)|lectorDisabledOption))|ellHit(None|ContentArea|TrackableArea|EditableTextArea))|T(imeZoneNameStyle(S(hort(Standard|DaylightSaving)|tandard)|DaylightSaving)|extFieldDatePickerStyle|ableViewSelectionHighlightStyle(Regular|SourceList)|racking(Mouse(Moved|EnteredAndExited)|CursorUpdate|InVisibleRect|EnabledDuringMouseDrag|A(ssumeInside|ctive(In(KeyWindow|ActiveApp)|WhenFirstResponder|Always))))|I(n(tersectSetExpressionType|dexedColorSpaceModel)|mageScale(None|Proportionally(Down|UpOrDown)|AxesIndependently))|Ope(nGLPFAAllowOfflineRenderers|rationQueue(DefaultMaxConcurrentOperationCount|Priority(High|Normal|Very(High|Low)|Low)))|D(iacriticInsensitiveSearch|ownloadsDirectory)|U(nionSetExpressionType|TF(16(BigEndianStringEncoding|StringEncoding|LittleEndianStringEncoding)|32(BigEndianStringEncoding|StringEncoding|LittleEndianStringEncoding)))|P(ointerFunctions(Ma(chVirtualMemory|llocMemory)|Str(ongMemory|uctPersonality)|C(StringPersonality|opyIn)|IntegerPersonality|ZeroingWeakMemory|O(paque(Memory|Personality)|bjectP(ointerPersonality|ersonality)))|at(hStyle(Standard|NavigationBar|PopUp)|ternColorSpaceModel)|rintPanelShows(Scaling|Copies|Orientation|P(a(perSize|ge(Range|SetupAccessory))|review)))|Executable(RuntimeMismatchError|NotLoadableError|ErrorM(inimum|aximum)|L(inkError|oadError)|ArchitectureMismatchError)|KeyValueObservingOption(Initial|Prior)|F(i(ndPanelSubstringMatchType(StartsWith|Contains|EndsWith|FullWord)|leRead(TooLargeError|UnknownStringEncodingError))|orcedOrderingSearch)|Wi(ndow(BackingLocation(MainMemory|Default|VideoMemory)|Sharing(Read(Only|Write)|None)|CollectionBehavior(MoveToActiveSpace|CanJoinAllSpaces|Default))|dthInsensitiveSearch)|AggregateExpressionType)\\b", - "name": "support.constant.cocoa.leopard" + "name": "support.constant.cocoa.leopard.objc" }, { "match": "\\bNS(R(GB(ModeColorPanel|ColorSpaceModel)|ight(Mouse(D(own(Mask)?|ragged(Mask)?)|Up(Mask)?)|T(ext(Movement|Alignment)|ab(sBezelBorder|StopType))|ArrowFunctionKey)|ound(RectBezelStyle|Bankers|ed(BezelStyle|TokenStyle|DisclosureBezelStyle)|Down|Up|Plain|Line(CapStyle|JoinStyle))|un(StoppedResponse|ContinuesResponse|AbortedResponse)|e(s(izableWindowMask|et(CursorRectsRunLoopOrdering|FunctionKey))|ce(ssedBezelStyle|iver(sCantHandleCommandScriptError|EvaluationScriptError))|turnTextMovement|doFunctionKey|quiredArgumentsMissingScriptError|l(evancyLevelIndicatorStyle|ative(Before|After))|gular(SquareBezelStyle|ControlSize)|moveTraitFontAction)|a(n(domSubelement|geDateMode)|tingLevelIndicatorStyle|dio(ModeMatrix|Button)))|G(IFFileType|lyph(Below|Inscribe(B(elow|ase)|Over(strike|Below)|Above)|Layout(WithPrevious|A(tAPoint|gainstAPoint))|A(ttribute(BidiLevel|Soft|Inscribe|Elastic)|bove))|r(ooveBorder|eaterThan(Comparison|OrEqualTo(Comparison|PredicateOperatorType)|PredicateOperatorType)|a(y(ModeColorPanel|ColorSpaceModel)|dient(None|Con(cave(Strong|Weak)|vex(Strong|Weak)))|phiteControlTint)))|XML(N(o(tationDeclarationKind|de(CompactEmptyElement|IsCDATA|OptionsNone|Use(SingleQuotes|DoubleQuotes)|Pre(serve(NamespaceOrder|C(haracterReferences|DATA)|DTD|Prefixes|E(ntities|mptyElements)|Quotes|Whitespace|A(ttributeOrder|ll))|ttyPrint)|ExpandEmptyElement))|amespaceKind)|CommentKind|TextKind|InvalidKind|D(ocument(X(MLKind|HTMLKind|Include)|HTMLKind|T(idy(XML|HTML)|extKind)|IncludeContentTypeDeclaration|Validate|Kind)|TDKind)|P(arser(GTRequiredError|XMLDeclNot(StartedError|FinishedError)|Mi(splaced(XMLDeclarationError|CDATAEndStringError)|xedContentDeclNot(StartedError|FinishedError))|S(t(andaloneValueError|ringNot(StartedError|ClosedError))|paceRequiredError|eparatorRequiredError)|N(MTOKENRequiredError|o(t(ationNot(StartedError|FinishedError)|WellBalancedError)|DTDError)|amespaceDeclarationError|AMERequiredError)|C(haracterRef(In(DTDError|PrologError|EpilogError)|AtEOFError)|o(nditionalSectionNot(StartedError|FinishedError)|mment(NotFinishedError|ContainsDoubleHyphenError))|DATANotFinishedError)|TagNameMismatchError|In(ternalError|valid(HexCharacterRefError|C(haracter(RefError|InEntityError|Error)|onditionalSectionError)|DecimalCharacterRefError|URIError|Encoding(NameError|Error)))|OutOfMemoryError|D(ocumentStartError|elegateAbortedParseError|OCTYPEDeclNotFinishedError)|U(RI(RequiredError|FragmentError)|n(declaredEntityError|parsedEntityError|knownEncodingError|finishedTagError))|P(CDATARequiredError|ublicIdentifierRequiredError|arsedEntityRef(MissingSemiError|NoNameError|In(Internal(SubsetError|Error)|PrologError|EpilogError)|AtEOFError)|r(ocessingInstructionNot(StartedError|FinishedError)|ematureDocumentEndError))|E(n(codingNotSupportedError|tity(Ref(In(DTDError|PrologError|EpilogError)|erence(MissingSemiError|WithoutNameError)|LoopError|AtEOFError)|BoundaryError|Not(StartedError|FinishedError)|Is(ParameterError|ExternalError)|ValueRequiredError))|qualExpectedError|lementContentDeclNot(StartedError|FinishedError)|xt(ernalS(tandaloneEntityError|ubsetNotFinishedError)|raContentError)|mptyDocumentError)|L(iteralNot(StartedError|FinishedError)|T(RequiredError|SlashRequiredError)|essThanSymbolInAttributeError)|Attribute(RedefinedError|HasNoValueError|Not(StartedError|FinishedError)|ListNot(StartedError|FinishedError)))|rocessingInstructionKind)|E(ntity(GeneralKind|DeclarationKind|UnparsedKind|P(ar(sedKind|ameterKind)|redefined))|lement(Declaration(MixedKind|UndefinedKind|E(lementKind|mptyKind)|Kind|AnyKind)|Kind))|Attribute(N(MToken(sKind|Kind)|otationKind)|CDATAKind|ID(Ref(sKind|Kind)|Kind)|DeclarationKind|En(tit(yKind|iesKind)|umerationKind)|Kind))|M(i(n(XEdge|iaturizableWindowMask|YEdge|uteCalendarUnit)|terLineJoinStyle|ddleSubelement|xedState)|o(nthCalendarUnit|deSwitchFunctionKey|use(Moved(Mask)?|E(ntered(Mask)?|ventSubtype|xited(Mask)?))|veToBezierPathElement|mentary(ChangeButton|Push(Button|InButton)|Light(Button)?))|enuFunctionKey|a(c(intoshInterfaceStyle|OSRomanStringEncoding)|tchesPredicateOperatorType|ppedRead|x(XEdge|YEdge))|ACHOperatingSystem)|B(MPFileType|o(ttomTabsBezelBorder|ldFontMask|rderlessWindowMask|x(Se(condary|parator)|OldStyle|Primary))|uttLineCapStyle|e(zelBorder|velLineJoinStyle|low(Bottom|Top)|gin(sWith(Comparison|PredicateOperatorType)|FunctionKey))|lueControlTint|ack(spaceCharacter|tabTextMovement|ingStore(Retained|Buffered|Nonretained)|TabCharacter|wardsSearch|groundTab)|r(owser(NoColumnResizing|UserColumnResizing|AutoColumnResizing)|eakFunctionKey))|S(h(ift(JISStringEncoding|KeyMask)|ow(ControlGlyphs|InvisibleGlyphs)|adowlessSquareBezelStyle)|y(s(ReqFunctionKey|tem(D(omainMask|efined(Mask)?)|FunctionKey))|mbolStringEncoding)|c(a(nnedOption|le(None|ToFit|Proportionally))|r(oll(er(NoPart|Increment(Page|Line|Arrow)|Decrement(Page|Line|Arrow)|Knob(Slot)?|Arrows(M(inEnd|axEnd)|None|DefaultSetting))|Wheel(Mask)?|LockFunctionKey)|eenChangedEventType))|t(opFunctionKey|r(ingDrawing(OneShot|DisableScreenFontSubstitution|Uses(DeviceMetrics|FontLeading|LineFragmentOrigin))|eam(Status(Reading|NotOpen|Closed|Open(ing)?|Error|Writing|AtEnd)|Event(Has(BytesAvailable|SpaceAvailable)|None|OpenCompleted|E(ndEncountered|rrorOccurred)))))|i(ngle(DateMode|UnderlineStyle)|ze(DownFontAction|UpFontAction))|olarisOperatingSystem|unOSOperatingSystem|pecialPageOrder|e(condCalendarUnit|lect(By(Character|Paragraph|Word)|i(ng(Next|Previous)|onAffinity(Downstream|Upstream))|edTab|FunctionKey)|gmentSwitchTracking(Momentary|Select(One|Any)))|quareLineCapStyle|witchButton|ave(ToOperation|Op(tions(Yes|No|Ask)|eration)|AsOperation)|mall(SquareBezelStyle|C(ontrolSize|apsFontMask)|IconButtonBezelStyle))|H(ighlightModeMatrix|SBModeColorPanel|o(ur(Minute(SecondDatePickerElementFlag|DatePickerElementFlag)|CalendarUnit)|rizontalRuler|meFunctionKey)|TTPCookieAcceptPolicy(Never|OnlyFromMainDocumentDomain|Always)|e(lp(ButtonBezelStyle|KeyMask|FunctionKey)|avierFontAction)|PUXOperatingSystem)|Year(MonthDa(yDatePickerElementFlag|tePickerElementFlag)|CalendarUnit)|N(o(n(StandardCharacterSetFontMask|ZeroWindingRule|activatingPanelMask|LossyASCIIStringEncoding)|Border|t(ification(SuspensionBehavior(Hold|Coalesce|D(eliverImmediately|rop))|NoCoalescing|CoalescingOn(Sender|Name)|DeliverImmediately|PostToAllSessions)|PredicateType|EqualToPredicateOperatorType)|S(cr(iptError|ollerParts)|ubelement|pecifierError)|CellMask|T(itle|opLevelContainersSpecifierError|abs(BezelBorder|NoBorder|LineBorder))|I(nterfaceStyle|mage)|UnderlineStyle|FontChangeAction)|u(ll(Glyph|CellType)|m(eric(Search|PadKeyMask)|berFormatter(Round(Half(Down|Up|Even)|Ceiling|Down|Up|Floor)|Behavior(10|Default)|S(cientificStyle|pellOutStyle)|NoStyle|CurrencyStyle|DecimalStyle|P(ercentStyle|ad(Before(Suffix|Prefix)|After(Suffix|Prefix))))))|e(t(Services(BadArgumentError|NotFoundError|C(ollisionError|ancelledError)|TimeoutError|InvalidError|UnknownError|ActivityInProgress)|workDomainMask)|wlineCharacter|xt(StepInterfaceStyle|FunctionKey))|EXTSTEPStringEncoding|a(t(iveShortGlyphPacking|uralTextAlignment)|rrowFontMask))|C(hange(ReadOtherContents|GrayCell(Mask)?|BackgroundCell(Mask)?|Cleared|Done|Undone|Autosaved)|MYK(ModeColorPanel|ColorSpaceModel)|ircular(BezelStyle|Slider)|o(n(stantValueExpressionType|t(inuousCapacityLevelIndicatorStyle|entsCellMask|ain(sComparison|erSpecifierError)|rol(Glyph|KeyMask))|densedFontMask)|lor(Panel(RGBModeMask|GrayModeMask|HSBModeMask|C(MYKModeMask|olorListModeMask|ustomPaletteModeMask|rayonModeMask)|WheelModeMask|AllModesMask)|ListModeColorPanel)|reServiceDirectory|m(p(osite(XOR|Source(In|O(ut|ver)|Atop)|Highlight|C(opy|lear)|Destination(In|O(ut|ver)|Atop)|Plus(Darker|Lighter))|ressedFontMask)|mandKeyMask))|u(stom(SelectorPredicateOperatorType|PaletteModeColorPanel)|r(sor(Update(Mask)?|PointingDevice)|veToBezierPathElement))|e(nterT(extAlignment|abStopType)|ll(State|H(ighlighted|as(Image(Horizontal|OnLeftOrBottom)|OverlappingImage))|ChangesContents|Is(Bordered|InsetButton)|Disabled|Editable|LightsBy(Gray|Background|Contents)|AllowsMixedState))|l(ipPagination|o(s(ePathBezierPathElement|ableWindowMask)|ckAndCalendarDatePickerStyle)|ear(ControlTint|DisplayFunctionKey|LineFunctionKey))|a(seInsensitive(Search|PredicateOption)|n(notCreateScriptCommandError|cel(Button|TextMovement))|chesDirectory|lculation(NoError|Overflow|DivideByZero|Underflow|LossOfPrecision)|rriageReturnCharacter)|r(itical(Request|AlertStyle)|ayonModeColorPanel))|T(hick(SquareBezelStyle|erSquareBezelStyle)|ypesetter(Behavior|HorizontalTabAction|ContainerBreakAction|ZeroAdvancementAction|OriginalBehavior|ParagraphBreakAction|WhitespaceAction|L(ineBreakAction|atestBehavior))|i(ckMark(Right|Below|Left|Above)|tledWindowMask|meZoneDatePickerElementFlag)|o(olbarItemVisibilityPriority(Standard|High|User|Low)|pTabsBezelBorder|ggleButton)|IFF(Compression(N(one|EXT)|CCITTFAX(3|4)|OldJPEG|JPEG|PackBits|LZW)|FileType)|e(rminate(Now|Cancel|Later)|xt(Read(InapplicableDocumentTypeError|WriteErrorM(inimum|aximum))|Block(M(i(nimum(Height|Width)|ddleAlignment)|a(rgin|ximum(Height|Width)))|B(o(ttomAlignment|rder)|aselineAlignment)|Height|TopAlignment|P(ercentageValueType|adding)|Width|AbsoluteValueType)|StorageEdited(Characters|Attributes)|CellType|ured(RoundedBezelStyle|BackgroundWindowMask|SquareBezelStyle)|Table(FixedLayoutAlgorithm|AutomaticLayoutAlgorithm)|Field(RoundedBezel|SquareBezel|AndStepperDatePickerStyle)|WriteInapplicableDocumentTypeError|ListPrependEnclosingMarker))|woByteGlyphPacking|ab(Character|TextMovement|le(tP(oint(Mask|EventSubtype)?|roximity(Mask|EventSubtype)?)|Column(NoResizing|UserResizingMask|AutoresizingMask)|View(ReverseSequentialColumnAutoresizingStyle|GridNone|S(olid(HorizontalGridLineMask|VerticalGridLineMask)|equentialColumnAutoresizingStyle)|NoColumnAutoresizing|UniformColumnAutoresizingStyle|FirstColumnOnlyAutoresizingStyle|LastColumnOnlyAutoresizingStyle)))|rackModeMatrix)|I(n(sert(CharFunctionKey|FunctionKey|LineFunctionKey)|t(Type|ernalS(criptError|pecifierError))|dexSubelement|validIndexSpecifierError|formational(Request|AlertStyle)|PredicateOperatorType)|talicFontMask|SO(2022JPStringEncoding|Latin(1StringEncoding|2StringEncoding))|dentityMappingCharacterCollection|llegalTextMovement|mage(R(ight|ep(MatchesDevice|LoadStatus(ReadingHeader|Completed|InvalidData|Un(expectedEOF|knownType)|WillNeedAllData)))|Below|C(ellType|ache(BySize|Never|Default|Always))|Interpolation(High|None|Default|Low)|O(nly|verlaps)|Frame(Gr(oove|ayBezel)|Button|None|Photo)|L(oadStatus(ReadError|C(ompleted|ancelled)|InvalidData|UnexpectedEOF)|eft)|A(lign(Right|Bottom(Right|Left)?|Center|Top(Right|Left)?|Left)|bove)))|O(n(State|eByteGlyphPacking|OffButton|lyScrollerArrows)|ther(Mouse(D(own(Mask)?|ragged(Mask)?)|Up(Mask)?)|TextMovement)|SF1OperatingSystem|pe(n(GL(GO(Re(setLibrary|tainRenderers)|ClearFormatCache|FormatCacheSize)|PFA(R(obust|endererID)|M(inimumPolicy|ulti(sample|Screen)|PSafe|aximumPolicy)|BackingStore|S(creenMask|te(ncilSize|reo)|ingleRenderer|upersample|ample(s|Buffers|Alpha))|NoRecovery|C(o(lor(Size|Float)|mpliant)|losestPolicy)|OffScreen|D(oubleBuffer|epthSize)|PixelBuffer|VirtualScreenCount|FullScreen|Window|A(cc(umSize|elerated)|ux(Buffers|DepthStencil)|l(phaSize|lRenderers))))|StepUnicodeReservedBase)|rationNotSupportedForKeyS(criptError|pecifierError))|ffState|KButton|rPredicateType|bjC(B(itfield|oolType)|S(hortType|tr(ingType|uctType)|electorType)|NoType|CharType|ObjectType|DoubleType|UnionType|PointerType|VoidType|FloatType|Long(Type|longType)|ArrayType))|D(i(s(c(losureBezelStyle|reteCapacityLevelIndicatorStyle)|playWindowRunLoopOrdering)|acriticInsensitivePredicateOption|rect(Selection|PredicateModifier))|o(c(ModalWindowMask|ument(Directory|ationDirectory))|ubleType|wn(TextMovement|ArrowFunctionKey))|e(s(cendingPageOrder|ktopDirectory)|cimalTabStopType|v(ice(NColorSpaceModel|IndependentModifierFlagsMask)|eloper(Directory|ApplicationDirectory))|fault(ControlTint|TokenStyle)|lete(Char(acter|FunctionKey)|FunctionKey|LineFunctionKey)|moApplicationDirectory)|a(yCalendarUnit|teFormatter(MediumStyle|Behavior(10|Default)|ShortStyle|NoStyle|FullStyle|LongStyle))|ra(wer(Clos(ingState|edState)|Open(ingState|State))|gOperation(Generic|Move|None|Copy|Delete|Private|Every|Link|All)))|U(ser(CancelledError|D(irectory|omainMask)|FunctionKey)|RL(Handle(NotLoaded|Load(Succeeded|InProgress|Failed))|CredentialPersistence(None|Permanent|ForSession))|n(scaledWindowMask|cachedRead|i(codeStringEncoding|talicFontMask|fiedTitleAndToolbarWindowMask)|d(o(CloseGroupingRunLoopOrdering|FunctionKey)|e(finedDateComponent|rline(Style(Single|None|Thick|Double)|Pattern(Solid|D(ot|ash(Dot(Dot)?)?)))))|known(ColorSpaceModel|P(ointingDevice|ageOrder)|KeyS(criptError|pecifierError))|boldFontMask)|tilityWindowMask|TF8StringEncoding|p(dateWindowsRunLoopOrdering|TextMovement|ArrowFunctionKey))|J(ustifiedTextAlignment|PEG(2000FileType|FileType)|apaneseEUC(GlyphPacking|StringEncoding))|P(o(s(t(Now|erFontMask|WhenIdle|ASAP)|iti(on(Replace|Be(fore|ginning)|End|After)|ve(IntType|DoubleType|FloatType)))|pUp(NoArrow|ArrowAt(Bottom|Center))|werOffEventType|rtraitOrientation)|NGFileType|ush(InCell(Mask)?|OnPushOffButton)|e(n(TipMask|UpperSideMask|PointingDevice|LowerSideMask)|riodic(Mask)?)|P(S(caleField|tatus(Title|Field)|aveButton)|N(ote(Title|Field)|ame(Title|Field))|CopiesField|TitleField|ImageButton|OptionsButton|P(a(perFeedButton|ge(Range(To|From)|ChoiceMatrix))|reviewButton)|LayoutButton)|lainTextTokenStyle|a(useFunctionKey|ragraphSeparatorCharacter|ge(DownFunctionKey|UpFunctionKey))|r(int(ing(ReplyLater|Success|Cancelled|Failure)|ScreenFunctionKey|erTable(NotFound|OK|Error)|FunctionKey)|o(p(ertyList(XMLFormat|MutableContainers(AndLeaves)?|BinaryFormat|Immutable|OpenStepFormat)|rietaryStringEncoding)|gressIndicator(BarStyle|SpinningStyle|Preferred(SmallThickness|Thickness|LargeThickness|AquaThickness)))|e(ssedTab|vFunctionKey))|L(HeightForm|CancelButton|TitleField|ImageButton|O(KButton|rientationMatrix)|UnitsButton|PaperNameButton|WidthForm))|E(n(terCharacter|d(sWith(Comparison|PredicateOperatorType)|FunctionKey))|v(e(nOddWindingRule|rySubelement)|aluatedObjectExpressionType)|qualTo(Comparison|PredicateOperatorType)|ra(serPointingDevice|CalendarUnit|DatePickerElementFlag)|x(clude(10|QuickDrawElementsIconCreationOption)|pandedFontMask|ecuteFunctionKey))|V(i(ew(M(in(XMargin|YMargin)|ax(XMargin|YMargin))|HeightSizable|NotSizable|WidthSizable)|aPanelFontAction)|erticalRuler|a(lidationErrorM(inimum|aximum)|riableExpressionType))|Key(SpecifierEvaluationScriptError|Down(Mask)?|Up(Mask)?|PathExpressionType|Value(MinusSetMutation|SetSetMutation|Change(Re(placement|moval)|Setting|Insertion)|IntersectSetMutation|ObservingOption(New|Old)|UnionSetMutation|ValidationError))|QTMovie(NormalPlayback|Looping(BackAndForthPlayback|Playback))|F(1(1FunctionKey|7FunctionKey|2FunctionKey|8FunctionKey|3FunctionKey|9FunctionKey|4FunctionKey|5FunctionKey|FunctionKey|0FunctionKey|6FunctionKey)|7FunctionKey|i(nd(PanelAction(Replace(A(ndFind|ll(InSelection)?))?|S(howFindPanel|e(tFindString|lectAll(InSelection)?))|Next|Previous)|FunctionKey)|tPagination|le(Read(No(SuchFileError|PermissionError)|CorruptFileError|In(validFileNameError|applicableStringEncodingError)|Un(supportedSchemeError|knownError))|HandlingPanel(CancelButton|OKButton)|NoSuchFileError|ErrorM(inimum|aximum)|Write(NoPermissionError|In(validFileNameError|applicableStringEncodingError)|OutOfSpaceError|Un(supportedSchemeError|knownError))|LockingError)|xedPitchFontMask)|2(1FunctionKey|7FunctionKey|2FunctionKey|8FunctionKey|3FunctionKey|9FunctionKey|4FunctionKey|5FunctionKey|FunctionKey|0FunctionKey|6FunctionKey)|o(nt(Mo(noSpaceTrait|dernSerifsClass)|BoldTrait|S(ymbolicClass|criptsClass|labSerifsClass|ansSerifClass)|C(o(ndensedTrait|llectionApplicationOnlyMask)|larendonSerifsClass)|TransitionalSerifsClass|I(ntegerAdvancementsRenderingMode|talicTrait)|O(ldStyleSerifsClass|rnamentalsClass)|DefaultRenderingMode|U(nknownClass|IOptimizedTrait)|Panel(S(hadowEffectModeMask|t(andardModesMask|rikethroughEffectModeMask)|izeModeMask)|CollectionModeMask|TextColorEffectModeMask|DocumentColorEffectModeMask|UnderlineEffectModeMask|FaceModeMask|All(ModesMask|EffectsModeMask))|ExpandedTrait|VerticalTrait|F(amilyClassMask|reeformSerifsClass)|Antialiased(RenderingMode|IntegerAdvancementsRenderingMode))|cusRing(Below|Type(None|Default|Exterior)|Only|Above)|urByteGlyphPacking|rm(attingError(M(inimum|aximum))?|FeedCharacter))|8FunctionKey|unction(ExpressionType|KeyMask)|3(1FunctionKey|2FunctionKey|3FunctionKey|4FunctionKey|5FunctionKey|FunctionKey|0FunctionKey)|9FunctionKey|4FunctionKey|P(RevertButton|S(ize(Title|Field)|etButton)|CurrentField|Preview(Button|Field))|l(oat(ingPointSamplesBitmapFormat|Type)|agsChanged(Mask)?)|axButton|5FunctionKey|6FunctionKey)|W(heelModeColorPanel|indow(s(NTOperatingSystem|CP125(1StringEncoding|2StringEncoding|3StringEncoding|4StringEncoding|0StringEncoding)|95(InterfaceStyle|OperatingSystem))|M(iniaturizeButton|ovedEventType)|Below|CloseButton|ToolbarButton|ZoomButton|Out|DocumentIconButton|ExposedEventType|Above)|orkspaceLaunch(NewInstance|InhibitingBackgroundOnly|Default|PreferringClassic|WithoutA(ctivation|ddingToRecents)|A(sync|nd(Hide(Others)?|Print)|llowingClassicStartup))|eek(day(CalendarUnit|OrdinalCalendarUnit)|CalendarUnit)|a(ntsBidiLevels|rningAlertStyle)|r(itingDirection(RightToLeft|Natural|LeftToRight)|apCalendarComponents))|L(i(stModeMatrix|ne(Moves(Right|Down|Up|Left)|B(order|reakBy(C(harWrapping|lipping)|Truncating(Middle|Head|Tail)|WordWrapping))|S(eparatorCharacter|weep(Right|Down|Up|Left))|ToBezierPathElement|DoesntMove|arSlider)|teralSearch|kePredicateOperatorType|ghterFontAction|braryDirectory)|ocalDomainMask|e(ssThan(Comparison|OrEqualTo(Comparison|PredicateOperatorType)|PredicateOperatorType)|ft(Mouse(D(own(Mask)?|ragged(Mask)?)|Up(Mask)?)|T(ext(Movement|Alignment)|ab(sBezelBorder|StopType))|ArrowFunctionKey))|a(yout(RightToLeft|NotDone|CantFit|OutOfGlyphs|Done|LeftToRight)|ndscapeOrientation)|ABColorSpaceModel)|A(sc(iiWithDoubleByteEUCGlyphPacking|endingPageOrder)|n(y(Type|PredicateModifier|EventMask)|choredSearch|imation(Blocking|Nonblocking(Threaded)?|E(ffect(DisappearingItemDefault|Poof)|ase(In(Out)?|Out))|Linear)|dPredicateType)|t(Bottom|tachmentCharacter|omicWrite|Top)|SCIIStringEncoding|d(obe(GB1CharacterCollection|CNS1CharacterCollection|Japan(1CharacterCollection|2CharacterCollection)|Korea1CharacterCollection)|dTraitFontAction|minApplicationDirectory)|uto(saveOperation|Pagination)|pp(lication(SupportDirectory|D(irectory|e(fined(Mask)?|legateReply(Success|Cancel|Failure)|activatedEventType))|ActivatedEventType)|KitDefined(Mask)?)|l(ternateKeyMask|pha(ShiftKeyMask|NonpremultipliedBitmapFormat|FirstBitmapFormat)|ert(SecondButtonReturn|ThirdButtonReturn|OtherReturn|DefaultReturn|ErrorReturn|FirstButtonReturn|AlternateReturn)|l(ScrollerParts|DomainsMask|PredicateModifier|LibrariesDirectory|ApplicationsDirectory))|rgument(sWrongScriptError|EvaluationScriptError)|bove(Bottom|Top)|WTEventType))\\b", - "name": "support.constant.cocoa" + "name": "support.constant.cocoa.objc" }, { - "include": "source.c" + "include": "#c_lang" }, { "include": "#bracketed_content" } ], "repository": { + "c_lang": { + "patterns": [ + { + "include": "#preprocessor-rule-enabled" + }, + { + "include": "#preprocessor-rule-disabled" + }, + { + "include": "#preprocessor-rule-conditional" + }, + { + "include": "#comments" + }, + { + "include": "#switch_statement" + }, + { + "match": "\\b(break|continue|do|else|for|goto|if|_Pragma|return|while)\\b", + "name": "keyword.control.objc" + }, + { + "include": "#storage_types" + }, + { + "match": "typedef", + "name": "keyword.other.typedef.objc" + }, + { + "match": "\\b(const|extern|register|restrict|static|volatile|inline)\\b", + "name": "storage.modifier.objc" + }, + { + "match": "\\bk[A-Z]\\w*\\b", + "name": "constant.other.variable.mac-classic.objc" + }, + { + "match": "\\bg[A-Z]\\w*\\b", + "name": "variable.other.readwrite.global.mac-classic.objc" + }, + { + "match": "\\bs[A-Z]\\w*\\b", + "name": "variable.other.readwrite.static.mac-classic.objc" + }, + { + "match": "\\b(NULL|true|false|TRUE|FALSE)\\b", + "name": "constant.language.objc" + }, + { + "include": "#operators" + }, + { + "include": "#numbers" + }, + { + "include": "#strings" + }, + { + "begin": "(?x)\n^\\s* ((\\#)\\s*define) \\s+\t# define\n((?[a-zA-Z_$][\\w$]*))\t # macro name\n(?:\n (\\()\n\t(\n\t \\s* \\g \\s*\t\t # first argument\n\t ((,) \\s* \\g \\s*)* # additional arguments\n\t (?:\\.\\.\\.)?\t\t\t# varargs ellipsis?\n\t)\n (\\))\n)?", + "beginCaptures": { + "1": { + "name": "keyword.control.directive.define.objc" + }, + "2": { + "name": "punctuation.definition.directive.objc" + }, + "3": { + "name": "entity.name.function.preprocessor.objc" + }, + "5": { + "name": "punctuation.definition.parameters.begin.objc" + }, + "6": { + "name": "variable.parameter.preprocessor.objc" + }, + "8": { + "name": "punctuation.separator.parameters.objc" + }, + "9": { + "name": "punctuation.definition.parameters.end.objc" + } + }, + "end": "(?=(?://|/\\*))|(?", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.objc" + } + }, + "name": "string.quoted.other.lt-gt.include.objc" + } + ] + }, + { + "include": "#pragma-mark" + }, + { + "begin": "^\\s*((#)\\s*line)\\b", + "beginCaptures": { + "1": { + "name": "keyword.control.directive.line.objc" + }, + "2": { + "name": "punctuation.definition.directive.objc" + } + }, + "end": "(?=(?://|/\\*))|(?\\]\\)]))\\s*([a-zA-Z_]\\w*)\\s*(?=(?:\\[\\]\\s*)?(?:,|\\)))", + "captures": { + "1": { + "name": "variable.parameter.probably.objc" + } + } + }, + "access-method": { + "name": "meta.function-call.member.objc", + "begin": "([a-zA-Z_][a-zA-Z_0-9]*|(?<=[\\]\\)]))\\s*(?:(\\.)|(->))((?:(?:[a-zA-Z_][a-zA-Z_0-9]*)\\s*(?:(?:\\.)|(?:->)))*)\\s*([a-zA-Z_][a-zA-Z_0-9]*)(\\()", + "beginCaptures": { + "1": { + "name": "variable.object.objc" + }, + "2": { + "name": "punctuation.separator.dot-access.objc" + }, + "3": { + "name": "punctuation.separator.pointer-access.objc" + }, + "4": { + "patterns": [ + { + "match": "\\.", + "name": "punctuation.separator.dot-access.objc" + }, + { + "match": "->", + "name": "punctuation.separator.pointer-access.objc" + }, + { + "match": "[a-zA-Z_][a-zA-Z_0-9]*", + "name": "variable.object.objc" + }, + { + "name": "everything.else.objc", + "match": ".+" + } + ] + }, + "5": { + "name": "entity.name.function.member.objc" + }, + "6": { + "name": "punctuation.section.arguments.begin.bracket.round.function.member.objc" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.arguments.end.bracket.round.function.member.objc" + } + }, + "patterns": [ + { + "include": "#function-call-innards" + } + ] + }, + "block": { + "patterns": [ + { + "begin": "{", + "beginCaptures": { + "0": { + "name": "punctuation.section.block.begin.bracket.curly.objc" + } + }, + "end": "}|(?=\\s*#\\s*(?:elif|else|endif)\\b)", + "endCaptures": { + "0": { + "name": "punctuation.section.block.end.bracket.curly.objc" + } + }, + "name": "meta.block.objc", + "patterns": [ + { + "include": "#block_innards" + } + ] + } + ] + }, + "block_innards": { + "patterns": [ + { + "include": "#preprocessor-rule-enabled-block" + }, + { + "include": "#preprocessor-rule-disabled-block" + }, + { + "include": "#preprocessor-rule-conditional-block" + }, + { + "include": "#method_access" + }, + { + "include": "#member_access" + }, + { + "include": "#c_function_call" + }, + { + "name": "meta.initialization.objc", + "begin": "(?x)\n(?:\n (?:\n\t(?=\\s)(?=+!]+ | \\(\\) | \\[\\]))\n)\n\\s*(\\() # opening bracket", + "beginCaptures": { + "1": { + "name": "variable.other.objc" + }, + "2": { + "name": "punctuation.section.parens.begin.bracket.round.initialization.objc" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.parens.end.bracket.round.initialization.objc" + } + }, + "patterns": [ + { + "include": "#function-call-innards" + } + ] + }, + { + "begin": "{", + "beginCaptures": { + "0": { + "name": "punctuation.section.block.begin.bracket.curly.objc" + } + }, + "end": "}|(?=\\s*#\\s*(?:elif|else|endif)\\b)", + "endCaptures": { + "0": { + "name": "punctuation.section.block.end.bracket.curly.objc" + } + }, + "patterns": [ + { + "include": "#block_innards" + } + ] + }, + { + "include": "#parens-block" + }, + { + "include": "$base" + } + ] + }, + "c_function_call": { + "begin": "(?x)\n(?!(?:while|for|do|if|else|switch|catch|enumerate|return|typeid|alignof|alignas|sizeof|[cr]?iterate|and|and_eq|bitand|bitor|compl|not|not_eq|or|or_eq|typeid|xor|xor_eq|alignof|alignas)\\s*\\()\n(?=\n(?:[A-Za-z_][A-Za-z0-9_]*+|::)++\\s*\\( # actual name\n|\n(?:(?<=operator)(?:[-*&<>=+!]+|\\(\\)|\\[\\]))\\s*\\(\n)", + "end": "(?<=\\))(?!\\w)", + "name": "meta.function-call.objc", + "patterns": [ + { + "include": "#function-call-innards" + } + ] + }, + "comments": { + "patterns": [ + { + "captures": { + "1": { + "name": "meta.toc-list.banner.block.objc" + } + }, + "match": "^/\\* =(\\s*.*?)\\s*= \\*/$\\n?", + "name": "comment.block.objc" + }, + { + "begin": "/\\*", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.begin.objc" + } + }, + "end": "\\*/", + "endCaptures": { + "0": { + "name": "punctuation.definition.comment.end.objc" + } + }, + "name": "comment.block.objc" + }, + { + "captures": { + "1": { + "name": "meta.toc-list.banner.line.objc" + } + }, + "match": "^// =(\\s*.*?)\\s*=\\s*$\\n?", + "name": "comment.line.banner.objc" + }, + { + "begin": "(^[ \\t]+)?(?=//)", + "beginCaptures": { + "1": { + "name": "punctuation.whitespace.comment.leading.objc" + } + }, + "end": "(?!\\G)", + "patterns": [ + { + "begin": "//", + "beginCaptures": { + "0": { + "name": "punctuation.definition.comment.objc" + } + }, + "end": "(?=\\n)", + "name": "comment.line.double-slash.objc", + "patterns": [ + { + "include": "#line_continuation_character" + } + ] + } + ] + } + ] + }, + "disabled": { + "begin": "^\\s*#\\s*if(n?def)?\\b.*$", + "end": "^\\s*#\\s*endif\\b", + "patterns": [ + { + "include": "#disabled" + }, + { + "include": "#pragma-mark" + } + ] + }, + "line_continuation_character": { + "patterns": [ + { + "match": "(\\\\)\\n", + "captures": { + "1": { + "name": "constant.character.escape.line-continuation.objc" + } + } + } + ] + }, + "parens": { + "name": "meta.parens.objc", + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.section.parens.begin.bracket.round.objc" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.parens.end.bracket.round.objc" + } + }, + "patterns": [ + { + "include": "$base" + } + ] + }, + "parens-block": { + "name": "meta.parens.block.objc", + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.section.parens.begin.bracket.round.objc" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.parens.end.bracket.round.objc" + } + }, + "patterns": [ + { + "include": "#block_innards" + }, + { + "match": "(?-mix:(?>=|\\|=", + "name": "keyword.operator.assignment.compound.bitwise.objc" + }, + { + "match": "<<|>>", + "name": "keyword.operator.bitwise.shift.objc" + }, + { + "match": "!=|<=|>=|==|<|>", + "name": "keyword.operator.comparison.objc" + }, + { + "match": "&&|!|\\|\\|", + "name": "keyword.operator.logical.objc" + }, + { + "match": "&|\\||\\^|~", + "name": "keyword.operator.objc" + }, + { + "match": "=", + "name": "keyword.operator.assignment.objc" + }, + { + "match": "%|\\*|/|-|\\+", + "name": "keyword.operator.objc" + }, + { + "begin": "(\\?)", + "beginCaptures": { + "1": { + "name": "keyword.operator.ternary.objc" + } + }, + "end": "(:)", + "endCaptures": { + "1": { + "name": "keyword.operator.ternary.objc" + } + }, + "patterns": [ + { + "include": "#function-call-innards" + }, + { + "include": "$base" + } + ] + } + ] + }, + "strings": { + "patterns": [ + { + "begin": "\"", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.objc" + } + }, + "end": "\"", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.objc" + } + }, + "name": "string.quoted.double.objc", + "patterns": [ + { + "include": "#string_escaped_char" + }, + { + "include": "#string_placeholder" + }, + { + "include": "#line_continuation_character" + } + ] + }, + { + "begin": "'", + "beginCaptures": { + "0": { + "name": "punctuation.definition.string.begin.objc" + } + }, + "end": "'", + "endCaptures": { + "0": { + "name": "punctuation.definition.string.end.objc" + } + }, + "name": "string.quoted.single.objc", + "patterns": [ + { + "include": "#string_escaped_char" + }, + { + "include": "#line_continuation_character" + } + ] + } + ] + }, + "string_escaped_char": { + "patterns": [ + { + "match": "(?x)\\\\ (\n\\\\\t\t\t |\n[abefnprtv'\"?] |\n[0-3]\\d{,2}\t |\n[4-7]\\d?\t\t|\nx[a-fA-F0-9]{,2} |\nu[a-fA-F0-9]{,4} |\nU[a-fA-F0-9]{,8} )", + "name": "constant.character.escape.objc" + }, + { + "match": "\\\\.", + "name": "invalid.illegal.unknown-escape.objc" + } + ] + }, + "string_placeholder": { + "patterns": [ + { + "match": "(?x) %\n(\\d+\\$)?\t\t\t\t\t\t # field (argument #)\n[#0\\- +']*\t\t\t\t\t\t # flags\n[,;:_]?\t\t\t\t\t\t\t # separator character (AltiVec)\n((-?\\d+)|\\*(-?\\d+\\$)?)?\t\t # minimum field width\n(\\.((-?\\d+)|\\*(-?\\d+\\$)?)?)?\t# precision\n(hh|h|ll|l|j|t|z|q|L|vh|vl|v|hv|hl)? # length modifier\n[diouxXDOUeEfFgGaACcSspn%]\t\t # conversion type", + "name": "constant.other.placeholder.objc" + }, + { + "match": "(%)(?!\"\\s*(PRI|SCN))", + "captures": { + "1": { + "name": "invalid.illegal.placeholder.objc" + } + } + } + ] + }, + "storage_types": { + "patterns": [ + { + "match": "(?-mix:(?=+!]+|\\(\\)|\\[\\]))\\s*\\(\n)", + "end": "(?<=\\))(?!\\w)|(?=+!]+|\\(\\)|\\[\\]))\n)\n\\s*(\\()", + "beginCaptures": { + "1": { + "name": "entity.name.function.objc" + }, + "2": { + "name": "punctuation.section.arguments.begin.bracket.round.objc" + } + }, + "end": "(\\))|(?=+!]+|\\(\\)|\\[\\]))\n)\n\\s*(\\()", + "beginCaptures": { + "1": { + "name": "entity.name.function.objc" + }, + "2": { + "name": "punctuation.section.parameters.begin.bracket.round.objc" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.parameters.end.bracket.round.objc" + } + }, + "patterns": [ + { + "include": "#probably_a_parameter" + }, + { + "include": "#function-innards" + } + ] + }, + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.section.parens.begin.bracket.round.objc" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.parens.end.bracket.round.objc" + } + }, + "patterns": [ + { + "include": "#function-innards" + } + ] + }, + { + "include": "$base" + } + ] + }, + "function-call-innards": { + "patterns": [ + { + "include": "#comments" + }, + { + "include": "#storage_types" + }, + { + "include": "#method_access" + }, + { + "include": "#member_access" + }, + { + "include": "#operators" + }, + { + "begin": "(?x)\n(?!(?:while|for|do|if|else|switch|catch|enumerate|return|typeid|alignof|alignas|sizeof|[cr]?iterate|and|and_eq|bitand|bitor|compl|not|not_eq|or|or_eq|typeid|xor|xor_eq|alignof|alignas)\\s*\\()\n(\n(?:[A-Za-z_][A-Za-z0-9_]*+|::)++ # actual name\n|\n(?:(?<=operator)(?:[-*&<>=+!]+|\\(\\)|\\[\\]))\n)\n\\s*(\\()", + "beginCaptures": { + "1": { + "name": "entity.name.function.objc" + }, + "2": { + "name": "punctuation.section.arguments.begin.bracket.round.objc" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.arguments.end.bracket.round.objc" + } + }, + "patterns": [ + { + "include": "#function-call-innards" + } + ] + }, + { + "begin": "\\(", + "beginCaptures": { + "0": { + "name": "punctuation.section.parens.begin.bracket.round.objc" + } + }, + "end": "\\)", + "endCaptures": { + "0": { + "name": "punctuation.section.parens.end.bracket.round.objc" + } + }, + "patterns": [ + { + "include": "#function-call-innards" + } + ] + }, + { + "include": "#block_innards" + } + ] + }, + "default_statement": { + "name": "meta.conditional.case.objc", + "begin": "((?\\[\\]=]))", + "patterns": [ + { + "name": "meta.head.switch.objc", + "begin": "\\G ?", + "end": "((?:\\{|(?=;)))", + "endCaptures": { + "1": { + "name": "punctuation.section.block.begin.bracket.curly.switch.objc" + } + }, + "patterns": [ + { + "include": "#switch_conditional_parentheses" + }, + { + "include": "$base" + } + ] + }, + { + "name": "meta.body.switch.objc", + "begin": "(?<=\\{)", + "end": "(\\})", + "endCaptures": { + "1": { + "name": "punctuation.section.block.end.bracket.curly.switch.objc" + } + }, + "patterns": [ + { + "include": "#default_statement" + }, + { + "include": "#case_statement" + }, + { + "include": "$base" + }, + { + "include": "#block_innards" + } + ] + }, + { + "name": "meta.tail.switch.objc", + "begin": "(?<=})[\\s\\n]*", + "end": "[\\s\\n]*(?=;)", + "patterns": [ + { + "include": "$base" + } + ] + } + ] + }, + "switch_conditional_parentheses": { + "name": "meta.conditional.switch.objc", + "begin": "(\\()", + "beginCaptures": { + "1": { + "name": "punctuation.section.parens.begin.bracket.round.conditional.switch.objc" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.parens.end.bracket.round.conditional.switch.objc" + } + }, + "patterns": [ + { + "include": "#conditional_context" + } + ] + }, + "static_assert": { + "begin": "(static_assert|_Static_assert)\\s*(\\()", + "beginCaptures": { + "1": { + "name": "keyword.other.static_assert.objc" + }, + "2": { + "name": "punctuation.section.arguments.begin.bracket.round.objc" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.arguments.end.bracket.round.objc" + } + }, + "patterns": [ + { + "name": "meta.static_assert.message.objc", + "begin": "(,)\\s*(?=(?:L|u8|u|U\\s*\\\")?)", + "beginCaptures": { + "1": { + "name": "punctuation.separator.delimiter.objc" + } + }, + "end": "(?=\\))", + "patterns": [ + { + "include": "#string_context" + }, + { + "include": "#string_context_c" + } + ] + }, + { + "include": "#function_call_context" + } + ] + }, + "conditional_context": { + "patterns": [ + { + "include": "$base" + }, + { + "include": "#block_innards" + } + ] + }, + "member_access": { + "match": "((?:[a-zA-Z_]\\w*|(?<=\\]|\\)))\\s*)(?:((?:\\.\\*|\\.))|((?:->\\*|->)))((?:[a-zA-Z_]\\w*\\s*(?-mix:(?:(?:\\.\\*|\\.))|(?:(?:->\\*|->)))\\s*)*)\\s*(\\b(?!(?:void|char|short|int|signed|unsigned|long|float|double|bool|_Bool|_Complex|_Imaginary|u_char|u_short|u_int|u_long|ushort|uint|u_quad_t|quad_t|qaddr_t|caddr_t|daddr_t|div_t|dev_t|fixpt_t|blkcnt_t|blksize_t|gid_t|in_addr_t|in_port_t|ino_t|key_t|mode_t|nlink_t|id_t|pid_t|off_t|segsz_t|swblk_t|uid_t|id_t|clock_t|size_t|ssize_t|time_t|useconds_t|suseconds_t|pthread_attr_t|pthread_cond_t|pthread_condattr_t|pthread_mutex_t|pthread_mutexattr_t|pthread_once_t|pthread_rwlock_t|pthread_rwlockattr_t|pthread_t|pthread_key_t|int8_t|int16_t|int32_t|int64_t|uint8_t|uint16_t|uint32_t|uint64_t|int_least8_t|int_least16_t|int_least32_t|int_least64_t|uint_least8_t|uint_least16_t|uint_least32_t|uint_least64_t|int_fast8_t|int_fast16_t|int_fast32_t|int_fast64_t|uint_fast8_t|uint_fast16_t|uint_fast32_t|uint_fast64_t|intptr_t|uintptr_t|intmax_t|intmax_t|uintmax_t|uintmax_t|memory_order|atomic_bool|atomic_char|atomic_schar|atomic_uchar|atomic_short|atomic_ushort|atomic_int|atomic_uint|atomic_long|atomic_ulong|atomic_llong|atomic_ullong|atomic_char16_t|atomic_char32_t|atomic_wchar_t|atomic_int_least8_t|atomic_uint_least8_t|atomic_int_least16_t|atomic_uint_least16_t|atomic_int_least32_t|atomic_uint_least32_t|atomic_int_least64_t|atomic_uint_least64_t|atomic_int_fast8_t|atomic_uint_fast8_t|atomic_int_fast16_t|atomic_uint_fast16_t|atomic_int_fast32_t|atomic_uint_fast32_t|atomic_int_fast64_t|atomic_uint_fast64_t|atomic_intptr_t|atomic_uintptr_t|atomic_size_t|atomic_ptrdiff_t|atomic_intmax_t|atomic_uintmax_t))[a-zA-Z_]\\w*\\b(?!\\())", + "captures": { + "1": { + "name": "variable.other.object.access.objc" + }, + "2": { + "name": "punctuation.separator.dot-access.objc" + }, + "3": { + "name": "punctuation.separator.pointer-access.objc" + }, + "4": { + "patterns": [ + { + "include": "#member_access" + }, + { + "include": "#method_access" + }, + { + "match": "((?:[a-zA-Z_]\\w*|(?<=\\]|\\)))\\s*)(?:((?:\\.\\*|\\.))|((?:->\\*|->)))", + "captures": { + "1": { + "name": "variable.other.object.access.objc" + }, + "2": { + "name": "punctuation.separator.dot-access.objc" + }, + "3": { + "name": "punctuation.separator.pointer-access.objc" + } + } + } + ] + }, + "5": { + "name": "variable.other.member.objc" + } + } + }, + "method_access": { + "contentName": "meta.function-call.member.objc", + "begin": "((?:[a-zA-Z_]\\w*|(?<=\\]|\\)))\\s*)(?:((?:\\.\\*|\\.))|((?:->\\*|->)))((?:[a-zA-Z_]\\w*\\s*(?-mix:(?:(?:\\.\\*|\\.))|(?:(?:->\\*|->)))\\s*)*)\\s*([a-zA-Z_]\\w*)(\\()", + "beginCaptures": { + "1": { + "name": "variable.other.object.access.objc" + }, + "2": { + "name": "punctuation.separator.dot-access.objc" + }, + "3": { + "name": "punctuation.separator.pointer-access.objc" + }, + "4": { + "patterns": [ + { + "include": "#member_access" + }, + { + "include": "#method_access" + }, + { + "match": "((?:[a-zA-Z_]\\w*|(?<=\\]|\\)))\\s*)(?:((?:\\.\\*|\\.))|((?:->\\*|->)))", + "captures": { + "1": { + "name": "variable.other.object.access.objc" + }, + "2": { + "name": "punctuation.separator.dot-access.objc" + }, + "3": { + "name": "punctuation.separator.pointer-access.objc" + } + } + } + ] + }, + "5": { + "name": "entity.name.function.member.objc" + }, + "6": { + "name": "punctuation.section.arguments.begin.bracket.round.function.member.objc" + } + }, + "end": "(\\))", + "endCaptures": { + "1": { + "name": "punctuation.section.arguments.end.bracket.round.function.member.objc" + } + }, + "patterns": [ + { + "include": "#function-call-innards" + } + ] + }, + "numbers": { + "begin": "(? + +/* + Multi + Line + Comments +*/ +@implementation Test + +- (void) applicationWillFinishLaunching:(NSNotification *)notification +{ +} + +- (IBAction)onSelectInput:(id)sender +{ + NSString* defaultDir = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true)[0]; + + NSOpenPanel* panel = [NSOpenPanel openPanel]; + [panel setAllowedFileTypes:[[NSArray alloc] initWithObjects:@"ipa", @"xcarchive", @"app", nil]]; + + [panel beginWithCompletionHandler:^(NSInteger result) + { + if (result == NSFileHandlingPanelOKButton) + [self.inputTextField setStringValue:[panel.URL path]]; + }]; + return YES; + + int hex = 0xFEF1F0F; + float ing = 3.14; + ing = 3.14e0; + ing = 31.4e-2; +} + +-(id) initWithParams:(id) aHandler withDeviceStateManager:(id) deviceStateManager +{ + // add a tap gesture recognizer + UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)]; + NSMutableArray *gestureRecognizers = [NSMutableArray array]; + [gestureRecognizers addObject:tapGesture]; + [gestureRecognizers addObjectsFromArray:scnView.gestureRecognizers]; + scnView.gestureRecognizers = gestureRecognizers; + + return tapGesture; + return nil; +} + +@end diff --git a/extensions/objective-c/test/colorize-results/test_m.json b/extensions/objective-c/test/colorize-results/test_m.json index c6a4fb257..0cecfd6f3 100644 --- a/extensions/objective-c/test/colorize-results/test_m.json +++ b/extensions/objective-c/test/colorize-results/test_m.json @@ -1,7 +1,7 @@ [ { "c": "//", - "t": "source.objc comment.line.double-slash.cpp.c punctuation.definition.comment.cpp.c", + "t": "source.objc comment.line.double-slash.objc punctuation.definition.comment.objc", "r": { "dark_plus": "comment: #6A9955", "light_plus": "comment: #008000", @@ -12,7 +12,7 @@ }, { "c": "//", - "t": "source.objc comment.line.double-slash.cpp.c punctuation.definition.comment.cpp.c", + "t": "source.objc comment.line.double-slash.objc punctuation.definition.comment.objc", "r": { "dark_plus": "comment: #6A9955", "light_plus": "comment: #008000", @@ -23,7 +23,7 @@ }, { "c": " Copyright (c) Microsoft Corporation. All rights reserved.", - "t": "source.objc comment.line.double-slash.cpp.c", + "t": "source.objc comment.line.double-slash.objc", "r": { "dark_plus": "comment: #6A9955", "light_plus": "comment: #008000", @@ -34,7 +34,7 @@ }, { "c": "//", - "t": "source.objc comment.line.double-slash.cpp.c punctuation.definition.comment.cpp.c", + "t": "source.objc comment.line.double-slash.objc punctuation.definition.comment.objc", "r": { "dark_plus": "comment: #6A9955", "light_plus": "comment: #008000", @@ -45,7 +45,7 @@ }, { "c": "#", - "t": "source.objc meta.preprocessor.include.c keyword.control.directive.import.c punctuation.definition.directive.c", + "t": "source.objc meta.preprocessor.include.objc keyword.control.directive.import.objc punctuation.definition.directive.objc", "r": { "dark_plus": "keyword.control: #C586C0", "light_plus": "keyword.control: #AF00DB", @@ -56,7 +56,7 @@ }, { "c": "import", - "t": "source.objc meta.preprocessor.include.c keyword.control.directive.import.c", + "t": "source.objc meta.preprocessor.include.objc keyword.control.directive.import.objc", "r": { "dark_plus": "keyword.control: #C586C0", "light_plus": "keyword.control: #AF00DB", @@ -67,7 +67,7 @@ }, { "c": " ", - "t": "source.objc meta.preprocessor.include.c", + "t": "source.objc meta.preprocessor.include.objc", "r": { "dark_plus": "meta.preprocessor: #569CD6", "light_plus": "meta.preprocessor: #0000FF", @@ -78,7 +78,7 @@ }, { "c": "\"", - "t": "source.objc meta.preprocessor.include.c string.quoted.double.include.c punctuation.definition.string.begin.c", + "t": "source.objc meta.preprocessor.include.objc string.quoted.double.include.objc punctuation.definition.string.begin.objc", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -89,7 +89,7 @@ }, { "c": "UseQuotes.h", - "t": "source.objc meta.preprocessor.include.c string.quoted.double.include.c", + "t": "source.objc meta.preprocessor.include.objc string.quoted.double.include.objc", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -100,7 +100,7 @@ }, { "c": "\"", - "t": "source.objc meta.preprocessor.include.c string.quoted.double.include.c punctuation.definition.string.end.c", + "t": "source.objc meta.preprocessor.include.objc string.quoted.double.include.objc punctuation.definition.string.end.objc", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -111,7 +111,7 @@ }, { "c": "#", - "t": "source.objc meta.preprocessor.include.c keyword.control.directive.import.c punctuation.definition.directive.c", + "t": "source.objc meta.preprocessor.include.objc keyword.control.directive.import.objc punctuation.definition.directive.objc", "r": { "dark_plus": "keyword.control: #C586C0", "light_plus": "keyword.control: #AF00DB", @@ -122,7 +122,7 @@ }, { "c": "import", - "t": "source.objc meta.preprocessor.include.c keyword.control.directive.import.c", + "t": "source.objc meta.preprocessor.include.objc keyword.control.directive.import.objc", "r": { "dark_plus": "keyword.control: #C586C0", "light_plus": "keyword.control: #AF00DB", @@ -133,7 +133,7 @@ }, { "c": " ", - "t": "source.objc meta.preprocessor.include.c", + "t": "source.objc meta.preprocessor.include.objc", "r": { "dark_plus": "meta.preprocessor: #569CD6", "light_plus": "meta.preprocessor: #0000FF", @@ -144,7 +144,7 @@ }, { "c": "<", - "t": "source.objc meta.preprocessor.include.c string.quoted.other.lt-gt.include.c punctuation.definition.string.begin.c", + "t": "source.objc meta.preprocessor.include.objc string.quoted.other.lt-gt.include.objc punctuation.definition.string.begin.objc", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -155,7 +155,7 @@ }, { "c": "Use/GTLT.h", - "t": "source.objc meta.preprocessor.include.c string.quoted.other.lt-gt.include.c", + "t": "source.objc meta.preprocessor.include.objc string.quoted.other.lt-gt.include.objc", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -166,7 +166,7 @@ }, { "c": ">", - "t": "source.objc meta.preprocessor.include.c string.quoted.other.lt-gt.include.c punctuation.definition.string.end.c", + "t": "source.objc meta.preprocessor.include.objc string.quoted.other.lt-gt.include.objc punctuation.definition.string.end.objc", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -177,7 +177,7 @@ }, { "c": "/*", - "t": "source.objc comment.block.c punctuation.definition.comment.begin.c", + "t": "source.objc comment.block.objc punctuation.definition.comment.begin.objc", "r": { "dark_plus": "comment: #6A9955", "light_plus": "comment: #008000", @@ -188,7 +188,7 @@ }, { "c": "\tMulti", - "t": "source.objc comment.block.c", + "t": "source.objc comment.block.objc", "r": { "dark_plus": "comment: #6A9955", "light_plus": "comment: #008000", @@ -199,7 +199,7 @@ }, { "c": "\tLine", - "t": "source.objc comment.block.c", + "t": "source.objc comment.block.objc", "r": { "dark_plus": "comment: #6A9955", "light_plus": "comment: #008000", @@ -210,7 +210,7 @@ }, { "c": "\tComments", - "t": "source.objc comment.block.c", + "t": "source.objc comment.block.objc", "r": { "dark_plus": "comment: #6A9955", "light_plus": "comment: #008000", @@ -221,7 +221,7 @@ }, { "c": "*/", - "t": "source.objc comment.block.c punctuation.definition.comment.end.c", + "t": "source.objc comment.block.objc punctuation.definition.comment.end.objc", "r": { "dark_plus": "comment: #6A9955", "light_plus": "comment: #008000", @@ -298,7 +298,7 @@ }, { "c": "void", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.function.objc meta.return-type.objc storage.type.built-in.primitive.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.function.objc meta.return-type.objc storage.type.built-in.primitive.objc", "r": { "dark_plus": "storage.type: #569CD6", "light_plus": "storage.type: #0000FF", @@ -364,7 +364,7 @@ }, { "c": "NSNotification", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.function.objc meta.argument-type.objc support.class.cocoa", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.function.objc meta.argument-type.objc support.class.cocoa.objc", "r": { "dark_plus": "support.class: #4EC9B0", "light_plus": "support.class: #267F99", @@ -386,7 +386,7 @@ }, { "c": "*", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.function.objc meta.argument-type.objc keyword.operator.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.function.objc meta.argument-type.objc keyword.operator.objc", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -419,7 +419,7 @@ }, { "c": "{", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c punctuation.section.block.begin.bracket.curly.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc punctuation.section.block.begin.bracket.curly.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -430,7 +430,7 @@ }, { "c": "}", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c punctuation.section.block.end.bracket.curly.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc punctuation.section.block.end.bracket.curly.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -551,7 +551,7 @@ }, { "c": "{", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c punctuation.section.block.begin.bracket.curly.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc punctuation.section.block.begin.bracket.curly.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -562,7 +562,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -573,7 +573,7 @@ }, { "c": "NSString", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c support.class.cocoa", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc support.class.cocoa.objc", "r": { "dark_plus": "support.class: #4EC9B0", "light_plus": "support.class: #267F99", @@ -584,7 +584,7 @@ }, { "c": "*", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c keyword.operator.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc keyword.operator.objc", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -595,7 +595,7 @@ }, { "c": " defaultDir ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -606,7 +606,7 @@ }, { "c": "=", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c keyword.operator.assignment.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc keyword.operator.assignment.objc", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -617,7 +617,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c punctuation.whitespace.support.function.leading.cocoa", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc punctuation.whitespace.support.function.leading.cocoa.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -628,7 +628,7 @@ }, { "c": "NSSearchPathForDirectoriesInDomains", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c support.function.cocoa", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc support.function.cocoa.objc", "r": { "dark_plus": "support.function: #DCDCAA", "light_plus": "support.function: #795E26", @@ -639,7 +639,7 @@ }, { "c": "(", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.parens.block.c punctuation.section.parens.begin.bracket.round.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.parens.block.objc punctuation.section.parens.begin.bracket.round.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -650,7 +650,7 @@ }, { "c": "NSDocumentDirectory", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.parens.block.c support.constant.cocoa", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.parens.block.objc support.constant.cocoa.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -661,7 +661,7 @@ }, { "c": ",", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.parens.block.c punctuation.separator.delimiter.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.parens.block.objc punctuation.separator.delimiter.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -672,7 +672,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.parens.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.parens.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -683,7 +683,7 @@ }, { "c": "NSUserDomainMask", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.parens.block.c support.constant.cocoa", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.parens.block.objc support.constant.cocoa.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -694,7 +694,7 @@ }, { "c": ",", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.parens.block.c punctuation.separator.delimiter.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.parens.block.objc punctuation.separator.delimiter.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -705,7 +705,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.parens.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.parens.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -716,7 +716,7 @@ }, { "c": "true", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.parens.block.c constant.language.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.parens.block.objc constant.language.objc", "r": { "dark_plus": "constant.language: #569CD6", "light_plus": "constant.language: #0000FF", @@ -727,7 +727,7 @@ }, { "c": ")", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.parens.block.c punctuation.section.parens.end.bracket.round.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.parens.block.objc punctuation.section.parens.end.bracket.round.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -738,7 +738,7 @@ }, { "c": "[", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c punctuation.definition.begin.bracket.square.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc punctuation.definition.begin.bracket.square.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -749,7 +749,7 @@ }, { "c": "0", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c constant.numeric.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc constant.numeric.decimal.objc", "r": { "dark_plus": "constant.numeric: #B5CEA8", "light_plus": "constant.numeric: #09885A", @@ -760,7 +760,7 @@ }, { "c": "]", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c punctuation.definition.end.bracket.square.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc punctuation.definition.end.bracket.square.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -771,7 +771,7 @@ }, { "c": ";", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c punctuation.terminator.statement.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc punctuation.terminator.statement.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -782,7 +782,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -793,7 +793,7 @@ }, { "c": "NSOpenPanel", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c support.class.cocoa", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc support.class.cocoa.objc", "r": { "dark_plus": "support.class: #4EC9B0", "light_plus": "support.class: #267F99", @@ -804,7 +804,7 @@ }, { "c": "*", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c keyword.operator.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc keyword.operator.objc", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -815,7 +815,7 @@ }, { "c": " panel ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -826,7 +826,7 @@ }, { "c": "=", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c keyword.operator.assignment.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc keyword.operator.assignment.objc", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -837,7 +837,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -848,7 +848,7 @@ }, { "c": "[", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c punctuation.definition.begin.bracket.square.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc punctuation.definition.begin.bracket.square.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -859,7 +859,7 @@ }, { "c": "NSOpenPanel", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c support.class.cocoa", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc support.class.cocoa.objc", "r": { "dark_plus": "support.class: #4EC9B0", "light_plus": "support.class: #267F99", @@ -870,7 +870,7 @@ }, { "c": " openPanel", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -881,7 +881,7 @@ }, { "c": "]", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c punctuation.definition.end.bracket.square.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc punctuation.definition.end.bracket.square.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -892,7 +892,7 @@ }, { "c": ";", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c punctuation.terminator.statement.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc punctuation.terminator.statement.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -903,7 +903,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -914,7 +914,7 @@ }, { "c": "[", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c punctuation.definition.begin.bracket.square.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc punctuation.definition.begin.bracket.square.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -925,7 +925,7 @@ }, { "c": "panel setAllowedFileTypes:", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -936,7 +936,7 @@ }, { "c": "[", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c punctuation.definition.begin.bracket.square.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc punctuation.definition.begin.bracket.square.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -947,7 +947,7 @@ }, { "c": "[", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c meta.bracket.square.access.c punctuation.definition.begin.bracket.square.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc meta.bracket.square.access.objc punctuation.definition.begin.bracket.square.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -958,7 +958,7 @@ }, { "c": "NSArray", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c meta.bracket.square.access.c support.class.cocoa", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc meta.bracket.square.access.objc support.class.cocoa.objc", "r": { "dark_plus": "support.class: #4EC9B0", "light_plus": "support.class: #267F99", @@ -969,7 +969,7 @@ }, { "c": " alloc", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c meta.bracket.square.access.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc meta.bracket.square.access.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -980,7 +980,7 @@ }, { "c": "]", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c meta.bracket.square.access.c punctuation.definition.end.bracket.square.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc meta.bracket.square.access.objc punctuation.definition.end.bracket.square.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -991,7 +991,7 @@ }, { "c": " initWithObjects:", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1002,7 +1002,7 @@ }, { "c": "@\"", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c string.quoted.double.objc punctuation.definition.string.begin.objc", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc string.quoted.double.objc punctuation.definition.string.begin.objc", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1013,7 +1013,7 @@ }, { "c": "ipa", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c string.quoted.double.objc", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc string.quoted.double.objc", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1024,7 +1024,7 @@ }, { "c": "\"", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c string.quoted.double.objc punctuation.definition.string.end.objc", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc string.quoted.double.objc punctuation.definition.string.end.objc", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1035,7 +1035,7 @@ }, { "c": ",", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c punctuation.separator.delimiter.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc punctuation.separator.delimiter.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1046,7 +1046,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1057,7 +1057,7 @@ }, { "c": "@\"", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c string.quoted.double.objc punctuation.definition.string.begin.objc", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc string.quoted.double.objc punctuation.definition.string.begin.objc", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1068,7 +1068,7 @@ }, { "c": "xcarchive", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c string.quoted.double.objc", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc string.quoted.double.objc", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1079,7 +1079,7 @@ }, { "c": "\"", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c string.quoted.double.objc punctuation.definition.string.end.objc", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc string.quoted.double.objc punctuation.definition.string.end.objc", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1090,7 +1090,7 @@ }, { "c": ",", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c punctuation.separator.delimiter.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc punctuation.separator.delimiter.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1101,7 +1101,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1112,7 +1112,7 @@ }, { "c": "@\"", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c string.quoted.double.objc punctuation.definition.string.begin.objc", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc string.quoted.double.objc punctuation.definition.string.begin.objc", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1123,7 +1123,7 @@ }, { "c": "app", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c string.quoted.double.objc", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc string.quoted.double.objc", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1134,7 +1134,7 @@ }, { "c": "\"", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c string.quoted.double.objc punctuation.definition.string.end.objc", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc string.quoted.double.objc punctuation.definition.string.end.objc", "r": { "dark_plus": "string: #CE9178", "light_plus": "string: #A31515", @@ -1145,7 +1145,7 @@ }, { "c": ",", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c punctuation.separator.delimiter.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc punctuation.separator.delimiter.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1156,7 +1156,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1167,7 +1167,7 @@ }, { "c": "nil", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c constant.language.objc", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc constant.language.objc", "r": { "dark_plus": "constant.language: #569CD6", "light_plus": "constant.language: #0000FF", @@ -1178,7 +1178,7 @@ }, { "c": "]", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c punctuation.definition.end.bracket.square.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc punctuation.definition.end.bracket.square.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1189,7 +1189,7 @@ }, { "c": "]", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c punctuation.definition.end.bracket.square.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc punctuation.definition.end.bracket.square.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1200,7 +1200,7 @@ }, { "c": ";", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c punctuation.terminator.statement.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc punctuation.terminator.statement.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1211,7 +1211,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1222,7 +1222,7 @@ }, { "c": "[", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c punctuation.definition.begin.bracket.square.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc punctuation.definition.begin.bracket.square.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1233,7 +1233,7 @@ }, { "c": "panel beginWithCompletionHandler:", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1244,7 +1244,7 @@ }, { "c": "^", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c keyword.operator.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc keyword.operator.objc", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -1255,7 +1255,7 @@ }, { "c": "(", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c punctuation.section.parens.begin.bracket.round.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc punctuation.section.parens.begin.bracket.round.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1266,7 +1266,7 @@ }, { "c": "NSInteger", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c support.type.cocoa.leopard", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc support.type.cocoa.leopard.objc", "r": { "dark_plus": "support.type: #4EC9B0", "light_plus": "support.type: #267F99", @@ -1277,7 +1277,7 @@ }, { "c": " result", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1288,7 +1288,7 @@ }, { "c": ")", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c punctuation.section.parens.end.bracket.round.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc punctuation.section.parens.end.bracket.round.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1299,7 +1299,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1310,7 +1310,7 @@ }, { "c": "{", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c punctuation.section.block.begin.bracket.curly.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc punctuation.section.block.begin.bracket.curly.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1321,7 +1321,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1332,7 +1332,7 @@ }, { "c": "if", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c keyword.control.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc keyword.control.objc", "r": { "dark_plus": "keyword.control: #C586C0", "light_plus": "keyword.control: #AF00DB", @@ -1343,7 +1343,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1354,7 +1354,7 @@ }, { "c": "(", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.parens.block.c punctuation.section.parens.begin.bracket.round.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.parens.block.objc punctuation.section.parens.begin.bracket.round.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1365,7 +1365,7 @@ }, { "c": "result ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.parens.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.parens.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1376,7 +1376,7 @@ }, { "c": "==", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.parens.block.c keyword.operator.comparison.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.parens.block.objc keyword.operator.comparison.objc", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -1387,7 +1387,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.parens.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.parens.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1398,7 +1398,7 @@ }, { "c": "NSFileHandlingPanelOKButton", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.parens.block.c support.constant.cocoa", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.parens.block.objc support.constant.cocoa.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1409,7 +1409,7 @@ }, { "c": ")", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.parens.block.c punctuation.section.parens.end.bracket.round.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.parens.block.objc punctuation.section.parens.end.bracket.round.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1420,7 +1420,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1431,7 +1431,7 @@ }, { "c": "[", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c punctuation.definition.begin.bracket.square.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc punctuation.definition.begin.bracket.square.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1442,7 +1442,7 @@ }, { "c": "self", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c variable.other.object.access.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc variable.other.object.access.objc", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -1453,7 +1453,7 @@ }, { "c": ".", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c punctuation.separator.dot-access.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc punctuation.separator.dot-access.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1464,7 +1464,7 @@ }, { "c": "inputTextField", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c variable.other.member.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc variable.other.member.objc", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -1475,7 +1475,7 @@ }, { "c": " setStringValue:", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1486,7 +1486,7 @@ }, { "c": "[", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c meta.bracket.square.access.c punctuation.definition.begin.bracket.square.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc meta.bracket.square.access.objc punctuation.definition.begin.bracket.square.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1497,7 +1497,7 @@ }, { "c": "panel", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c meta.bracket.square.access.c variable.other.object.access.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc meta.bracket.square.access.objc variable.other.object.access.objc", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -1508,7 +1508,7 @@ }, { "c": ".", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c meta.bracket.square.access.c punctuation.separator.dot-access.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc meta.bracket.square.access.objc punctuation.separator.dot-access.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1519,7 +1519,7 @@ }, { "c": "URL", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c meta.bracket.square.access.c variable.other.member.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc meta.bracket.square.access.objc variable.other.member.objc", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -1530,7 +1530,7 @@ }, { "c": " path", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c meta.bracket.square.access.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc meta.bracket.square.access.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1541,7 +1541,7 @@ }, { "c": "]", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c meta.bracket.square.access.c punctuation.definition.end.bracket.square.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc meta.bracket.square.access.objc punctuation.definition.end.bracket.square.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1552,7 +1552,7 @@ }, { "c": "]", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c punctuation.definition.end.bracket.square.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc punctuation.definition.end.bracket.square.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1563,7 +1563,7 @@ }, { "c": ";", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c punctuation.terminator.statement.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc punctuation.terminator.statement.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1574,7 +1574,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1585,7 +1585,7 @@ }, { "c": "}", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c punctuation.section.block.end.bracket.curly.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc punctuation.section.block.end.bracket.curly.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1596,7 +1596,7 @@ }, { "c": "]", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c punctuation.definition.end.bracket.square.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc punctuation.definition.end.bracket.square.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1607,7 +1607,7 @@ }, { "c": ";", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c punctuation.terminator.statement.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc punctuation.terminator.statement.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1618,7 +1618,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1629,7 +1629,7 @@ }, { "c": "return", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c keyword.control.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc keyword.control.objc", "r": { "dark_plus": "keyword.control: #C586C0", "light_plus": "keyword.control: #AF00DB", @@ -1640,7 +1640,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1651,7 +1651,7 @@ }, { "c": "YES", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c constant.language.objc", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc constant.language.objc", "r": { "dark_plus": "constant.language: #569CD6", "light_plus": "constant.language: #0000FF", @@ -1662,7 +1662,7 @@ }, { "c": ";", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c punctuation.terminator.statement.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc punctuation.terminator.statement.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1673,7 +1673,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1684,7 +1684,7 @@ }, { "c": "int", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c storage.type.built-in.primitive.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc storage.type.built-in.primitive.objc", "r": { "dark_plus": "storage.type: #569CD6", "light_plus": "storage.type: #0000FF", @@ -1695,7 +1695,7 @@ }, { "c": " hex ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1706,7 +1706,7 @@ }, { "c": "=", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c keyword.operator.assignment.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc keyword.operator.assignment.objc", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -1717,7 +1717,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1727,8 +1727,19 @@ } }, { - "c": "0xFEF1F0F", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c constant.numeric.c", + "c": "0x", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc keyword.other.unit.hexadecimal.objc", + "r": { + "dark_plus": "keyword.other.unit: #B5CEA8", + "light_plus": "keyword.other.unit: #09885A", + "dark_vs": "keyword.other.unit: #B5CEA8", + "light_vs": "keyword.other.unit: #09885A", + "hc_black": "keyword.other.unit: #B5CEA8" + } + }, + { + "c": "FEF1F0F", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc constant.numeric.hexadecimal.objc", "r": { "dark_plus": "constant.numeric: #B5CEA8", "light_plus": "constant.numeric: #09885A", @@ -1739,7 +1750,7 @@ }, { "c": ";", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c punctuation.terminator.statement.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc punctuation.terminator.statement.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1750,7 +1761,7 @@ }, { "c": "\t ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1761,7 +1772,7 @@ }, { "c": "float", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c storage.type.built-in.primitive.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc storage.type.built-in.primitive.objc", "r": { "dark_plus": "storage.type: #569CD6", "light_plus": "storage.type: #0000FF", @@ -1772,7 +1783,7 @@ }, { "c": " ing ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1783,7 +1794,7 @@ }, { "c": "=", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c keyword.operator.assignment.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc keyword.operator.assignment.objc", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -1794,7 +1805,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1804,8 +1815,30 @@ } }, { - "c": "3.14", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c constant.numeric.c", + "c": "3", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc constant.numeric.decimal.objc", + "r": { + "dark_plus": "constant.numeric: #B5CEA8", + "light_plus": "constant.numeric: #09885A", + "dark_vs": "constant.numeric: #B5CEA8", + "light_vs": "constant.numeric: #09885A", + "hc_black": "constant.numeric: #B5CEA8" + } + }, + { + "c": ".", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc constant.numeric.decimal.point.objc", + "r": { + "dark_plus": "constant.numeric: #B5CEA8", + "light_plus": "constant.numeric: #09885A", + "dark_vs": "constant.numeric: #B5CEA8", + "light_vs": "constant.numeric: #09885A", + "hc_black": "constant.numeric: #B5CEA8" + } + }, + { + "c": "14", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc constant.numeric.decimal.objc", "r": { "dark_plus": "constant.numeric: #B5CEA8", "light_plus": "constant.numeric: #09885A", @@ -1816,7 +1849,7 @@ }, { "c": ";", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c punctuation.terminator.statement.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc punctuation.terminator.statement.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1827,7 +1860,7 @@ }, { "c": "\t ing ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1838,7 +1871,7 @@ }, { "c": "=", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c keyword.operator.assignment.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc keyword.operator.assignment.objc", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -1849,7 +1882,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1859,8 +1892,52 @@ } }, { - "c": "3.14e0", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c constant.numeric.c", + "c": "3", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc constant.numeric.decimal.objc", + "r": { + "dark_plus": "constant.numeric: #B5CEA8", + "light_plus": "constant.numeric: #09885A", + "dark_vs": "constant.numeric: #B5CEA8", + "light_vs": "constant.numeric: #09885A", + "hc_black": "constant.numeric: #B5CEA8" + } + }, + { + "c": ".", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc constant.numeric.decimal.point.objc", + "r": { + "dark_plus": "constant.numeric: #B5CEA8", + "light_plus": "constant.numeric: #09885A", + "dark_vs": "constant.numeric: #B5CEA8", + "light_vs": "constant.numeric: #09885A", + "hc_black": "constant.numeric: #B5CEA8" + } + }, + { + "c": "14", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc constant.numeric.decimal.objc", + "r": { + "dark_plus": "constant.numeric: #B5CEA8", + "light_plus": "constant.numeric: #09885A", + "dark_vs": "constant.numeric: #B5CEA8", + "light_vs": "constant.numeric: #09885A", + "hc_black": "constant.numeric: #B5CEA8" + } + }, + { + "c": "e", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc keyword.other.unit.exponent.decimal.objc", + "r": { + "dark_plus": "keyword.other.unit: #B5CEA8", + "light_plus": "keyword.other.unit: #09885A", + "dark_vs": "keyword.other.unit: #B5CEA8", + "light_vs": "keyword.other.unit: #09885A", + "hc_black": "keyword.other.unit: #B5CEA8" + } + }, + { + "c": "0", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc constant.numeric.exponent.decimal.objc", "r": { "dark_plus": "constant.numeric: #B5CEA8", "light_plus": "constant.numeric: #09885A", @@ -1871,7 +1948,7 @@ }, { "c": ";", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c punctuation.terminator.statement.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc punctuation.terminator.statement.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1882,7 +1959,7 @@ }, { "c": "\t ing ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1893,7 +1970,7 @@ }, { "c": "=", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c keyword.operator.assignment.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc keyword.operator.assignment.objc", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -1904,7 +1981,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1914,8 +1991,63 @@ } }, { - "c": "31.4e-2", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c constant.numeric.c", + "c": "31", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc constant.numeric.decimal.objc", + "r": { + "dark_plus": "constant.numeric: #B5CEA8", + "light_plus": "constant.numeric: #09885A", + "dark_vs": "constant.numeric: #B5CEA8", + "light_vs": "constant.numeric: #09885A", + "hc_black": "constant.numeric: #B5CEA8" + } + }, + { + "c": ".", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc constant.numeric.decimal.point.objc", + "r": { + "dark_plus": "constant.numeric: #B5CEA8", + "light_plus": "constant.numeric: #09885A", + "dark_vs": "constant.numeric: #B5CEA8", + "light_vs": "constant.numeric: #09885A", + "hc_black": "constant.numeric: #B5CEA8" + } + }, + { + "c": "4", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc constant.numeric.decimal.objc", + "r": { + "dark_plus": "constant.numeric: #B5CEA8", + "light_plus": "constant.numeric: #09885A", + "dark_vs": "constant.numeric: #B5CEA8", + "light_vs": "constant.numeric: #09885A", + "hc_black": "constant.numeric: #B5CEA8" + } + }, + { + "c": "e", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc keyword.other.unit.exponent.decimal.objc", + "r": { + "dark_plus": "keyword.other.unit: #B5CEA8", + "light_plus": "keyword.other.unit: #09885A", + "dark_vs": "keyword.other.unit: #B5CEA8", + "light_vs": "keyword.other.unit: #09885A", + "hc_black": "keyword.other.unit: #B5CEA8" + } + }, + { + "c": "-", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc keyword.operator.minus.exponent.decimal.objc", + "r": { + "dark_plus": "keyword.operator: #D4D4D4", + "light_plus": "keyword.operator: #000000", + "dark_vs": "keyword.operator: #D4D4D4", + "light_vs": "keyword.operator: #000000", + "hc_black": "keyword.operator: #D4D4D4" + } + }, + { + "c": "2", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc constant.numeric.exponent.decimal.objc", "r": { "dark_plus": "constant.numeric: #B5CEA8", "light_plus": "constant.numeric: #09885A", @@ -1926,7 +2058,7 @@ }, { "c": ";", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c punctuation.terminator.statement.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc punctuation.terminator.statement.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -1937,7 +2069,7 @@ }, { "c": "}", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c punctuation.section.block.end.bracket.curly.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc punctuation.section.block.end.bracket.curly.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2234,7 +2366,7 @@ }, { "c": "{", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c punctuation.section.block.begin.bracket.curly.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc punctuation.section.block.begin.bracket.curly.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2245,7 +2377,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c punctuation.whitespace.comment.leading.cpp.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc punctuation.whitespace.comment.leading.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2256,7 +2388,7 @@ }, { "c": "//", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c comment.line.double-slash.cpp.c punctuation.definition.comment.cpp.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc comment.line.double-slash.objc punctuation.definition.comment.objc", "r": { "dark_plus": "comment: #6A9955", "light_plus": "comment: #008000", @@ -2267,7 +2399,7 @@ }, { "c": " add a tap gesture recognizer", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c comment.line.double-slash.cpp.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc comment.line.double-slash.objc", "r": { "dark_plus": "comment: #6A9955", "light_plus": "comment: #008000", @@ -2278,7 +2410,7 @@ }, { "c": " UITapGestureRecognizer ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2289,7 +2421,7 @@ }, { "c": "*", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c keyword.operator.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc keyword.operator.objc", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -2300,7 +2432,7 @@ }, { "c": "tapGesture ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2311,7 +2443,7 @@ }, { "c": "=", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c keyword.operator.assignment.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc keyword.operator.assignment.objc", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -2322,7 +2454,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2333,7 +2465,7 @@ }, { "c": "[", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c punctuation.definition.begin.bracket.square.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc punctuation.definition.begin.bracket.square.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2344,7 +2476,7 @@ }, { "c": "[", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c punctuation.definition.begin.bracket.square.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc punctuation.definition.begin.bracket.square.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2355,7 +2487,7 @@ }, { "c": "UITapGestureRecognizer alloc", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2366,7 +2498,7 @@ }, { "c": "]", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.bracket.square.access.c punctuation.definition.end.bracket.square.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.bracket.square.access.objc punctuation.definition.end.bracket.square.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2377,7 +2509,7 @@ }, { "c": " initWithTarget:self action:", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2388,7 +2520,7 @@ }, { "c": "@", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.selector.objc storage.type.objc punctuation.definition.storage.type.objc", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.selector.objc storage.type.objc punctuation.definition.storage.type.objc", "r": { "dark_plus": "storage.type: #569CD6", "light_plus": "storage.type: #0000FF", @@ -2399,7 +2531,7 @@ }, { "c": "selector", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.selector.objc storage.type.objc", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.selector.objc storage.type.objc", "r": { "dark_plus": "storage.type: #569CD6", "light_plus": "storage.type: #0000FF", @@ -2410,7 +2542,7 @@ }, { "c": "(", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.selector.objc punctuation.definition.storage.type.objc", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.selector.objc punctuation.definition.storage.type.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2421,7 +2553,7 @@ }, { "c": "handleTap:", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.selector.objc meta.selector.method-name.objc support.function.any-method.name-of-parameter.objc", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.selector.objc meta.selector.method-name.objc support.function.any-method.name-of-parameter.objc", "r": { "dark_plus": "support.function: #DCDCAA", "light_plus": "support.function: #795E26", @@ -2432,7 +2564,7 @@ }, { "c": ")", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c meta.selector.objc punctuation.definition.storage.type.objc", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc meta.selector.objc punctuation.definition.storage.type.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2443,7 +2575,7 @@ }, { "c": "]", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c punctuation.definition.end.bracket.square.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc punctuation.definition.end.bracket.square.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2454,7 +2586,7 @@ }, { "c": ";", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c punctuation.terminator.statement.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc punctuation.terminator.statement.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2465,7 +2597,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2476,7 +2608,7 @@ }, { "c": "NSMutableArray", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c support.class.cocoa", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc support.class.cocoa.objc", "r": { "dark_plus": "support.class: #4EC9B0", "light_plus": "support.class: #267F99", @@ -2487,7 +2619,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2498,7 +2630,7 @@ }, { "c": "*", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c keyword.operator.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc keyword.operator.objc", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -2509,7 +2641,7 @@ }, { "c": "gestureRecognizers ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2520,7 +2652,7 @@ }, { "c": "=", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c keyword.operator.assignment.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc keyword.operator.assignment.objc", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -2531,7 +2663,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2542,7 +2674,7 @@ }, { "c": "[", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c punctuation.definition.begin.bracket.square.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc punctuation.definition.begin.bracket.square.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2553,7 +2685,7 @@ }, { "c": "NSMutableArray", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c support.class.cocoa", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc support.class.cocoa.objc", "r": { "dark_plus": "support.class: #4EC9B0", "light_plus": "support.class: #267F99", @@ -2564,7 +2696,7 @@ }, { "c": " array", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2575,7 +2707,7 @@ }, { "c": "]", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c punctuation.definition.end.bracket.square.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc punctuation.definition.end.bracket.square.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2586,7 +2718,7 @@ }, { "c": ";", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c punctuation.terminator.statement.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc punctuation.terminator.statement.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2597,7 +2729,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2608,7 +2740,7 @@ }, { "c": "[", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c punctuation.definition.begin.bracket.square.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc punctuation.definition.begin.bracket.square.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2619,7 +2751,7 @@ }, { "c": "gestureRecognizers addObject:tapGesture", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2630,7 +2762,7 @@ }, { "c": "]", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c punctuation.definition.end.bracket.square.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc punctuation.definition.end.bracket.square.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2641,7 +2773,7 @@ }, { "c": ";", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c punctuation.terminator.statement.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc punctuation.terminator.statement.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2652,7 +2784,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2663,7 +2795,7 @@ }, { "c": "[", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c punctuation.definition.begin.bracket.square.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc punctuation.definition.begin.bracket.square.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2674,7 +2806,7 @@ }, { "c": "gestureRecognizers addObjectsFromArray:", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2685,7 +2817,7 @@ }, { "c": "scnView", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c variable.other.object.access.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc variable.other.object.access.objc", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -2696,7 +2828,7 @@ }, { "c": ".", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c punctuation.separator.dot-access.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc punctuation.separator.dot-access.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2707,7 +2839,7 @@ }, { "c": "gestureRecognizers", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c variable.other.member.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc variable.other.member.objc", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -2718,7 +2850,7 @@ }, { "c": "]", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c meta.bracket.square.access.c punctuation.definition.end.bracket.square.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc meta.bracket.square.access.objc punctuation.definition.end.bracket.square.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2729,7 +2861,7 @@ }, { "c": ";", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c punctuation.terminator.statement.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc punctuation.terminator.statement.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2740,7 +2872,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2751,7 +2883,7 @@ }, { "c": "scnView", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c variable.other.object.access.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc variable.other.object.access.objc", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -2762,7 +2894,7 @@ }, { "c": ".", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c punctuation.separator.dot-access.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc punctuation.separator.dot-access.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2773,7 +2905,7 @@ }, { "c": "gestureRecognizers", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c variable.other.member.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc variable.other.member.objc", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -2784,7 +2916,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2795,7 +2927,7 @@ }, { "c": "=", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c keyword.operator.assignment.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc keyword.operator.assignment.objc", "r": { "dark_plus": "keyword.operator: #D4D4D4", "light_plus": "keyword.operator: #000000", @@ -2806,7 +2938,7 @@ }, { "c": " gestureRecognizers", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2817,7 +2949,7 @@ }, { "c": ";", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c punctuation.terminator.statement.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc punctuation.terminator.statement.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2828,7 +2960,7 @@ }, { "c": "\t", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2839,7 +2971,7 @@ }, { "c": "return", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c keyword.control.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc keyword.control.objc", "r": { "dark_plus": "keyword.control: #C586C0", "light_plus": "keyword.control: #AF00DB", @@ -2850,7 +2982,7 @@ }, { "c": " tapGesture", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2861,7 +2993,7 @@ }, { "c": ";", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c punctuation.terminator.statement.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc punctuation.terminator.statement.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2872,7 +3004,7 @@ }, { "c": "\t", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2883,7 +3015,7 @@ }, { "c": "return", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c keyword.control.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc keyword.control.objc", "r": { "dark_plus": "keyword.control: #C586C0", "light_plus": "keyword.control: #AF00DB", @@ -2894,7 +3026,7 @@ }, { "c": " ", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2905,7 +3037,7 @@ }, { "c": "nil", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c constant.language.objc", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc constant.language.objc", "r": { "dark_plus": "constant.language: #569CD6", "light_plus": "constant.language: #0000FF", @@ -2916,7 +3048,7 @@ }, { "c": ";", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c punctuation.terminator.statement.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc punctuation.terminator.statement.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", @@ -2927,7 +3059,7 @@ }, { "c": "}", - "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.c punctuation.section.block.end.bracket.curly.c", + "t": "source.objc meta.implementation.objc meta.scope.implementation.objc meta.function-with-body.objc meta.block.objc punctuation.section.block.end.bracket.curly.objc", "r": { "dark_plus": "default: #D4D4D4", "light_plus": "default: #000000", diff --git a/extensions/objective-c/test/colorize-results/test_mm.json b/extensions/objective-c/test/colorize-results/test_mm.json new file mode 100644 index 000000000..2af2751bc --- /dev/null +++ b/extensions/objective-c/test/colorize-results/test_mm.json @@ -0,0 +1,3093 @@ +[ + { + "c": "//", + "t": "source.objcpp comment.line.double-slash.objcpp punctuation.definition.comment.objcpp", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": "//", + "t": "source.objcpp comment.line.double-slash.objcpp punctuation.definition.comment.objcpp", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": " Copyright (c) Microsoft Corporation. All rights reserved.", + "t": "source.objcpp comment.line.double-slash.objcpp", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": "//", + "t": "source.objcpp comment.line.double-slash.objcpp punctuation.definition.comment.objcpp", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": "#", + "t": "source.objcpp meta.preprocessor.include.objcpp keyword.control.directive.import.objcpp punctuation.definition.directive.objcpp", + "r": { + "dark_plus": "keyword.control: #C586C0", + "light_plus": "keyword.control: #AF00DB", + "dark_vs": "keyword.control: #569CD6", + "light_vs": "keyword.control: #0000FF", + "hc_black": "keyword.control: #C586C0" + } + }, + { + "c": "import", + "t": "source.objcpp meta.preprocessor.include.objcpp keyword.control.directive.import.objcpp", + "r": { + "dark_plus": "keyword.control: #C586C0", + "light_plus": "keyword.control: #AF00DB", + "dark_vs": "keyword.control: #569CD6", + "light_vs": "keyword.control: #0000FF", + "hc_black": "keyword.control: #C586C0" + } + }, + { + "c": " ", + "t": "source.objcpp meta.preprocessor.include.objcpp", + "r": { + "dark_plus": "meta.preprocessor: #569CD6", + "light_plus": "meta.preprocessor: #0000FF", + "dark_vs": "meta.preprocessor: #569CD6", + "light_vs": "meta.preprocessor: #0000FF", + "hc_black": "meta.preprocessor: #569CD6" + } + }, + { + "c": "\"", + "t": "source.objcpp meta.preprocessor.include.objcpp string.quoted.double.include.objcpp punctuation.definition.string.begin.objcpp", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178" + } + }, + { + "c": "UseQuotes.h", + "t": "source.objcpp meta.preprocessor.include.objcpp string.quoted.double.include.objcpp", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178" + } + }, + { + "c": "\"", + "t": "source.objcpp meta.preprocessor.include.objcpp string.quoted.double.include.objcpp punctuation.definition.string.end.objcpp", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178" + } + }, + { + "c": "#", + "t": "source.objcpp meta.preprocessor.include.objcpp keyword.control.directive.import.objcpp punctuation.definition.directive.objcpp", + "r": { + "dark_plus": "keyword.control: #C586C0", + "light_plus": "keyword.control: #AF00DB", + "dark_vs": "keyword.control: #569CD6", + "light_vs": "keyword.control: #0000FF", + "hc_black": "keyword.control: #C586C0" + } + }, + { + "c": "import", + "t": "source.objcpp meta.preprocessor.include.objcpp keyword.control.directive.import.objcpp", + "r": { + "dark_plus": "keyword.control: #C586C0", + "light_plus": "keyword.control: #AF00DB", + "dark_vs": "keyword.control: #569CD6", + "light_vs": "keyword.control: #0000FF", + "hc_black": "keyword.control: #C586C0" + } + }, + { + "c": " ", + "t": "source.objcpp meta.preprocessor.include.objcpp", + "r": { + "dark_plus": "meta.preprocessor: #569CD6", + "light_plus": "meta.preprocessor: #0000FF", + "dark_vs": "meta.preprocessor: #569CD6", + "light_vs": "meta.preprocessor: #0000FF", + "hc_black": "meta.preprocessor: #569CD6" + } + }, + { + "c": "<", + "t": "source.objcpp meta.preprocessor.include.objcpp string.quoted.other.lt-gt.include.objcpp punctuation.definition.string.begin.objcpp", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178" + } + }, + { + "c": "Use/GTLT.h", + "t": "source.objcpp meta.preprocessor.include.objcpp string.quoted.other.lt-gt.include.objcpp", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178" + } + }, + { + "c": ">", + "t": "source.objcpp meta.preprocessor.include.objcpp string.quoted.other.lt-gt.include.objcpp punctuation.definition.string.end.objcpp", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178" + } + }, + { + "c": "/*", + "t": "source.objcpp comment.block.objcpp punctuation.definition.comment.begin.objcpp", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": "\tMulti", + "t": "source.objcpp comment.block.objcpp", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": "\tLine", + "t": "source.objcpp comment.block.objcpp", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": "\tComments", + "t": "source.objcpp comment.block.objcpp", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": "*/", + "t": "source.objcpp comment.block.objcpp punctuation.definition.comment.end.objcpp", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": "@", + "t": "source.objcpp meta.implementation.objcpp storage.type.objcpp punctuation.definition.storage.type.objcpp", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + }, + { + "c": "implementation", + "t": "source.objcpp meta.implementation.objcpp storage.type.objcpp", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "Test", + "t": "source.objcpp meta.implementation.objcpp entity.name.type.objcpp", + "r": { + "dark_plus": "entity.name.type: #4EC9B0", + "light_plus": "entity.name.type: #267F99", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "entity.name.type: #4EC9B0" + } + }, + { + "c": "- ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "(", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.return-type.objcpp punctuation.definition.type.begin.objcpp", + "r": { + "dark_plus": "meta.return-type: #4EC9B0", + "light_plus": "meta.return-type: #267F99", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "meta.return-type: #4EC9B0" + } + }, + { + "c": "void", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.return-type.objcpp storage.type.built-in.primitive.objcpp", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + }, + { + "c": ")", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.return-type.objcpp punctuation.definition.type.end.objcpp", + "r": { + "dark_plus": "meta.return-type: #4EC9B0", + "light_plus": "meta.return-type: #267F99", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "meta.return-type: #4EC9B0" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.return-type.objcpp", + "r": { + "dark_plus": "meta.return-type: #4EC9B0", + "light_plus": "meta.return-type: #267F99", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "meta.return-type: #4EC9B0" + } + }, + { + "c": "applicationWillFinishLaunching", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.return-type.objcpp entity.name.function.objcpp", + "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": ":", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp entity.name.function.name-of-parameter.objcpp punctuation.separator.arguments.objcpp", + "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": "(", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp punctuation.definition.type.begin.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "NSNotification", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp support.class.cocoa.objcpp", + "r": { + "dark_plus": "support.class: #4EC9B0", + "light_plus": "support.class: #267F99", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "support.class: #4EC9B0" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "*", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp keyword.operator.objcpp", + "r": { + "dark_plus": "keyword.operator: #D4D4D4", + "light_plus": "keyword.operator: #000000", + "dark_vs": "keyword.operator: #D4D4D4", + "light_vs": "keyword.operator: #000000", + "hc_black": "keyword.operator: #D4D4D4" + } + }, + { + "c": ")", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp punctuation.definition.type.end.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "notification", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp variable.parameter.function.objcpp", + "r": { + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "variable: #9CDCFE" + } + }, + { + "c": "{", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.section.block.begin.bracket.curly.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "}", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.section.block.end.bracket.curly.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "- ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "(", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.return-type.objcpp punctuation.definition.type.begin.objcpp", + "r": { + "dark_plus": "meta.return-type: #4EC9B0", + "light_plus": "meta.return-type: #267F99", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "meta.return-type: #4EC9B0" + } + }, + { + "c": "IBAction", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.return-type.objcpp storage.type.objcpp", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + }, + { + "c": ")", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.return-type.objcpp punctuation.definition.type.end.objcpp", + "r": { + "dark_plus": "meta.return-type: #4EC9B0", + "light_plus": "meta.return-type: #267F99", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "meta.return-type: #4EC9B0" + } + }, + { + "c": "onSelectInput", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.return-type.objcpp entity.name.function.objcpp", + "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": ":", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp entity.name.function.name-of-parameter.objcpp punctuation.separator.arguments.objcpp", + "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": "(", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp punctuation.definition.type.begin.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "id", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp storage.type.id.objcpp", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + }, + { + "c": ")", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp punctuation.definition.type.end.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "sender", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp variable.parameter.function.objcpp", + "r": { + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "variable: #9CDCFE" + } + }, + { + "c": "{", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.section.block.begin.bracket.curly.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "NSString", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp support.class.cocoa.objcpp", + "r": { + "dark_plus": "support.class: #4EC9B0", + "light_plus": "support.class: #267F99", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "support.class: #4EC9B0" + } + }, + { + "c": "*", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.operator.objcpp", + "r": { + "dark_plus": "keyword.operator: #D4D4D4", + "light_plus": "keyword.operator: #000000", + "dark_vs": "keyword.operator: #D4D4D4", + "light_vs": "keyword.operator: #000000", + "hc_black": "keyword.operator: #D4D4D4" + } + }, + { + "c": " defaultDir ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "=", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.operator.assignment.objcpp", + "r": { + "dark_plus": "keyword.operator: #D4D4D4", + "light_plus": "keyword.operator: #000000", + "dark_vs": "keyword.operator: #D4D4D4", + "light_vs": "keyword.operator: #000000", + "hc_black": "keyword.operator: #D4D4D4" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.whitespace.support.function.leading.cocoa.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "NSSearchPathForDirectoriesInDomains", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp support.function.cocoa.objcpp", + "r": { + "dark_plus": "support.function: #DCDCAA", + "light_plus": "support.function: #795E26", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "support.function: #DCDCAA" + } + }, + { + "c": "(", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.parens.block.objcpp punctuation.section.parens.begin.bracket.round.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "NSDocumentDirectory", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.parens.block.objcpp support.constant.cocoa.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ",", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.parens.block.objcpp punctuation.separator.delimiter.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.parens.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "NSUserDomainMask", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.parens.block.objcpp support.constant.cocoa.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ",", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.parens.block.objcpp punctuation.separator.delimiter.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.parens.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "true", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.parens.block.objcpp constant.language.objcpp", + "r": { + "dark_plus": "constant.language: #569CD6", + "light_plus": "constant.language: #0000FF", + "dark_vs": "constant.language: #569CD6", + "light_vs": "constant.language: #0000FF", + "hc_black": "constant.language: #569CD6" + } + }, + { + "c": ")", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.parens.block.objcpp punctuation.section.parens.end.bracket.round.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "[", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.definition.begin.bracket.square.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "0", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp constant.numeric.decimal.objcpp", + "r": { + "dark_plus": "constant.numeric: #B5CEA8", + "light_plus": "constant.numeric: #09885A", + "dark_vs": "constant.numeric: #B5CEA8", + "light_vs": "constant.numeric: #09885A", + "hc_black": "constant.numeric: #B5CEA8" + } + }, + { + "c": "]", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.definition.end.bracket.square.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ";", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.terminator.statement.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "NSOpenPanel", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp support.class.cocoa.objcpp", + "r": { + "dark_plus": "support.class: #4EC9B0", + "light_plus": "support.class: #267F99", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "support.class: #4EC9B0" + } + }, + { + "c": "*", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.operator.objcpp", + "r": { + "dark_plus": "keyword.operator: #D4D4D4", + "light_plus": "keyword.operator: #000000", + "dark_vs": "keyword.operator: #D4D4D4", + "light_vs": "keyword.operator: #000000", + "hc_black": "keyword.operator: #D4D4D4" + } + }, + { + "c": " panel ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "=", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.operator.assignment.objcpp", + "r": { + "dark_plus": "keyword.operator: #D4D4D4", + "light_plus": "keyword.operator: #000000", + "dark_vs": "keyword.operator: #D4D4D4", + "light_vs": "keyword.operator: #000000", + "hc_black": "keyword.operator: #D4D4D4" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "[", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.definition.begin.bracket.square.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "NSOpenPanel", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp support.class.cocoa.objcpp", + "r": { + "dark_plus": "support.class: #4EC9B0", + "light_plus": "support.class: #267F99", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "support.class: #4EC9B0" + } + }, + { + "c": " openPanel", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "]", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.definition.end.bracket.square.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ";", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.terminator.statement.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "[", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.definition.begin.bracket.square.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "panel setAllowedFileTypes:", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "[", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp punctuation.definition.begin.bracket.square.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "[", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp punctuation.definition.begin.bracket.square.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "NSArray", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp support.class.cocoa.objcpp", + "r": { + "dark_plus": "support.class: #4EC9B0", + "light_plus": "support.class: #267F99", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "support.class: #4EC9B0" + } + }, + { + "c": " alloc", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "]", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp punctuation.definition.end.bracket.square.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " initWithObjects:", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "@\"", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp string.quoted.double.objcpp punctuation.definition.string.begin.objcpp", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178" + } + }, + { + "c": "ipa", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp string.quoted.double.objcpp", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178" + } + }, + { + "c": "\"", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp string.quoted.double.objcpp punctuation.definition.string.end.objcpp", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178" + } + }, + { + "c": ",", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp punctuation.separator.delimiter.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "@\"", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp string.quoted.double.objcpp punctuation.definition.string.begin.objcpp", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178" + } + }, + { + "c": "xcarchive", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp string.quoted.double.objcpp", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178" + } + }, + { + "c": "\"", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp string.quoted.double.objcpp punctuation.definition.string.end.objcpp", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178" + } + }, + { + "c": ",", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp punctuation.separator.delimiter.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "@\"", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp string.quoted.double.objcpp punctuation.definition.string.begin.objcpp", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178" + } + }, + { + "c": "app", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp string.quoted.double.objcpp", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178" + } + }, + { + "c": "\"", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp string.quoted.double.objcpp punctuation.definition.string.end.objcpp", + "r": { + "dark_plus": "string: #CE9178", + "light_plus": "string: #A31515", + "dark_vs": "string: #CE9178", + "light_vs": "string: #A31515", + "hc_black": "string: #CE9178" + } + }, + { + "c": ",", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp punctuation.separator.delimiter.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "nil", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp constant.language.objcpp", + "r": { + "dark_plus": "constant.language: #569CD6", + "light_plus": "constant.language: #0000FF", + "dark_vs": "constant.language: #569CD6", + "light_vs": "constant.language: #0000FF", + "hc_black": "constant.language: #569CD6" + } + }, + { + "c": "]", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp punctuation.definition.end.bracket.square.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "]", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.definition.end.bracket.square.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ";", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.terminator.statement.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "[", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.definition.begin.bracket.square.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "panel beginWithCompletionHandler:", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "^", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp keyword.operator.objcpp", + "r": { + "dark_plus": "keyword.operator: #D4D4D4", + "light_plus": "keyword.operator: #000000", + "dark_vs": "keyword.operator: #D4D4D4", + "light_vs": "keyword.operator: #000000", + "hc_black": "keyword.operator: #D4D4D4" + } + }, + { + "c": "(", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.section.parens.begin.bracket.round.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "NSInteger", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp support.type.cocoa.leopard.objcpp", + "r": { + "dark_plus": "support.type: #4EC9B0", + "light_plus": "support.type: #267F99", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "support.type: #4EC9B0" + } + }, + { + "c": " result", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ")", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.section.parens.end.bracket.round.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "{", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.section.block.begin.bracket.curly.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "if", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp keyword.control.objcpp", + "r": { + "dark_plus": "keyword.control: #C586C0", + "light_plus": "keyword.control: #AF00DB", + "dark_vs": "keyword.control: #569CD6", + "light_vs": "keyword.control: #0000FF", + "hc_black": "keyword.control: #C586C0" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "(", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.parens.block.objcpp punctuation.section.parens.begin.bracket.round.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "result ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.parens.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "==", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.parens.block.objcpp keyword.operator.comparison.objcpp", + "r": { + "dark_plus": "keyword.operator: #D4D4D4", + "light_plus": "keyword.operator: #000000", + "dark_vs": "keyword.operator: #D4D4D4", + "light_vs": "keyword.operator: #000000", + "hc_black": "keyword.operator: #D4D4D4" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.parens.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "NSFileHandlingPanelOKButton", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.parens.block.objcpp support.constant.cocoa.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ")", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.parens.block.objcpp punctuation.section.parens.end.bracket.round.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "[", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp punctuation.definition.begin.bracket.square.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "self", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp variable.other.object.access.objcpp", + "r": { + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "variable: #9CDCFE" + } + }, + { + "c": ".", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp punctuation.separator.dot-access.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "inputTextField", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp variable.other.member.objcpp", + "r": { + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "variable: #9CDCFE" + } + }, + { + "c": " setStringValue:", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "[", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp punctuation.definition.begin.bracket.square.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "panel", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp variable.other.object.access.objcpp", + "r": { + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "variable: #9CDCFE" + } + }, + { + "c": ".", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp punctuation.separator.dot-access.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "URL", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp variable.other.member.objcpp", + "r": { + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "variable: #9CDCFE" + } + }, + { + "c": " path", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "]", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp punctuation.definition.end.bracket.square.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "]", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp punctuation.definition.end.bracket.square.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ";", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.terminator.statement.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "}", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.section.block.end.bracket.curly.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "]", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.definition.end.bracket.square.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ";", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.terminator.statement.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "return", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.control.objcpp", + "r": { + "dark_plus": "keyword.control: #C586C0", + "light_plus": "keyword.control: #AF00DB", + "dark_vs": "keyword.control: #569CD6", + "light_vs": "keyword.control: #0000FF", + "hc_black": "keyword.control: #C586C0" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "YES", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp constant.language.objcpp", + "r": { + "dark_plus": "constant.language: #569CD6", + "light_plus": "constant.language: #0000FF", + "dark_vs": "constant.language: #569CD6", + "light_vs": "constant.language: #0000FF", + "hc_black": "constant.language: #569CD6" + } + }, + { + "c": ";", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.terminator.statement.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "int", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp storage.type.built-in.primitive.objcpp", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + }, + { + "c": " hex ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "=", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.operator.assignment.objcpp", + "r": { + "dark_plus": "keyword.operator: #D4D4D4", + "light_plus": "keyword.operator: #000000", + "dark_vs": "keyword.operator: #D4D4D4", + "light_vs": "keyword.operator: #000000", + "hc_black": "keyword.operator: #D4D4D4" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "0x", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.other.unit.hexadecimal.objcpp", + "r": { + "dark_plus": "keyword.other.unit: #B5CEA8", + "light_plus": "keyword.other.unit: #09885A", + "dark_vs": "keyword.other.unit: #B5CEA8", + "light_vs": "keyword.other.unit: #09885A", + "hc_black": "keyword.other.unit: #B5CEA8" + } + }, + { + "c": "FEF1F0F", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp constant.numeric.hexadecimal.objcpp", + "r": { + "dark_plus": "constant.numeric: #B5CEA8", + "light_plus": "constant.numeric: #09885A", + "dark_vs": "constant.numeric: #B5CEA8", + "light_vs": "constant.numeric: #09885A", + "hc_black": "constant.numeric: #B5CEA8" + } + }, + { + "c": ";", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.terminator.statement.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "\t ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "float", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp storage.type.built-in.primitive.objcpp", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + }, + { + "c": " ing ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "=", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.operator.assignment.objcpp", + "r": { + "dark_plus": "keyword.operator: #D4D4D4", + "light_plus": "keyword.operator: #000000", + "dark_vs": "keyword.operator: #D4D4D4", + "light_vs": "keyword.operator: #000000", + "hc_black": "keyword.operator: #D4D4D4" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "3", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp constant.numeric.decimal.objcpp", + "r": { + "dark_plus": "constant.numeric: #B5CEA8", + "light_plus": "constant.numeric: #09885A", + "dark_vs": "constant.numeric: #B5CEA8", + "light_vs": "constant.numeric: #09885A", + "hc_black": "constant.numeric: #B5CEA8" + } + }, + { + "c": ".", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp constant.numeric.decimal.point.objcpp", + "r": { + "dark_plus": "constant.numeric: #B5CEA8", + "light_plus": "constant.numeric: #09885A", + "dark_vs": "constant.numeric: #B5CEA8", + "light_vs": "constant.numeric: #09885A", + "hc_black": "constant.numeric: #B5CEA8" + } + }, + { + "c": "14", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp constant.numeric.decimal.objcpp", + "r": { + "dark_plus": "constant.numeric: #B5CEA8", + "light_plus": "constant.numeric: #09885A", + "dark_vs": "constant.numeric: #B5CEA8", + "light_vs": "constant.numeric: #09885A", + "hc_black": "constant.numeric: #B5CEA8" + } + }, + { + "c": ";", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.terminator.statement.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "\t ing ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "=", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.operator.assignment.objcpp", + "r": { + "dark_plus": "keyword.operator: #D4D4D4", + "light_plus": "keyword.operator: #000000", + "dark_vs": "keyword.operator: #D4D4D4", + "light_vs": "keyword.operator: #000000", + "hc_black": "keyword.operator: #D4D4D4" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "3", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp constant.numeric.decimal.objcpp", + "r": { + "dark_plus": "constant.numeric: #B5CEA8", + "light_plus": "constant.numeric: #09885A", + "dark_vs": "constant.numeric: #B5CEA8", + "light_vs": "constant.numeric: #09885A", + "hc_black": "constant.numeric: #B5CEA8" + } + }, + { + "c": ".", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp constant.numeric.decimal.point.objcpp", + "r": { + "dark_plus": "constant.numeric: #B5CEA8", + "light_plus": "constant.numeric: #09885A", + "dark_vs": "constant.numeric: #B5CEA8", + "light_vs": "constant.numeric: #09885A", + "hc_black": "constant.numeric: #B5CEA8" + } + }, + { + "c": "14", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp constant.numeric.decimal.objcpp", + "r": { + "dark_plus": "constant.numeric: #B5CEA8", + "light_plus": "constant.numeric: #09885A", + "dark_vs": "constant.numeric: #B5CEA8", + "light_vs": "constant.numeric: #09885A", + "hc_black": "constant.numeric: #B5CEA8" + } + }, + { + "c": "e", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.other.unit.exponent.decimal.objcpp", + "r": { + "dark_plus": "keyword.other.unit: #B5CEA8", + "light_plus": "keyword.other.unit: #09885A", + "dark_vs": "keyword.other.unit: #B5CEA8", + "light_vs": "keyword.other.unit: #09885A", + "hc_black": "keyword.other.unit: #B5CEA8" + } + }, + { + "c": "0", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp constant.numeric.exponent.decimal.objcpp", + "r": { + "dark_plus": "constant.numeric: #B5CEA8", + "light_plus": "constant.numeric: #09885A", + "dark_vs": "constant.numeric: #B5CEA8", + "light_vs": "constant.numeric: #09885A", + "hc_black": "constant.numeric: #B5CEA8" + } + }, + { + "c": ";", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.terminator.statement.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "\t ing ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "=", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.operator.assignment.objcpp", + "r": { + "dark_plus": "keyword.operator: #D4D4D4", + "light_plus": "keyword.operator: #000000", + "dark_vs": "keyword.operator: #D4D4D4", + "light_vs": "keyword.operator: #000000", + "hc_black": "keyword.operator: #D4D4D4" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "31", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp constant.numeric.decimal.objcpp", + "r": { + "dark_plus": "constant.numeric: #B5CEA8", + "light_plus": "constant.numeric: #09885A", + "dark_vs": "constant.numeric: #B5CEA8", + "light_vs": "constant.numeric: #09885A", + "hc_black": "constant.numeric: #B5CEA8" + } + }, + { + "c": ".", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp constant.numeric.decimal.point.objcpp", + "r": { + "dark_plus": "constant.numeric: #B5CEA8", + "light_plus": "constant.numeric: #09885A", + "dark_vs": "constant.numeric: #B5CEA8", + "light_vs": "constant.numeric: #09885A", + "hc_black": "constant.numeric: #B5CEA8" + } + }, + { + "c": "4", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp constant.numeric.decimal.objcpp", + "r": { + "dark_plus": "constant.numeric: #B5CEA8", + "light_plus": "constant.numeric: #09885A", + "dark_vs": "constant.numeric: #B5CEA8", + "light_vs": "constant.numeric: #09885A", + "hc_black": "constant.numeric: #B5CEA8" + } + }, + { + "c": "e", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.other.unit.exponent.decimal.objcpp", + "r": { + "dark_plus": "keyword.other.unit: #B5CEA8", + "light_plus": "keyword.other.unit: #09885A", + "dark_vs": "keyword.other.unit: #B5CEA8", + "light_vs": "keyword.other.unit: #09885A", + "hc_black": "keyword.other.unit: #B5CEA8" + } + }, + { + "c": "-", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.operator.minus.exponent.decimal.objcpp", + "r": { + "dark_plus": "keyword.operator: #D4D4D4", + "light_plus": "keyword.operator: #000000", + "dark_vs": "keyword.operator: #D4D4D4", + "light_vs": "keyword.operator: #000000", + "hc_black": "keyword.operator: #D4D4D4" + } + }, + { + "c": "2", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp constant.numeric.exponent.decimal.objcpp", + "r": { + "dark_plus": "constant.numeric: #B5CEA8", + "light_plus": "constant.numeric: #09885A", + "dark_vs": "constant.numeric: #B5CEA8", + "light_vs": "constant.numeric: #09885A", + "hc_black": "constant.numeric: #B5CEA8" + } + }, + { + "c": ";", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.terminator.statement.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "}", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.section.block.end.bracket.curly.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "-", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "(", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.return-type.objcpp punctuation.definition.type.begin.objcpp", + "r": { + "dark_plus": "meta.return-type: #4EC9B0", + "light_plus": "meta.return-type: #267F99", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "meta.return-type: #4EC9B0" + } + }, + { + "c": "id", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.return-type.objcpp storage.type.id.objcpp", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + }, + { + "c": ")", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.return-type.objcpp punctuation.definition.type.end.objcpp", + "r": { + "dark_plus": "meta.return-type: #4EC9B0", + "light_plus": "meta.return-type: #267F99", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "meta.return-type: #4EC9B0" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.return-type.objcpp", + "r": { + "dark_plus": "meta.return-type: #4EC9B0", + "light_plus": "meta.return-type: #267F99", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "meta.return-type: #4EC9B0" + } + }, + { + "c": "initWithParams", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.return-type.objcpp entity.name.function.objcpp", + "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": ":", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp entity.name.function.name-of-parameter.objcpp punctuation.separator.arguments.objcpp", + "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": "(", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp punctuation.definition.type.begin.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "id", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp meta.id-with-protocol.objcpp storage.type.objcpp", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + }, + { + "c": "<", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp meta.id-with-protocol.objcpp meta.protocol-list.objcpp punctuation.section.scope.begin.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "anObject", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp meta.id-with-protocol.objcpp meta.protocol-list.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ">", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp meta.id-with-protocol.objcpp meta.protocol-list.objcpp punctuation.section.scope.end.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ")", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp punctuation.definition.type.end.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "aHandler", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp variable.parameter.function.objcpp", + "r": { + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "variable: #9CDCFE" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "withDeviceStateManager", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp entity.name.function.name-of-parameter.objcpp", + "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": ":", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp entity.name.function.name-of-parameter.objcpp punctuation.separator.arguments.objcpp", + "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": "(", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp punctuation.definition.type.begin.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "id", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp meta.id-with-protocol.objcpp storage.type.objcpp", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + }, + { + "c": "<", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp meta.id-with-protocol.objcpp meta.protocol-list.objcpp punctuation.section.scope.begin.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "anotherObject", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp meta.id-with-protocol.objcpp meta.protocol-list.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ">", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp meta.id-with-protocol.objcpp meta.protocol-list.objcpp punctuation.section.scope.end.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ")", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp punctuation.definition.type.end.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "deviceStateManager", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp variable.parameter.function.objcpp", + "r": { + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "variable: #9CDCFE" + } + }, + { + "c": "{", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.section.block.begin.bracket.curly.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.whitespace.comment.leading.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "//", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp comment.line.double-slash.objcpp punctuation.definition.comment.objcpp", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": " add a tap gesture recognizer", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp comment.line.double-slash.objcpp", + "r": { + "dark_plus": "comment: #6A9955", + "light_plus": "comment: #008000", + "dark_vs": "comment: #6A9955", + "light_vs": "comment: #008000", + "hc_black": "comment: #7CA668" + } + }, + { + "c": " UITapGestureRecognizer ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "*", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.operator.objcpp", + "r": { + "dark_plus": "keyword.operator: #D4D4D4", + "light_plus": "keyword.operator: #000000", + "dark_vs": "keyword.operator: #D4D4D4", + "light_vs": "keyword.operator: #000000", + "hc_black": "keyword.operator: #D4D4D4" + } + }, + { + "c": "tapGesture ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "=", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.operator.assignment.objcpp", + "r": { + "dark_plus": "keyword.operator: #D4D4D4", + "light_plus": "keyword.operator: #000000", + "dark_vs": "keyword.operator: #D4D4D4", + "light_vs": "keyword.operator: #000000", + "hc_black": "keyword.operator: #D4D4D4" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "[", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.definition.begin.bracket.square.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "[", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp punctuation.definition.begin.bracket.square.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "UITapGestureRecognizer alloc", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "]", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp punctuation.definition.end.bracket.square.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " initWithTarget:self action:", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "@", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.selector.objcpp storage.type.objcpp punctuation.definition.storage.type.objcpp", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + }, + { + "c": "selector", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.selector.objcpp storage.type.objcpp", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + }, + { + "c": "(", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.selector.objcpp punctuation.definition.storage.type.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "handleTap:", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.selector.objcpp meta.selector.method-name.objcpp support.function.any-method.name-of-parameter.objcpp", + "r": { + "dark_plus": "support.function: #DCDCAA", + "light_plus": "support.function: #795E26", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "support.function: #DCDCAA" + } + }, + { + "c": ")", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.selector.objcpp punctuation.definition.storage.type.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "]", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.definition.end.bracket.square.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ";", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.terminator.statement.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "NSMutableArray", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp support.class.cocoa.objcpp", + "r": { + "dark_plus": "support.class: #4EC9B0", + "light_plus": "support.class: #267F99", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "support.class: #4EC9B0" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "*", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.operator.objcpp", + "r": { + "dark_plus": "keyword.operator: #D4D4D4", + "light_plus": "keyword.operator: #000000", + "dark_vs": "keyword.operator: #D4D4D4", + "light_vs": "keyword.operator: #000000", + "hc_black": "keyword.operator: #D4D4D4" + } + }, + { + "c": "gestureRecognizers ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "=", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.operator.assignment.objcpp", + "r": { + "dark_plus": "keyword.operator: #D4D4D4", + "light_plus": "keyword.operator: #000000", + "dark_vs": "keyword.operator: #D4D4D4", + "light_vs": "keyword.operator: #000000", + "hc_black": "keyword.operator: #D4D4D4" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "[", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.definition.begin.bracket.square.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "NSMutableArray", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp support.class.cocoa.objcpp", + "r": { + "dark_plus": "support.class: #4EC9B0", + "light_plus": "support.class: #267F99", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "support.class: #4EC9B0" + } + }, + { + "c": " array", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "]", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.definition.end.bracket.square.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ";", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.terminator.statement.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "[", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.definition.begin.bracket.square.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "gestureRecognizers addObject:tapGesture", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "]", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.definition.end.bracket.square.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ";", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.terminator.statement.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "[", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.definition.begin.bracket.square.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "gestureRecognizers addObjectsFromArray:", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "scnView", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp variable.other.object.access.objcpp", + "r": { + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "variable: #9CDCFE" + } + }, + { + "c": ".", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.separator.dot-access.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "gestureRecognizers", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp variable.other.member.objcpp", + "r": { + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "variable: #9CDCFE" + } + }, + { + "c": "]", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.definition.end.bracket.square.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ";", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.terminator.statement.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "scnView", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp variable.other.object.access.objcpp", + "r": { + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "variable: #9CDCFE" + } + }, + { + "c": ".", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.separator.dot-access.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "gestureRecognizers", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp variable.other.member.objcpp", + "r": { + "dark_plus": "variable: #9CDCFE", + "light_plus": "variable: #001080", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "variable: #9CDCFE" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "=", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.operator.assignment.objcpp", + "r": { + "dark_plus": "keyword.operator: #D4D4D4", + "light_plus": "keyword.operator: #000000", + "dark_vs": "keyword.operator: #D4D4D4", + "light_vs": "keyword.operator: #000000", + "hc_black": "keyword.operator: #D4D4D4" + } + }, + { + "c": " gestureRecognizers", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ";", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.terminator.statement.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "\t", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "return", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.control.objcpp", + "r": { + "dark_plus": "keyword.control: #C586C0", + "light_plus": "keyword.control: #AF00DB", + "dark_vs": "keyword.control: #569CD6", + "light_vs": "keyword.control: #0000FF", + "hc_black": "keyword.control: #C586C0" + } + }, + { + "c": " tapGesture", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": ";", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.terminator.statement.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "\t", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "return", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.control.objcpp", + "r": { + "dark_plus": "keyword.control: #C586C0", + "light_plus": "keyword.control: #AF00DB", + "dark_vs": "keyword.control: #569CD6", + "light_vs": "keyword.control: #0000FF", + "hc_black": "keyword.control: #C586C0" + } + }, + { + "c": " ", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "nil", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp constant.language.objcpp", + "r": { + "dark_plus": "constant.language: #569CD6", + "light_plus": "constant.language: #0000FF", + "dark_vs": "constant.language: #569CD6", + "light_vs": "constant.language: #0000FF", + "hc_black": "constant.language: #569CD6" + } + }, + { + "c": ";", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.terminator.statement.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "}", + "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.section.block.end.bracket.curly.objcpp", + "r": { + "dark_plus": "default: #D4D4D4", + "light_plus": "default: #000000", + "dark_vs": "default: #D4D4D4", + "light_vs": "default: #000000", + "hc_black": "default: #FFFFFF" + } + }, + { + "c": "@", + "t": "source.objcpp meta.implementation.objcpp storage.type.objcpp punctuation.definition.storage.type.objcpp", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + }, + { + "c": "end", + "t": "source.objcpp meta.implementation.objcpp storage.type.objcpp", + "r": { + "dark_plus": "storage.type: #569CD6", + "light_plus": "storage.type: #0000FF", + "dark_vs": "storage.type: #569CD6", + "light_vs": "storage.type: #0000FF", + "hc_black": "storage.type: #569CD6" + } + } +] \ No newline at end of file diff --git a/extensions/package.json b/extensions/package.json index 8d41ef689..52ece5e20 100644 --- a/extensions/package.json +++ b/extensions/package.json @@ -3,9 +3,9 @@ "version": "0.0.1", "description": "Dependencies shared by all extensions", "dependencies": { - "typescript": "3.4.5" + "typescript": "3.5.2" }, "scripts": { "postinstall": "node ./postinstall" } -} \ No newline at end of file +} diff --git a/extensions/perl/cgmanifest.json b/extensions/perl/cgmanifest.json index 83d911076..b7c850dd1 100644 --- a/extensions/perl/cgmanifest.json +++ b/extensions/perl/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "textmate/perl.tmbundle", "repositoryUrl": "https://github.com/textmate/perl.tmbundle", - "commitHash": "80826abe75250286c2a1a07958e50e8551d3f50c" + "commitHash": "d9841a0878239fa43f88c640f8d458590f97e8f5" } }, "licenseDetail": [ diff --git a/extensions/perl/package.json b/extensions/perl/package.json index e8dfd7eac..5676e219f 100644 --- a/extensions/perl/package.json +++ b/extensions/perl/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "*" }, "scripts": { "update-grammar": "node ../../build/npm/update-grammar.js textmate/perl.tmbundle Syntaxes/Perl.plist ./syntaxes/perl.tmLanguage.json Syntaxes/Perl%206.tmLanguage ./syntaxes/perl6.tmLanguage.json" diff --git a/extensions/php-language-features/package.json b/extensions/php-language-features/package.json index 28ccad47d..8172c6bec 100644 --- a/extensions/php-language-features/package.json +++ b/extensions/php-language-features/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "icon": "icons/logo.png", "engines": { "vscode": "0.10.x" @@ -37,7 +38,8 @@ "null" ], "default": null, - "description": "%configuration.validate.executablePath%" + "description": "%configuration.validate.executablePath%", + "scope": "machine" }, "php.validate.run": { "type": "string", @@ -80,6 +82,6 @@ "vscode-nls": "^4.0.0" }, "devDependencies": { - "@types/node": "^10.12.21" + "@types/node": "^10.14.8" } } diff --git a/extensions/php-language-features/yarn.lock b/extensions/php-language-features/yarn.lock index 1bcd757b8..e6247e292 100644 --- a/extensions/php-language-features/yarn.lock +++ b/extensions/php-language-features/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@types/node@^10.12.21": - version "10.12.21" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.21.tgz#7e8a0c34cf29f4e17a36e9bd0ea72d45ba03908e" - integrity sha512-CBgLNk4o3XMnqMc0rhb6lc77IwShMEglz05deDcn2lQxyXEZivfwgYJu7SMha9V5XcrP6qZuevTHV/QrN2vjKQ== +"@types/node@^10.14.8": + version "10.14.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9" + integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw== vscode-nls@^4.0.0: version "4.0.0" diff --git a/extensions/php/.vscodeignore b/extensions/php/.vscodeignore index 98efc0327..5da0ed79e 100644 --- a/extensions/php/.vscodeignore +++ b/extensions/php/.vscodeignore @@ -4,3 +4,4 @@ out/test/** src/** tsconfig.json cgmanifest.json +.vscode \ No newline at end of file diff --git a/extensions/php/build/update-grammar.js b/extensions/php/build/update-grammar.js index a6bf6d527..58b1207a4 100644 --- a/extensions/php/build/update-grammar.js +++ b/extensions/php/build/update-grammar.js @@ -23,16 +23,40 @@ function adaptInjectionScope(grammar) { // Workaround for https://github.com/Microsoft/vscode/issues/40279 // and https://github.com/Microsoft/vscode-textmate/issues/59 function fixBadRegex(grammar) { + function fail(msg) { + throw new Error(`fixBadRegex callback couldn't patch ${msg}. It may be obsolete`); + } + const scopeResolution = grammar.repository['scope-resolution']; if (scopeResolution) { const match = scopeResolution.patterns[0].match; if (match === '(?i)([a-z_\\x{7f}-\\x{7fffffff}\\\\][a-z0-9_\\x{7f}-\\x{7fffffff}\\\\]*)(?=\\s*::)') { scopeResolution.patterns[0].match = '([A-Za-z_\\x{7f}-\\x{7fffffff}\\\\][A-Za-z0-9_\\x{7f}-\\x{7fffffff}\\\\]*)(?=\\s*::)'; - return; + } else { + fail('scope-resolution.match'); } + } else { + fail('scope-resolution'); } - throw new Error(`fixBadRegex callback couldn't patch the regex. It may be obsolete`); + const functionCall = grammar.repository['function-call']; + if (functionCall) { + const begin0 = functionCall.patterns[0].begin; + if (begin0 === '(?xi)\n(\n \\\\?(?{1,5})}", + "name": "constant.character.escape.powershell" + }, + { + "match": "`u(?:\\{[0-9a-fA-F]{,6}.)?", + "name": "invalid.character.escape.powershell" + } + ] + }, "function": { "begin": "^(?:\\s*+)(?i)(function|filter|configuration|workflow)\\s+(?:(global|local|script|private):)?((?:\\p{L}|\\d|_|-|\\.)+)", "beginCaptures": { @@ -677,7 +645,7 @@ { "captures": { "0": { - "name": "support.constant.automatic.powershell" + "name": "support.variable.automatic.powershell" }, "1": { "name": "punctuation.definition.variable.powershell" @@ -687,7 +655,7 @@ } }, "comment": "Automatic variables are not constants, but they are read-only. In monokai (default) color schema support.variable doesn't have color, so we use constant.", - "match": "(\\$)(?i:(\\$|\\^|\\?|_|Args|ConsoleFileName|Event|EventArgs|EventSubscriber|ForEach|Input|LastExitCode|Matches|MyInvocation|NestedPromptLevel|Profile|PSBoundParameters|PsCmdlet|PsCulture|PSDebugContext|PSItem|PSCommandPath|PSScriptRoot|PsUICulture|Pwd|Sender|SourceArgs|SourceEventArgs|StackTrace|Switch|This))((?:\\.(?:\\p{L}|\\d|_)+)*\\b)?\\b" + "match": "(\\$)((?:[$^?])|(?i:_|Args|ConsoleFileName|Event|EventArgs|EventSubscriber|ForEach|Input|LastExitCode|Matches|MyInvocation|NestedPromptLevel|Profile|PSBoundParameters|PsCmdlet|PsCulture|PSDebugContext|PSItem|PSCommandPath|PSScriptRoot|PsUICulture|Pwd|Sender|SourceArgs|SourceEventArgs|StackTrace|Switch|This)\\b)((?:\\.(?:\\p{L}|\\d|_)+)*\\b)?" }, { "captures": { @@ -865,7 +833,7 @@ } }, "comment": "Automatic variables are not constants, but they are read-only...", - "match": "(\\$)(?i:(\\$|\\^|\\?|_|Args|ConsoleFileName|Event|EventArgs|EventSubscriber|ForEach|Input|LastExitCode|Matches|MyInvocation|NestedPromptLevel|Profile|PSBoundParameters|PsCmdlet|PsCulture|PSDebugContext|PSItem|PSCommandPath|PSScriptRoot|PsUICulture|Pwd|Sender|SourceArgs|SourceEventArgs|StackTrace|Switch|This))\\b" + "match": "(\\$)((?:[$^?])|(?i:_|Args|ConsoleFileName|Event|EventArgs|EventSubscriber|ForEach|Input|LastExitCode|Matches|MyInvocation|NestedPromptLevel|Profile|PSBoundParameters|PsCmdlet|PsCulture|PSDebugContext|PSItem|PSCommandPath|PSScriptRoot|PsUICulture|Pwd|Sender|SourceArgs|SourceEventArgs|StackTrace|Switch|This)\\b)" }, { "captures": { @@ -897,7 +865,7 @@ "name": "variable.other.member.powershell" } }, - "match": "(?i:(\\$|@)(global|local|private|script|using|workflow):((?:\\p{L}|\\d|_)+))" + "match": "(?i:(\\$)(global|local|private|script|using|workflow):((?:\\p{L}|\\d|_)+))" }, { "captures": { @@ -1023,9 +991,6 @@ { "include": "#variableNoProperty" }, - { - "include": "#variable" - }, { "include": "#doubleQuotedStringEscapes" }, diff --git a/extensions/powershell/test/colorize-results/test_ps1.json b/extensions/powershell/test/colorize-results/test_ps1.json index fd82cda53..e41d13064 100644 --- a/extensions/powershell/test/colorize-results/test_ps1.json +++ b/extensions/powershell/test/colorize-results/test_ps1.json @@ -716,24 +716,24 @@ }, { "c": "$", - "t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell support.constant.automatic.powershell punctuation.definition.variable.powershell", + "t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell support.variable.automatic.powershell punctuation.definition.variable.powershell", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", + "dark_plus": "support.variable: #9CDCFE", + "light_plus": "support.variable: #001080", "dark_vs": "default: #D4D4D4", "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "hc_black": "support.variable: #9CDCFE" } }, { "c": "_", - "t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell support.constant.automatic.powershell", + "t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell support.variable.automatic.powershell", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", + "dark_plus": "support.variable: #9CDCFE", + "light_plus": "support.variable: #001080", "dark_vs": "default: #D4D4D4", "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "hc_black": "support.variable: #9CDCFE" } }, { @@ -1090,24 +1090,24 @@ }, { "c": "$", - "t": "source.powershell meta.scriptblock.powershell interpolated.simple.source.powershell support.constant.automatic.powershell punctuation.definition.variable.powershell", + "t": "source.powershell meta.scriptblock.powershell interpolated.simple.source.powershell support.variable.automatic.powershell punctuation.definition.variable.powershell", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", + "dark_plus": "support.variable: #9CDCFE", + "light_plus": "support.variable: #001080", "dark_vs": "default: #D4D4D4", "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "hc_black": "support.variable: #9CDCFE" } }, { "c": "_", - "t": "source.powershell meta.scriptblock.powershell interpolated.simple.source.powershell support.constant.automatic.powershell", + "t": "source.powershell meta.scriptblock.powershell interpolated.simple.source.powershell support.variable.automatic.powershell", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", + "dark_plus": "support.variable: #9CDCFE", + "light_plus": "support.variable: #001080", "dark_vs": "default: #D4D4D4", "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "hc_black": "support.variable: #9CDCFE" } }, { @@ -1299,24 +1299,24 @@ }, { "c": "$", - "t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell interpolated.simple.source.powershell support.constant.automatic.powershell punctuation.definition.variable.powershell", + "t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell interpolated.simple.source.powershell support.variable.automatic.powershell punctuation.definition.variable.powershell", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", + "dark_plus": "support.variable: #9CDCFE", + "light_plus": "support.variable: #001080", "dark_vs": "default: #D4D4D4", "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "hc_black": "support.variable: #9CDCFE" } }, { "c": "_", - "t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell interpolated.simple.source.powershell support.constant.automatic.powershell", + "t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell interpolated.simple.source.powershell support.variable.automatic.powershell", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", + "dark_plus": "support.variable: #9CDCFE", + "light_plus": "support.variable: #001080", "dark_vs": "default: #D4D4D4", "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "hc_black": "support.variable: #9CDCFE" } }, { @@ -1486,24 +1486,24 @@ }, { "c": "$", - "t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell meta.scriptblock.powershell interpolated.simple.source.powershell support.constant.automatic.powershell punctuation.definition.variable.powershell", + "t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell meta.scriptblock.powershell interpolated.simple.source.powershell support.variable.automatic.powershell punctuation.definition.variable.powershell", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", + "dark_plus": "support.variable: #9CDCFE", + "light_plus": "support.variable: #001080", "dark_vs": "default: #D4D4D4", "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "hc_black": "support.variable: #9CDCFE" } }, { "c": "matches", - "t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell meta.scriptblock.powershell interpolated.simple.source.powershell support.constant.automatic.powershell", + "t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell meta.scriptblock.powershell interpolated.simple.source.powershell support.variable.automatic.powershell", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", + "dark_plus": "support.variable: #9CDCFE", + "light_plus": "support.variable: #001080", "dark_vs": "default: #D4D4D4", "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "hc_black": "support.variable: #9CDCFE" } }, { @@ -1563,24 +1563,24 @@ }, { "c": "$", - "t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell meta.scriptblock.powershell interpolated.simple.source.powershell support.constant.automatic.powershell punctuation.definition.variable.powershell", + "t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell meta.scriptblock.powershell interpolated.simple.source.powershell support.variable.automatic.powershell punctuation.definition.variable.powershell", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", + "dark_plus": "support.variable: #9CDCFE", + "light_plus": "support.variable: #001080", "dark_vs": "default: #D4D4D4", "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "hc_black": "support.variable: #9CDCFE" } }, { "c": "matches", - "t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell meta.scriptblock.powershell interpolated.simple.source.powershell support.constant.automatic.powershell", + "t": "source.powershell meta.scriptblock.powershell meta.scriptblock.powershell meta.scriptblock.powershell interpolated.simple.source.powershell support.variable.automatic.powershell", "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", + "dark_plus": "support.variable: #9CDCFE", + "light_plus": "support.variable: #001080", "dark_vs": "default: #D4D4D4", "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" + "hc_black": "support.variable: #9CDCFE" } }, { diff --git a/extensions/pug/package.json b/extensions/pug/package.json index 270cc4b5e..19049be77 100644 --- a/extensions/pug/package.json +++ b/extensions/pug/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "*" }, "scripts": { "update-grammar": "node ../../build/npm/update-grammar.js davidrios/pug-tmbundle Syntaxes/Pug.JSON-tmLanguage ./syntaxes/pug.tmLanguage.json" diff --git a/extensions/pug/test/colorize-results/test_pug.json b/extensions/pug/test/colorize-results/test_pug.json index ef42ebe54..a022fd80c 100644 --- a/extensions/pug/test/colorize-results/test_pug.json +++ b/extensions/pug/test/colorize-results/test_pug.json @@ -848,7 +848,7 @@ }, { "c": "user", - "t": "text.pug meta.control.flow.pug variable.other.readwrite.js", + "t": "text.pug meta.control.flow.pug js.embedded.control.flow.pug variable.other.readwrite.js", "r": { "dark_plus": "variable: #9CDCFE", "light_plus": "variable: #001080", @@ -1617,7 +1617,7 @@ } }, { - "c": " ", + "c": " samp", "t": "text.pug inline.pug", "r": { "dark_plus": "default: #D4D4D4", @@ -1627,17 +1627,6 @@ "hc_black": "default: #FFFFFF" } }, - { - "c": "samp", - "t": "text.pug inline.pug tag.inline.pug meta.tag.other entity.name.tag.pug", - "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.pug inline.pug entity.name.function.pug", @@ -1683,51 +1672,7 @@ } }, { - "c": " ", - "t": "text.pug inline.pug", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "This", - "t": "text.pug inline.pug tag.inline.pug meta.tag.other entity.name.tag.pug", - "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.pug inline.pug", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "is", - "t": "text.pug inline.pug tag.inline.pug meta.tag.other entity.name.tag.pug", - "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": " ", + "c": " This is sample text", "t": "text.pug inline.pug", "r": { "dark_plus": "default: #D4D4D4", @@ -1737,39 +1682,6 @@ "hc_black": "default: #FFFFFF" } }, - { - "c": "sample", - "t": "text.pug inline.pug tag.inline.pug meta.tag.other entity.name.tag.pug", - "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.pug inline.pug", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "text", - "t": "text.pug inline.pug tag.inline.pug meta.tag.other entity.name.tag.pug", - "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.pug inline.pug entity.name.function.pug", diff --git a/extensions/python/.vscodeignore b/extensions/python/.vscodeignore index 89fb2149d..4d5a14fc9 100644 --- a/extensions/python/.vscodeignore +++ b/extensions/python/.vscodeignore @@ -1,4 +1,6 @@ test/** src/** tsconfig.json +extension.webpack.config.js cgmanifest.json +.vscode \ No newline at end of file diff --git a/extensions/python/extension.webpack.config.js b/extensions/python/extension.webpack.config.js new file mode 100644 index 000000000..1467031c5 --- /dev/null +++ b/extensions/python/extension.webpack.config.js @@ -0,0 +1,17 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +//@ts-check + +'use strict'; + +const withDefaults = require('../shared.webpack.config'); + +module.exports = withDefaults({ + context: __dirname, + entry: { + pythonMain: './src/pythonMain.ts' + } +}); diff --git a/extensions/python/package.json b/extensions/python/package.json index 53ca25bd8..645cba2ba 100644 --- a/extensions/python/package.json +++ b/extensions/python/package.json @@ -4,14 +4,16 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "*" }, "activationEvents": ["onLanguage:python"], "main": "./out/pythonMain", "contributes": { "languages": [{ "id": "python", - "extensions": [ ".py", ".rpy", ".pyw", ".cpy", ".gyp", ".gypi", ".snakefile", ".smk", ".pyi", ".ipy"], + "extensions": [ ".py", ".rpy", ".pyw", ".cpy", ".gyp", ".gypi", ".pyi", ".ipy"], "aliases": [ "Python", "py" ], + "filenames": [ "Snakefile" ], "firstLine": "^#!\\s*/.*\\bpython[0-9.-]*\\b", "configuration": "./language-configuration.json" }], diff --git a/extensions/r/package.json b/extensions/r/package.json index c9b682918..63ff6a6dc 100644 --- a/extensions/r/package.json +++ b/extensions/r/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "*" }, "scripts": { "update-grammar": "node ../../build/npm/update-grammar.js Ikuyadeu/vscode-R syntax/r.json ./syntaxes/r.tmLanguage.json" diff --git a/extensions/razor/package.json b/extensions/razor/package.json index f4432ee98..98147bed6 100644 --- a/extensions/razor/package.json +++ b/extensions/razor/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "0.10.x" }, @@ -25,7 +26,7 @@ "embeddedLanguages": { "section.embedded.source.cshtml": "csharp", "source.css": "css", - "source.js": "javascript" + "source.js": "javascript" } }] } diff --git a/extensions/ruby/package.json b/extensions/ruby/package.json index 98d66a891..4572f2526 100644 --- a/extensions/ruby/package.json +++ b/extensions/ruby/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "*" }, "scripts": { "update-grammar": "node ../../build/npm/update-grammar.js textmate/ruby.tmbundle Syntaxes/Ruby.plist ./syntaxes/ruby.tmLanguage.json" @@ -11,7 +12,7 @@ "contributes": { "languages": [{ "id": "ruby", - "extensions": [ ".rb", ".rbx", ".rjs", ".gemspec", ".rake", ".ru", ".erb" ], + "extensions": [ ".rb", ".rbx", ".rjs", ".gemspec", ".rake", ".ru", ".erb", ".podspec", ".rbi" ], "filenames": [ "rakefile", "gemfile", "guardfile", "podfile", "capfile" ], "aliases": [ "Ruby", "rb" ], "firstLine": "^#!\\s*/.*\\bruby\\b", diff --git a/extensions/rust/cgmanifest.json b/extensions/rust/cgmanifest.json index c3056722e..5181efba1 100644 --- a/extensions/rust/cgmanifest.json +++ b/extensions/rust/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "language-rust", "repositoryUrl": "https://github.com/zargony/atom-language-rust", - "commitHash": "5238d9834953ed7c58d9b5b9bb0c084c3c11ecd6" + "commitHash": "7d59e2ad79fbe5925bd2fd3bd3857bf9f421ff6f" } }, "license": "MIT", diff --git a/extensions/rust/package.json b/extensions/rust/package.json index 4436da8bc..660783881 100644 --- a/extensions/rust/package.json +++ b/extensions/rust/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "*" }, "scripts": { "update-grammar": "node ../../build/npm/update-grammar.js zargony/atom-language-rust grammars/rust.cson ./syntaxes/rust.tmLanguage.json" diff --git a/extensions/rust/syntaxes/rust.tmLanguage.json b/extensions/rust/syntaxes/rust.tmLanguage.json index 9b7373336..784bd8c9a 100644 --- a/extensions/rust/syntaxes/rust.tmLanguage.json +++ b/extensions/rust/syntaxes/rust.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/zargony/atom-language-rust/commit/5238d9834953ed7c58d9b5b9bb0c084c3c11ecd6", + "version": "https://github.com/zargony/atom-language-rust/commit/7d59e2ad79fbe5925bd2fd3bd3857bf9f421ff6f", "name": "Rust", "scopeName": "source.rust", "patterns": [ @@ -160,7 +160,7 @@ { "comment": "Control keyword", "name": "keyword.control.rust", - "match": "\\b(break|continue|else|if|in|for|loop|match|return|while)\\b" + "match": "\\b(async|await|break|continue|else|if|in|for|loop|match|return|try|while)\\b" }, { "comment": "Keyword", diff --git a/extensions/scss/package.json b/extensions/scss/package.json index 060bda698..39338e30e 100644 --- a/extensions/scss/package.json +++ b/extensions/scss/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "*" }, "scripts": { "update-grammar": "node ../../build/npm/update-grammar.js atom/language-sass grammars/scss.cson ./syntaxes/scss.tmLanguage.json grammars/sassdoc.cson ./syntaxes/sassdoc.tmLanguage.json" diff --git a/extensions/shaderlab/package.json b/extensions/shaderlab/package.json index e20d103f9..d5f1f462f 100644 --- a/extensions/shaderlab/package.json +++ b/extensions/shaderlab/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "*" }, diff --git a/extensions/shared.webpack.config.js b/extensions/shared.webpack.config.js index 8e2288c1e..2fba65c92 100644 --- a/extensions/shared.webpack.config.js +++ b/extensions/shared.webpack.config.js @@ -9,11 +9,17 @@ 'use strict'; const path = require('path'); +const fs = require('fs'); const merge = require('merge-options'); const CopyWebpackPlugin = require('copy-webpack-plugin'); - +const { NLSBundlePlugin } = require('vscode-nls-dev/lib/webpack-bundler'); module.exports = function withDefaults(/**@type WebpackConfig*/extConfig) { + // Need to find the top-most `package.json` file + const folderName = path.relative(__dirname, extConfig.context).split(/[\\\/]/)[0]; + const pkgPath = path.join(__dirname, folderName, 'package.json'); + const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')); + const id = `${pkg.publisher}.${pkg.name}`; /** @type WebpackConfig */ let defaultConfig = { @@ -62,9 +68,11 @@ module.exports = function withDefaults(/**@type WebpackConfig*/extConfig) { // yes, really source maps devtool: 'source-map', plugins: [ + // @ts-ignore new CopyWebpackPlugin([ - { from: './out/**/*', to: '.', ignore: ['*.js', '*.js.map'], flatten: true } - ]) + { from: 'src', to: '.', ignore: ['**/test/**', '*.ts'] } + ]), + new NLSBundlePlugin(id) ], }; diff --git a/extensions/shellscript/language-configuration.json b/extensions/shellscript/language-configuration.json index 01b6a8a28..964623ac4 100644 --- a/extensions/shellscript/language-configuration.json +++ b/extensions/shellscript/language-configuration.json @@ -22,5 +22,11 @@ ["\"", "\""], ["'", "'"], ["`", "`"] - ] -} \ No newline at end of file + ], + "folding": { + "markers": { + "start": "^\\s*#\\s*#?region\\b.*", + "end": "^\\s*#\\s*#?endregion\\b.*" + } + } +} diff --git a/extensions/shellscript/package.json b/extensions/shellscript/package.json index c343b4fd9..a55af2b08 100644 --- a/extensions/shellscript/package.json +++ b/extensions/shellscript/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "*" }, "scripts": { "update-grammar": "node ../../build/npm/update-grammar.js atom/language-shellscript grammars/shell-unix-bash.cson ./syntaxes/shell-unix-bash.tmLanguage.json" @@ -13,8 +14,8 @@ "id": "shellscript", "aliases": ["Shell Script", "shellscript", "bash", "sh", "zsh", "ksh"], "extensions": [".sh", ".bash", ".bashrc", ".bash_aliases", ".bash_profile", ".bash_login", ".ebuild", ".install", ".profile", ".bash_logout", ".zsh", ".zshrc", ".zprofile", ".zlogin", ".zlogout", ".zshenv", ".zsh-theme", ".ksh"], - "filenames": ["PKGBUILD"], - "firstLine": "^#!.*\\b(bash|zsh|sh|tcsh|ksh|ash).*|^#\\s*-\\*-[^*]*mode:\\s*shell-script[^*]*-\\*-", + "filenames": ["APKBUILD", "PKGBUILD"], + "firstLine": "^#!.*\\b(bash|zsh|sh|tcsh|ksh|ash|qsh).*|^#\\s*-\\*-[^*]*mode:\\s*shell-script[^*]*-\\*-", "configuration": "./language-configuration.json", "mimetypes": ["text/x-shellscript"] }], diff --git a/extensions/sql/cgmanifest.json b/extensions/sql/cgmanifest.json index 4cdccf12d..7abcea36e 100644 --- a/extensions/sql/cgmanifest.json +++ b/extensions/sql/cgmanifest.json @@ -6,11 +6,11 @@ "git": { "name": "Microsoft/vscode-mssql", "repositoryUrl": "https://github.com/Microsoft/vscode-mssql", - "commitHash": "cd754662e5607c62ecdc51d2a2dc844546a0bbb6" + "commitHash": "a79741f76fd33bd137a8c28172c9750b978309b6" } }, "license": "MIT", - "version": "1.4.0" + "version": "1.6.0" } ], "version": 1 diff --git a/extensions/sql/package.json b/extensions/sql/package.json index f0256026d..8c283e972 100644 --- a/extensions/sql/package.json +++ b/extensions/sql/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "*" }, "scripts": { "update-grammar": "node ../../build/npm/update-grammar.js Microsoft/vscode-mssql syntaxes/SQL.plist ./syntaxes/sql.tmLanguage.json" diff --git a/extensions/sql/syntaxes/sql.tmLanguage.json b/extensions/sql/syntaxes/sql.tmLanguage.json index d7bc056c6..1dd690378 100644 --- a/extensions/sql/syntaxes/sql.tmLanguage.json +++ b/extensions/sql/syntaxes/sql.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/vscode-mssql/commit/cd754662e5607c62ecdc51d2a2dc844546a0bbb6", + "version": "https://github.com/Microsoft/vscode-mssql/commit/a79741f76fd33bd137a8c28172c9750b978309b6", "name": "SQL", "scopeName": "source.sql", "patterns": [ @@ -17,7 +17,7 @@ "name": "text.bracketed" }, { - "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|between|bigint|binary|binding|bit|block|blocksize|bmk|break|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|close|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|continue_after_error|contract|contract_name|control|conversation|conversation_group_id|conversation_handle|copy|copy_only|count_rows|counter|create(\\s+or\\s+alter)?|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|deallocate|dec|decimal|declare(\\s+cursor)?|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|distinct|distributed|distribution|drop|drop_existing|dts_buffers|dump|durability|dynamic|edition|elements|else|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|execute|exists|expand|expiredate|expiry_date|explicit|external_access|failover|failover_mode|failure_condition_level|fast|fast_forward|fastfirstrow|federated_service_account|fetch|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|goto|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|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|kill|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|open|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|proc(edure)?|procedure_name|profile|provider|query_capture_mode|query_governor_cost_limit|query_optimizer_hotfixes|query_store|queue|quoted_identifier|raiserror|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|reconfigure|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|revert|rewind|rewindonly|returns|robust|role|rollup|root|round_robin|route|row|rowdump|rowguidcol|rowlock|row_terminator|rows|rows_per_batch|rowsets_only|rowterminator|rowversion|rsa_1024|rsa_2048|rsa_3072|rsa_4096|rsa_512|safe|safety|sample|save|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|shutdown|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|truncate|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|waitfor|webmethod|weekday|weight|well_formed_xml|when|while|widechar|widechar_ansi|widenative|windows|with|within|witness|without|without_array_wrapper|workload|wsdl|xact_abort|xlock|xml|xmlschema|xquery|xsinil|zone)\\b", + "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|alter|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|between|bigint|binary|binding|bit|block|blocksize|bmk|break|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|close|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|continue_after_error|contract|contract_name|control|conversation|conversation_group_id|conversation_handle|copy|copy_only|count_rows|counter|create(\\s+or\\s+alter)?|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|deallocate|dec|decimal|declare(\\s+cursor)?|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|distinct|distributed|distribution|drop|drop_existing|dts_buffers|dump|durability|dynamic|edition|elements|else|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|except|exec|executable|execute|exists|expand|expiredate|expiry_date|explicit|external|external_access|failover|failover_mode|failure_condition_level|fast|fast_forward|fastfirstrow|federated_service_account|fetch|field_terminator|fieldterminator|file|filelistonly|filegroup|filename|filestream|filestream_log|filestream_on|filetable|file_format|filter|first_row|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|goto|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|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|intersect|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|kill|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|open|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|proc(edure)?|procedure_name|profile|provider|query_capture_mode|query_governor_cost_limit|query_optimizer_hotfixes|query_store|queue|quoted_identifier|raiserror|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|reconfigure|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|revert|rewind|rewindonly|returns|robust|role|rollup|root|round_robin|route|row|rowdump|rowguidcol|rowlock|row_terminator|rows|rows_per_batch|rowsets_only|rowterminator|rowversion|rsa_1024|rsa_2048|rsa_3072|rsa_4096|rsa_512|safe|safety|sample|save|schema|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|shutdown|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|truncate|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|waitfor|webmethod|weekday|weight|well_formed_xml|when|while|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" }, { diff --git a/extensions/swift/package.json b/extensions/swift/package.json index e4e5380d9..f88ac07ea 100644 --- a/extensions/swift/package.json +++ b/extensions/swift/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "*" }, "scripts": { "update-grammar": "node ../../build/npm/update-grammar.js textmate/swift.tmbundle Syntaxes/Swift.tmLanguage ./syntaxes/swift.tmLanguage.json" diff --git a/extensions/theme-abyss/package.json b/extensions/theme-abyss/package.json index 2d6e6962c..bdeb6a2a6 100644 --- a/extensions/theme-abyss/package.json +++ b/extensions/theme-abyss/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "*" }, "contributes": { "themes": [ diff --git a/extensions/theme-abyss/themes/abyss-color-theme.json b/extensions/theme-abyss/themes/abyss-color-theme.json index 979b62369..43a3ae648 100644 --- a/extensions/theme-abyss/themes/abyss-color-theme.json +++ b/extensions/theme-abyss/themes/abyss-color-theme.json @@ -86,7 +86,9 @@ "name": "Class name", "scope": [ "entity.name.class", - "entity.name.type" + "entity.name.type", + "entity.name.namespace", + "entity.name.scope-resolution" ], "settings": { "fontStyle": "underline", @@ -400,7 +402,7 @@ "statusBar.noFolderBackground": "#10192c", "statusBar.debuggingBackground": "#10192c", // "statusBar.foreground": "", - "statusBarItem.hostBackground": "#0063a5", + "statusBarItem.remoteBackground": "#0063a5", "statusBarItem.prominentBackground": "#0063a5", "statusBarItem.prominentHoverBackground": "#0063a5dd", // "statusBarItem.activeBackground": "", diff --git a/extensions/theme-defaults/fileicons/images/Document_16x.svg b/extensions/theme-defaults/fileicons/images/Document_16x.svg deleted file mode 100644 index 46a9f38cc..000000000 --- a/extensions/theme-defaults/fileicons/images/Document_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/extensions/theme-defaults/fileicons/images/Document_16x_inverse.svg b/extensions/theme-defaults/fileicons/images/Document_16x_inverse.svg deleted file mode 100755 index 14abfb510..000000000 --- a/extensions/theme-defaults/fileicons/images/Document_16x_inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/extensions/theme-defaults/fileicons/images/FolderOpen_16x.svg b/extensions/theme-defaults/fileicons/images/FolderOpen_16x.svg deleted file mode 100644 index 1a3933d63..000000000 --- a/extensions/theme-defaults/fileicons/images/FolderOpen_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/extensions/theme-defaults/fileicons/images/FolderOpen_16x_inverse.svg b/extensions/theme-defaults/fileicons/images/FolderOpen_16x_inverse.svg deleted file mode 100755 index fbf57c927..000000000 --- a/extensions/theme-defaults/fileicons/images/FolderOpen_16x_inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/extensions/theme-defaults/fileicons/images/Folder_16x.svg b/extensions/theme-defaults/fileicons/images/Folder_16x.svg deleted file mode 100644 index 3d64ae71d..000000000 --- a/extensions/theme-defaults/fileicons/images/Folder_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/extensions/theme-defaults/fileicons/images/Folder_16x_inverse.svg b/extensions/theme-defaults/fileicons/images/Folder_16x_inverse.svg deleted file mode 100755 index 13b18d180..000000000 --- a/extensions/theme-defaults/fileicons/images/Folder_16x_inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/extensions/theme-defaults/fileicons/images/RootFolderOpen_16x.svg b/extensions/theme-defaults/fileicons/images/RootFolderOpen_16x.svg deleted file mode 100755 index 20460ec99..000000000 --- a/extensions/theme-defaults/fileicons/images/RootFolderOpen_16x.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/extensions/theme-defaults/fileicons/images/RootFolderOpen_16x_inverse.svg b/extensions/theme-defaults/fileicons/images/RootFolderOpen_16x_inverse.svg deleted file mode 100755 index d1a0fb04b..000000000 --- a/extensions/theme-defaults/fileicons/images/RootFolderOpen_16x_inverse.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/extensions/theme-defaults/fileicons/images/RootFolder_16x.svg b/extensions/theme-defaults/fileicons/images/RootFolder_16x.svg deleted file mode 100755 index 9a049f623..000000000 --- a/extensions/theme-defaults/fileicons/images/RootFolder_16x.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/extensions/theme-defaults/fileicons/images/RootFolder_16x_inverse.svg b/extensions/theme-defaults/fileicons/images/RootFolder_16x_inverse.svg deleted file mode 100755 index 037212729..000000000 --- a/extensions/theme-defaults/fileicons/images/RootFolder_16x_inverse.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/extensions/theme-defaults/fileicons/images/document-dark.svg b/extensions/theme-defaults/fileicons/images/document-dark.svg new file mode 100644 index 000000000..5ed5762a1 --- /dev/null +++ b/extensions/theme-defaults/fileicons/images/document-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/extensions/theme-defaults/fileicons/images/document-light.svg b/extensions/theme-defaults/fileicons/images/document-light.svg new file mode 100644 index 000000000..ad54e13b1 --- /dev/null +++ b/extensions/theme-defaults/fileicons/images/document-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/extensions/theme-defaults/fileicons/images/folder-dark.svg b/extensions/theme-defaults/fileicons/images/folder-dark.svg new file mode 100644 index 000000000..43d454e7e --- /dev/null +++ b/extensions/theme-defaults/fileicons/images/folder-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/extensions/theme-defaults/fileicons/images/folder-light.svg b/extensions/theme-defaults/fileicons/images/folder-light.svg new file mode 100644 index 000000000..8daecdac6 --- /dev/null +++ b/extensions/theme-defaults/fileicons/images/folder-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/extensions/theme-defaults/fileicons/images/folder-open-dark.svg b/extensions/theme-defaults/fileicons/images/folder-open-dark.svg new file mode 100644 index 000000000..6bc1c584e --- /dev/null +++ b/extensions/theme-defaults/fileicons/images/folder-open-dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/extensions/theme-defaults/fileicons/images/folder-open-light.svg b/extensions/theme-defaults/fileicons/images/folder-open-light.svg new file mode 100644 index 000000000..0a50339b6 --- /dev/null +++ b/extensions/theme-defaults/fileicons/images/folder-open-light.svg @@ -0,0 +1,4 @@ + + + + diff --git a/extensions/theme-defaults/fileicons/images/root-folder-dark.svg b/extensions/theme-defaults/fileicons/images/root-folder-dark.svg new file mode 100644 index 000000000..cdb770c86 --- /dev/null +++ b/extensions/theme-defaults/fileicons/images/root-folder-dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/extensions/theme-defaults/fileicons/images/root-folder-light.svg b/extensions/theme-defaults/fileicons/images/root-folder-light.svg new file mode 100644 index 000000000..82a029469 --- /dev/null +++ b/extensions/theme-defaults/fileicons/images/root-folder-light.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/extensions/theme-defaults/fileicons/images/root-folder-open-dark.svg b/extensions/theme-defaults/fileicons/images/root-folder-open-dark.svg new file mode 100644 index 000000000..472def3da --- /dev/null +++ b/extensions/theme-defaults/fileicons/images/root-folder-open-dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/extensions/theme-defaults/fileicons/images/root-folder-open-light.svg b/extensions/theme-defaults/fileicons/images/root-folder-open-light.svg new file mode 100644 index 000000000..d2363bfae --- /dev/null +++ b/extensions/theme-defaults/fileicons/images/root-folder-open-light.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/extensions/theme-defaults/fileicons/vs_minimal-icon-theme.json b/extensions/theme-defaults/fileicons/vs_minimal-icon-theme.json index 9c9f60b6e..7a1780653 100644 --- a/extensions/theme-defaults/fileicons/vs_minimal-icon-theme.json +++ b/extensions/theme-defaults/fileicons/vs_minimal-icon-theme.json @@ -1,34 +1,34 @@ { "iconDefinitions": { "_root_folder_dark": { - "iconPath": "./images/RootFolder_16x_inverse.svg" + "iconPath": "./images/root-folder-dark.svg" }, "_root_folder_open_dark": { - "iconPath": "./images/RootFolderOpen_16x_inverse.svg" + "iconPath": "./images/root-folder-open-dark.svg" }, "_folder_dark": { - "iconPath": "./images/Folder_16x_inverse.svg" + "iconPath": "./images/folder-dark.svg" }, "_folder_open_dark": { - "iconPath": "./images/FolderOpen_16x_inverse.svg" + "iconPath": "./images/folder-open-dark.svg" }, "_file_dark": { - "iconPath": "./images/Document_16x_inverse.svg" + "iconPath": "./images/document-dark.svg" }, "_root_folder": { - "iconPath": "./images/RootFolder_16x.svg" + "iconPath": "./images/root-folder-light.svg" }, "_root_folder_open": { - "iconPath": "./images/RootFolderOpen_16x.svg" + "iconPath": "./images/root-folder-open-light.svg" }, "_folder_light": { - "iconPath": "./images/Folder_16x.svg" + "iconPath": "./images/folder-light.svg" }, "_folder_open_light": { - "iconPath": "./images/FolderOpen_16x.svg" + "iconPath": "./images/folder-open-light.svg" }, "_file_light": { - "iconPath": "./images/Document_16x.svg" + "iconPath": "./images/document-light.svg" } }, diff --git a/extensions/theme-defaults/package.json b/extensions/theme-defaults/package.json index bbc13a472..56d5fa3f4 100644 --- a/extensions/theme-defaults/package.json +++ b/extensions/theme-defaults/package.json @@ -5,6 +5,7 @@ "categories": [ "Themes" ], "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "*" }, "contributes": { "themes": [ diff --git a/extensions/theme-defaults/themes/dark_defaults.json b/extensions/theme-defaults/themes/dark_defaults.json index 276a71d0f..00c2ac8c3 100644 --- a/extensions/theme-defaults/themes/dark_defaults.json +++ b/extensions/theme-defaults/themes/dark_defaults.json @@ -15,6 +15,8 @@ "settings.textInputBackground": "#292929", "settings.numberInputBackground": "#292929", "menu.background": "#252526", - "menu.foreground": "#CCCCCC" + "menu.foreground": "#CCCCCC", + "statusBarItem.remoteForeground": "#FFF", + "statusBarItem.remoteBackground": "#16825D" } } \ No newline at end of file diff --git a/extensions/theme-defaults/themes/dark_plus.json b/extensions/theme-defaults/themes/dark_plus.json index e73cc3a09..1898153ba 100644 --- a/extensions/theme-defaults/themes/dark_plus.json +++ b/extensions/theme-defaults/themes/dark_plus.json @@ -21,6 +21,8 @@ "support.class", "support.type", "entity.name.type", + "entity.name.namespace", + "entity.name.scope-resolution", "entity.name.class", "storage.type.numeric.go", "storage.type.byte.go", @@ -67,10 +69,10 @@ } }, { - "name": "Control flow keywords", + "name": "Control flow / Special keywords", "scope": [ "keyword.control", - "keyword.operator.new.cpp", + "source.cpp keyword.operator.new", "keyword.operator.delete", "keyword.other.using", "keyword.other.operator" diff --git a/extensions/theme-defaults/themes/hc_black.json b/extensions/theme-defaults/themes/hc_black.json index 0b20650d8..8119256d5 100644 --- a/extensions/theme-defaults/themes/hc_black.json +++ b/extensions/theme-defaults/themes/hc_black.json @@ -5,7 +5,7 @@ "colors": { "selection.background": "#008000", "editor.selectionBackground": "#FFFFFF", - "statusBarItem.hostBackground": "#00000000" + "statusBarItem.remoteBackground": "#00000000" }, "tokenColors": [ { @@ -26,6 +26,8 @@ "support.class", "support.type", "entity.name.type", + "entity.name.namespace", + "entity.name.scope-resolution", "entity.name.class", "storage.type.cs", "storage.type.generic.cs", @@ -65,11 +67,11 @@ } }, { - "name": "Control flow keywords", + "name": "Control flow / Special keywords", "scope": [ "keyword.control", - "keyword.operator.new.cpp", - "keyword.operator.delete.cpp", + "source.cpp keyword.operator.new", + "source.cpp keyword.operator.delete", "keyword.other.using", "keyword.other.operator" ], diff --git a/extensions/theme-defaults/themes/hc_black_defaults.json b/extensions/theme-defaults/themes/hc_black_defaults.json index 54211a5b8..9d11138a9 100644 --- a/extensions/theme-defaults/themes/hc_black_defaults.json +++ b/extensions/theme-defaults/themes/hc_black_defaults.json @@ -6,7 +6,7 @@ "editor.foreground": "#FFFFFF", "editorIndentGuide.background": "#FFFFFF", "editorIndentGuide.activeBackground": "#FFFFFF", - "statusBarItem.hostBackground": "#00000000", + "statusBarItem.remoteBackground": "#00000000", "sideBarTitle.foreground": "#FFFFFF" }, "settings": [ diff --git a/extensions/theme-defaults/themes/light_defaults.json b/extensions/theme-defaults/themes/light_defaults.json index 91c5fb1d9..e28c9b8ed 100644 --- a/extensions/theme-defaults/themes/light_defaults.json +++ b/extensions/theme-defaults/themes/light_defaults.json @@ -14,6 +14,8 @@ "list.hoverBackground": "#E8E8E8", "input.placeholderForeground": "#767676", "settings.textInputBorder": "#CECECE", - "settings.numberInputBorder": "#CECECE" + "settings.numberInputBorder": "#CECECE", + "statusBarItem.remoteForeground": "#FFF", + "statusBarItem.remoteBackground": "#16825D" } } \ No newline at end of file diff --git a/extensions/theme-defaults/themes/light_plus.json b/extensions/theme-defaults/themes/light_plus.json index ce23ed901..7138f045d 100644 --- a/extensions/theme-defaults/themes/light_plus.json +++ b/extensions/theme-defaults/themes/light_plus.json @@ -21,6 +21,8 @@ "support.class", "support.type", "entity.name.type", + "entity.name.namespace", + "entity.name.scope-resolution", "entity.name.class", "storage.type.numeric.go", "storage.type.byte.go", @@ -67,11 +69,11 @@ } }, { - "name": "Control flow keywords", + "name": "Control flow / Special keywords", "scope": [ "keyword.control", - "keyword.operator.new.cpp", - "keyword.operator.delete.cpp", + "source.cpp keyword.operator.new", + "source.cpp keyword.operator.delete", "keyword.other.using", "keyword.other.operator" ], diff --git a/extensions/theme-kimbie-dark/package.json b/extensions/theme-kimbie-dark/package.json index 06682901e..1031c34d2 100644 --- a/extensions/theme-kimbie-dark/package.json +++ b/extensions/theme-kimbie-dark/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "*" }, "contributes": { "themes": [ 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 0d7753ae4..4b0eb5bdf 100644 --- a/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json +++ b/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json @@ -27,7 +27,7 @@ "statusBar.background": "#423523", "statusBar.debuggingBackground": "#423523", "statusBar.noFolderBackground": "#423523", - "statusBarItem.hostBackground": "#6e583b", + "statusBarItem.remoteBackground": "#6e583b", "activityBar.background": "#221a0f", "activityBar.foreground": "#d3af86", "sideBar.background": "#362712", @@ -147,7 +147,9 @@ "scope": [ "support.class", "entity.name.class", - "entity.name.type" + "entity.name.type", + "entity.name.namespace", + "entity.name.scope-resolution" ], "settings": { "foreground": "#f06431" diff --git a/extensions/theme-monokai-dimmed/package.json b/extensions/theme-monokai-dimmed/package.json index f64721a89..66c4711d9 100644 --- a/extensions/theme-monokai-dimmed/package.json +++ b/extensions/theme-monokai-dimmed/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "*" }, 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 1aad04028..5f5e5cff9 100644 --- a/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json +++ b/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json @@ -31,7 +31,7 @@ "statusBar.debuggingBackground": "#505050", "statusBar.noFolderBackground": "#505050", "titleBar.activeBackground": "#505050", - "statusBarItem.hostBackground": "#3655b5", + "statusBarItem.remoteBackground": "#3655b5", "activityBar.background": "#353535", "activityBar.foreground": "#ffffff", "activityBarBadge.background": "#3655b5", @@ -143,7 +143,7 @@ }, { "name": "Class name", - "scope": "entity.name.class, entity.name.type", + "scope": "entity.name.class, entity.name.type, entity.name.namespace, entity.name.scope-resolution", "settings": { "fontStyle": "", "foreground": "#9B0000", @@ -255,7 +255,7 @@ } }, { - "name": "Keyword Control", + "name": "Keyword Control / Special", "scope": [ "keyword.control", "keyword.operator.new.cpp", diff --git a/extensions/theme-monokai/package.json b/extensions/theme-monokai/package.json index 550f22933..13b2db10d 100644 --- a/extensions/theme-monokai/package.json +++ b/extensions/theme-monokai/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "*" }, diff --git a/extensions/theme-monokai/themes/monokai-color-theme.json b/extensions/theme-monokai/themes/monokai-color-theme.json index a203ace74..c16fa3c55 100644 --- a/extensions/theme-monokai/themes/monokai-color-theme.json +++ b/extensions/theme-monokai/themes/monokai-color-theme.json @@ -50,7 +50,7 @@ "statusBar.background": "#414339", "statusBar.noFolderBackground": "#414339", "statusBar.debuggingBackground": "#75715E", - "statusBarItem.hostBackground": "#AC6218", + "statusBarItem.remoteBackground": "#AC6218", "activityBar.background": "#272822", "activityBar.foreground": "#f8f8f2", "activityBar.dropBackground": "#414339", @@ -205,7 +205,7 @@ }, { "name": "Class name", - "scope": "entity.name.type, entity.name.class", + "scope": "entity.name.type, entity.name.class, entity.name.namespace, entity.name.scope-resolution", "settings": { "fontStyle": "underline", "foreground": "#A6E22E" diff --git a/extensions/theme-quietlight/package.json b/extensions/theme-quietlight/package.json index 0620f7308..0263925ee 100644 --- a/extensions/theme-quietlight/package.json +++ b/extensions/theme-quietlight/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "*" }, diff --git a/extensions/theme-quietlight/themes/quietlight-color-theme.json b/extensions/theme-quietlight/themes/quietlight-color-theme.json index 467c81df9..38681612b 100644 --- a/extensions/theme-quietlight/themes/quietlight-color-theme.json +++ b/extensions/theme-quietlight/themes/quietlight-color-theme.json @@ -125,6 +125,8 @@ "name": "Classes", "scope": [ "entity.name.type", + "entity.name.namespace", + "entity.name.scope-resolution", "entity.other.inherited-class", "support.class" ], @@ -516,7 +518,7 @@ "statusBar.background": "#705697", "statusBar.noFolderBackground": "#705697", "statusBar.debuggingBackground": "#705697", - "statusBarItem.hostBackground": "#4e3c69", + "statusBarItem.remoteBackground": "#4e3c69", "activityBar.background": "#EDEDF5", "activityBar.foreground": "#705697", "activityBarBadge.background": "#705697", diff --git a/extensions/theme-red/package.json b/extensions/theme-red/package.json index 4b4f294fc..ba751a33e 100644 --- a/extensions/theme-red/package.json +++ b/extensions/theme-red/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "*" }, "contributes": { "themes": [ diff --git a/extensions/theme-red/themes/Red-color-theme.json b/extensions/theme-red/themes/Red-color-theme.json index 31fa8a1b6..18e5786a8 100644 --- a/extensions/theme-red/themes/Red-color-theme.json +++ b/extensions/theme-red/themes/Red-color-theme.json @@ -9,7 +9,7 @@ "sideBar.background": "#330000", "statusBar.background": "#700000", "statusBar.noFolderBackground": "#700000", - "statusBarItem.hostBackground": "#c33", + "statusBarItem.remoteBackground": "#c33", "editorGroupHeader.tabsBackground": "#330000", "titleBar.activeBackground": "#770000", "titleBar.inactiveBackground": "#772222", diff --git a/extensions/theme-seti/build/update-icon-theme.js b/extensions/theme-seti/build/update-icon-theme.js index c60de74fe..6819e8533 100644 --- a/extensions/theme-seti/build/update-icon-theme.js +++ b/extensions/theme-seti/build/update-icon-theme.js @@ -10,7 +10,7 @@ let fs = require('fs'); let https = require('https'); let url = require('url'); -// list of languagesIs not shipped with VSCode. The information is used to associate an icon with a langauge association +// list of languagesIs not shipped with VSCode. The information is used to associate an icon with a language association let nonBuiltInLanguages = { // { fileNames, extensions } "r": { extensions: ['r', 'rhistory', 'rprofile', 'rt'] }, "argdown": { extensions: ['ad', 'adown', 'argdown', 'argdn'] }, @@ -35,7 +35,7 @@ let nonBuiltInLanguages = { // { fileNames, extensions } "todo": { fileNames: ['todo'] } }; -let FROM_DISK = false; // set to true to take content from a repo checkedout next to the vscode repo +let FROM_DISK = true; // set to true to take content from a repo checked out next to the vscode repo let font, fontMappingsFile, fileAssociationFile, colorsFile; if (!FROM_DISK) { diff --git a/extensions/theme-seti/cgmanifest.json b/extensions/theme-seti/cgmanifest.json index 2b449830f..c742c019e 100644 --- a/extensions/theme-seti/cgmanifest.json +++ b/extensions/theme-seti/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "seti-ui", "repositoryUrl": "https://github.com/jesseweed/seti-ui", - "commitHash": "89175d7f9e0c70cd325b80a18a3c77fc8eb7c798" + "commitHash": "904c16acced1134a81b31d71d60293288c31334b" } }, "version": "0.1.0" diff --git a/extensions/theme-seti/icons/seti.woff b/extensions/theme-seti/icons/seti.woff index e590d77f6..b85727d01 100644 Binary files a/extensions/theme-seti/icons/seti.woff and b/extensions/theme-seti/icons/seti.woff differ diff --git a/extensions/theme-seti/icons/vs-seti-icon-theme.json b/extensions/theme-seti/icons/vs-seti-icon-theme.json index 4aec20740..2b5d276a5 100644 --- a/extensions/theme-seti/icons/vs-seti-icon-theme.json +++ b/extensions/theme-seti/icons/vs-seti-icon-theme.json @@ -206,6 +206,14 @@ "fontCharacter": "\\E017", "fontColor": "#a074c4" }, + "_cpp_2_light": { + "fontCharacter": "\\E017", + "fontColor": "#b7b73b" + }, + "_cpp_2": { + "fontCharacter": "\\E017", + "fontColor": "#cbcb41" + }, "_crystal_light": { "fontCharacter": "\\E018", "fontColor": "#bfc2c1" @@ -246,999 +254,1103 @@ "fontCharacter": "\\E01C", "fontColor": "#cc3e44" }, - "_db_light": { + "_dart_light": { + "fontCharacter": "\\E01D", + "fontColor": "#498ba7" + }, + "_dart": { "fontCharacter": "\\E01D", + "fontColor": "#519aba" + }, + "_db_light": { + "fontCharacter": "\\E01E", "fontColor": "#dd4b78" }, "_db": { - "fontCharacter": "\\E01D", + "fontCharacter": "\\E01E", "fontColor": "#f55385" }, "_default_light": { - "fontCharacter": "\\E01E", + "fontCharacter": "\\E01F", "fontColor": "#bfc2c1" }, "_default": { - "fontCharacter": "\\E01E", + "fontCharacter": "\\E01F", "fontColor": "#d4d7d6" }, "_docker_light": { - "fontCharacter": "\\E020", + "fontCharacter": "\\E021", "fontColor": "#498ba7" }, "_docker": { - "fontCharacter": "\\E020", + "fontCharacter": "\\E021", "fontColor": "#519aba" }, "_docker_1_light": { - "fontCharacter": "\\E020", + "fontCharacter": "\\E021", "fontColor": "#455155" }, "_docker_1": { - "fontCharacter": "\\E020", + "fontCharacter": "\\E021", "fontColor": "#4d5a5e" }, "_docker_2_light": { - "fontCharacter": "\\E020", + "fontCharacter": "\\E021", "fontColor": "#7fae42" }, "_docker_2": { - "fontCharacter": "\\E020", + "fontCharacter": "\\E021", "fontColor": "#8dc149" }, "_docker_3_light": { - "fontCharacter": "\\E020", + "fontCharacter": "\\E021", "fontColor": "#dd4b78" }, "_docker_3": { - "fontCharacter": "\\E020", + "fontCharacter": "\\E021", "fontColor": "#f55385" }, "_ejs_light": { - "fontCharacter": "\\E022", + "fontCharacter": "\\E023", "fontColor": "#b7b73b" }, "_ejs": { - "fontCharacter": "\\E022", + "fontCharacter": "\\E023", "fontColor": "#cbcb41" }, "_elixir_light": { - "fontCharacter": "\\E023", + "fontCharacter": "\\E024", "fontColor": "#9068b0" }, "_elixir": { - "fontCharacter": "\\E023", + "fontCharacter": "\\E024", "fontColor": "#a074c4" }, "_elixir_script_light": { - "fontCharacter": "\\E024", + "fontCharacter": "\\E025", "fontColor": "#9068b0" }, "_elixir_script": { - "fontCharacter": "\\E024", + "fontCharacter": "\\E025", "fontColor": "#a074c4" }, "_elm_light": { - "fontCharacter": "\\E025", + "fontCharacter": "\\E026", "fontColor": "#498ba7" }, "_elm": { - "fontCharacter": "\\E025", + "fontCharacter": "\\E026", "fontColor": "#519aba" }, "_eslint_light": { - "fontCharacter": "\\E027", + "fontCharacter": "\\E028", "fontColor": "#9068b0" }, "_eslint": { - "fontCharacter": "\\E027", + "fontCharacter": "\\E028", "fontColor": "#a074c4" }, "_eslint_1_light": { - "fontCharacter": "\\E027", + "fontCharacter": "\\E028", "fontColor": "#455155" }, "_eslint_1": { - "fontCharacter": "\\E027", + "fontCharacter": "\\E028", "fontColor": "#4d5a5e" }, "_ethereum_light": { - "fontCharacter": "\\E028", + "fontCharacter": "\\E029", "fontColor": "#498ba7" }, "_ethereum": { - "fontCharacter": "\\E028", + "fontCharacter": "\\E029", "fontColor": "#519aba" }, "_f-sharp_light": { - "fontCharacter": "\\E029", + "fontCharacter": "\\E02A", "fontColor": "#498ba7" }, "_f-sharp": { - "fontCharacter": "\\E029", + "fontCharacter": "\\E02A", "fontColor": "#519aba" }, "_favicon_light": { - "fontCharacter": "\\E02A", + "fontCharacter": "\\E02B", "fontColor": "#b7b73b" }, "_favicon": { - "fontCharacter": "\\E02A", + "fontCharacter": "\\E02B", "fontColor": "#cbcb41" }, "_firebase_light": { - "fontCharacter": "\\E02B", + "fontCharacter": "\\E02C", "fontColor": "#cc6d2e" }, "_firebase": { - "fontCharacter": "\\E02B", + "fontCharacter": "\\E02C", "fontColor": "#e37933" }, "_firefox_light": { - "fontCharacter": "\\E02C", + "fontCharacter": "\\E02D", "fontColor": "#cc6d2e" }, "_firefox": { - "fontCharacter": "\\E02C", + "fontCharacter": "\\E02D", "fontColor": "#e37933" }, "_font_light": { - "fontCharacter": "\\E02E", + "fontCharacter": "\\E02F", "fontColor": "#b8383d" }, "_font": { - "fontCharacter": "\\E02E", + "fontCharacter": "\\E02F", "fontColor": "#cc3e44" }, "_git_light": { - "fontCharacter": "\\E02F", + "fontCharacter": "\\E030", "fontColor": "#3b4b52" }, "_git": { - "fontCharacter": "\\E02F", + "fontCharacter": "\\E030", "fontColor": "#41535b" }, "_go_light": { - "fontCharacter": "\\E033", + "fontCharacter": "\\E034", "fontColor": "#498ba7" }, "_go": { - "fontCharacter": "\\E033", + "fontCharacter": "\\E034", "fontColor": "#519aba" }, "_go2_light": { - "fontCharacter": "\\E034", + "fontCharacter": "\\E035", "fontColor": "#498ba7" }, "_go2": { - "fontCharacter": "\\E034", + "fontCharacter": "\\E035", "fontColor": "#519aba" }, "_gradle_light": { - "fontCharacter": "\\E035", + "fontCharacter": "\\E036", "fontColor": "#7fae42" }, "_gradle": { - "fontCharacter": "\\E035", + "fontCharacter": "\\E036", "fontColor": "#8dc149" }, "_grails_light": { - "fontCharacter": "\\E036", + "fontCharacter": "\\E037", "fontColor": "#7fae42" }, "_grails": { - "fontCharacter": "\\E036", + "fontCharacter": "\\E037", "fontColor": "#8dc149" }, + "_graphql_light": { + "fontCharacter": "\\E038", + "fontColor": "#dd4b78" + }, + "_graphql": { + "fontCharacter": "\\E038", + "fontColor": "#f55385" + }, "_grunt_light": { - "fontCharacter": "\\E037", + "fontCharacter": "\\E039", "fontColor": "#cc6d2e" }, "_grunt": { - "fontCharacter": "\\E037", + "fontCharacter": "\\E039", "fontColor": "#e37933" }, "_gulp_light": { - "fontCharacter": "\\E038", + "fontCharacter": "\\E03A", "fontColor": "#b8383d" }, "_gulp": { - "fontCharacter": "\\E038", + "fontCharacter": "\\E03A", "fontColor": "#cc3e44" }, "_haml_light": { - "fontCharacter": "\\E03A", + "fontCharacter": "\\E03C", "fontColor": "#b8383d" }, "_haml": { - "fontCharacter": "\\E03A", + "fontCharacter": "\\E03C", "fontColor": "#cc3e44" }, + "_happenings_light": { + "fontCharacter": "\\E03D", + "fontColor": "#498ba7" + }, + "_happenings": { + "fontCharacter": "\\E03D", + "fontColor": "#519aba" + }, "_haskell_light": { - "fontCharacter": "\\E03B", + "fontCharacter": "\\E03E", "fontColor": "#9068b0" }, "_haskell": { - "fontCharacter": "\\E03B", + "fontCharacter": "\\E03E", "fontColor": "#a074c4" }, "_haxe_light": { - "fontCharacter": "\\E03C", + "fontCharacter": "\\E03F", "fontColor": "#cc6d2e" }, "_haxe": { - "fontCharacter": "\\E03C", + "fontCharacter": "\\E03F", "fontColor": "#e37933" }, "_haxe_1_light": { - "fontCharacter": "\\E03C", + "fontCharacter": "\\E03F", "fontColor": "#b7b73b" }, "_haxe_1": { - "fontCharacter": "\\E03C", + "fontCharacter": "\\E03F", "fontColor": "#cbcb41" }, "_haxe_2_light": { - "fontCharacter": "\\E03C", + "fontCharacter": "\\E03F", "fontColor": "#498ba7" }, "_haxe_2": { - "fontCharacter": "\\E03C", + "fontCharacter": "\\E03F", "fontColor": "#519aba" }, "_haxe_3_light": { - "fontCharacter": "\\E03C", + "fontCharacter": "\\E03F", "fontColor": "#9068b0" }, "_haxe_3": { - "fontCharacter": "\\E03C", + "fontCharacter": "\\E03F", "fontColor": "#a074c4" }, "_heroku_light": { - "fontCharacter": "\\E03D", + "fontCharacter": "\\E040", "fontColor": "#9068b0" }, "_heroku": { - "fontCharacter": "\\E03D", + "fontCharacter": "\\E040", "fontColor": "#a074c4" }, "_hex_light": { - "fontCharacter": "\\E03E", + "fontCharacter": "\\E041", "fontColor": "#b8383d" }, "_hex": { - "fontCharacter": "\\E03E", + "fontCharacter": "\\E041", "fontColor": "#cc3e44" }, "_html_light": { - "fontCharacter": "\\E03F", - "fontColor": "#cc6d2e" + "fontCharacter": "\\E042", + "fontColor": "#498ba7" }, "_html": { - "fontCharacter": "\\E03F", + "fontCharacter": "\\E042", + "fontColor": "#519aba" + }, + "_html_1_light": { + "fontCharacter": "\\E042", + "fontColor": "#7fae42" + }, + "_html_1": { + "fontCharacter": "\\E042", + "fontColor": "#8dc149" + }, + "_html_2_light": { + "fontCharacter": "\\E042", + "fontColor": "#b7b73b" + }, + "_html_2": { + "fontCharacter": "\\E042", + "fontColor": "#cbcb41" + }, + "_html_3_light": { + "fontCharacter": "\\E042", + "fontColor": "#cc6d2e" + }, + "_html_3": { + "fontCharacter": "\\E042", "fontColor": "#e37933" }, "_html_erb_light": { - "fontCharacter": "\\E040", + "fontCharacter": "\\E043", "fontColor": "#b8383d" }, "_html_erb": { - "fontCharacter": "\\E040", + "fontCharacter": "\\E043", "fontColor": "#cc3e44" }, "_ignored_light": { - "fontCharacter": "\\E041", + "fontCharacter": "\\E044", "fontColor": "#3b4b52" }, "_ignored": { - "fontCharacter": "\\E041", + "fontCharacter": "\\E044", "fontColor": "#41535b" }, "_illustrator_light": { - "fontCharacter": "\\E042", + "fontCharacter": "\\E045", "fontColor": "#b7b73b" }, "_illustrator": { - "fontCharacter": "\\E042", + "fontCharacter": "\\E045", "fontColor": "#cbcb41" }, "_image_light": { - "fontCharacter": "\\E043", + "fontCharacter": "\\E046", "fontColor": "#9068b0" }, "_image": { - "fontCharacter": "\\E043", + "fontCharacter": "\\E046", "fontColor": "#a074c4" }, "_info_light": { - "fontCharacter": "\\E044", + "fontCharacter": "\\E047", "fontColor": "#498ba7" }, "_info": { - "fontCharacter": "\\E044", + "fontCharacter": "\\E047", "fontColor": "#519aba" }, "_ionic_light": { - "fontCharacter": "\\E045", + "fontCharacter": "\\E048", "fontColor": "#498ba7" }, "_ionic": { - "fontCharacter": "\\E045", + "fontCharacter": "\\E048", "fontColor": "#519aba" }, "_jade_light": { - "fontCharacter": "\\E046", + "fontCharacter": "\\E049", "fontColor": "#b8383d" }, "_jade": { - "fontCharacter": "\\E046", + "fontCharacter": "\\E049", "fontColor": "#cc3e44" }, "_java_light": { - "fontCharacter": "\\E047", + "fontCharacter": "\\E04A", "fontColor": "#b8383d" }, "_java": { - "fontCharacter": "\\E047", + "fontCharacter": "\\E04A", "fontColor": "#cc3e44" }, "_javascript_light": { - "fontCharacter": "\\E048", + "fontCharacter": "\\E04B", "fontColor": "#b7b73b" }, "_javascript": { - "fontCharacter": "\\E048", + "fontCharacter": "\\E04B", "fontColor": "#cbcb41" }, "_javascript_1_light": { - "fontCharacter": "\\E048", + "fontCharacter": "\\E04B", "fontColor": "#cc6d2e" }, "_javascript_1": { - "fontCharacter": "\\E048", + "fontCharacter": "\\E04B", "fontColor": "#e37933" }, "_javascript_2_light": { - "fontCharacter": "\\E048", + "fontCharacter": "\\E04B", "fontColor": "#498ba7" }, "_javascript_2": { - "fontCharacter": "\\E048", + "fontCharacter": "\\E04B", "fontColor": "#519aba" }, "_jenkins_light": { - "fontCharacter": "\\E049", + "fontCharacter": "\\E04C", "fontColor": "#b8383d" }, "_jenkins": { - "fontCharacter": "\\E049", + "fontCharacter": "\\E04C", "fontColor": "#cc3e44" }, "_jinja_light": { - "fontCharacter": "\\E04A", + "fontCharacter": "\\E04D", "fontColor": "#b8383d" }, "_jinja": { - "fontCharacter": "\\E04A", + "fontCharacter": "\\E04D", "fontColor": "#cc3e44" }, "_json_light": { - "fontCharacter": "\\E04C", + "fontCharacter": "\\E04F", "fontColor": "#b7b73b" }, "_json": { - "fontCharacter": "\\E04C", + "fontCharacter": "\\E04F", "fontColor": "#cbcb41" }, "_json_1_light": { - "fontCharacter": "\\E04C", + "fontCharacter": "\\E04F", "fontColor": "#7fae42" }, "_json_1": { - "fontCharacter": "\\E04C", + "fontCharacter": "\\E04F", "fontColor": "#8dc149" }, "_julia_light": { - "fontCharacter": "\\E04D", + "fontCharacter": "\\E050", "fontColor": "#9068b0" }, "_julia": { - "fontCharacter": "\\E04D", + "fontCharacter": "\\E050", "fontColor": "#a074c4" }, "_karma_light": { - "fontCharacter": "\\E04E", + "fontCharacter": "\\E051", "fontColor": "#7fae42" }, "_karma": { - "fontCharacter": "\\E04E", + "fontCharacter": "\\E051", "fontColor": "#8dc149" }, "_kotlin_light": { - "fontCharacter": "\\E04F", + "fontCharacter": "\\E052", "fontColor": "#cc6d2e" }, "_kotlin": { - "fontCharacter": "\\E04F", + "fontCharacter": "\\E052", "fontColor": "#e37933" }, "_less_light": { - "fontCharacter": "\\E050", + "fontCharacter": "\\E053", "fontColor": "#498ba7" }, "_less": { - "fontCharacter": "\\E050", + "fontCharacter": "\\E053", "fontColor": "#519aba" }, "_license_light": { - "fontCharacter": "\\E051", + "fontCharacter": "\\E054", "fontColor": "#b7b73b" }, "_license": { - "fontCharacter": "\\E051", + "fontCharacter": "\\E054", "fontColor": "#cbcb41" }, "_license_1_light": { - "fontCharacter": "\\E051", + "fontCharacter": "\\E054", "fontColor": "#cc6d2e" }, "_license_1": { - "fontCharacter": "\\E051", + "fontCharacter": "\\E054", "fontColor": "#e37933" }, "_license_2_light": { - "fontCharacter": "\\E051", + "fontCharacter": "\\E054", "fontColor": "#b8383d" }, "_license_2": { - "fontCharacter": "\\E051", + "fontCharacter": "\\E054", "fontColor": "#cc3e44" }, "_liquid_light": { - "fontCharacter": "\\E052", + "fontCharacter": "\\E055", "fontColor": "#7fae42" }, "_liquid": { - "fontCharacter": "\\E052", + "fontCharacter": "\\E055", "fontColor": "#8dc149" }, "_livescript_light": { - "fontCharacter": "\\E053", + "fontCharacter": "\\E056", "fontColor": "#498ba7" }, "_livescript": { - "fontCharacter": "\\E053", + "fontCharacter": "\\E056", "fontColor": "#519aba" }, "_lock_light": { - "fontCharacter": "\\E054", + "fontCharacter": "\\E057", "fontColor": "#7fae42" }, "_lock": { - "fontCharacter": "\\E054", + "fontCharacter": "\\E057", "fontColor": "#8dc149" }, "_lua_light": { - "fontCharacter": "\\E055", + "fontCharacter": "\\E058", "fontColor": "#498ba7" }, "_lua": { - "fontCharacter": "\\E055", + "fontCharacter": "\\E058", "fontColor": "#519aba" }, "_makefile_light": { - "fontCharacter": "\\E056", + "fontCharacter": "\\E059", "fontColor": "#cc6d2e" }, "_makefile": { - "fontCharacter": "\\E056", + "fontCharacter": "\\E059", "fontColor": "#e37933" }, "_makefile_1_light": { - "fontCharacter": "\\E056", + "fontCharacter": "\\E059", "fontColor": "#9068b0" }, "_makefile_1": { - "fontCharacter": "\\E056", + "fontCharacter": "\\E059", "fontColor": "#a074c4" }, "_makefile_2_light": { - "fontCharacter": "\\E056", + "fontCharacter": "\\E059", "fontColor": "#627379" }, "_makefile_2": { - "fontCharacter": "\\E056", + "fontCharacter": "\\E059", "fontColor": "#6d8086" }, "_makefile_3_light": { - "fontCharacter": "\\E056", + "fontCharacter": "\\E059", "fontColor": "#498ba7" }, "_makefile_3": { - "fontCharacter": "\\E056", + "fontCharacter": "\\E059", "fontColor": "#519aba" }, "_markdown_light": { - "fontCharacter": "\\E057", + "fontCharacter": "\\E05A", "fontColor": "#498ba7" }, "_markdown": { - "fontCharacter": "\\E057", + "fontCharacter": "\\E05A", "fontColor": "#519aba" }, "_maven_light": { - "fontCharacter": "\\E058", + "fontCharacter": "\\E05B", "fontColor": "#b8383d" }, "_maven": { - "fontCharacter": "\\E058", + "fontCharacter": "\\E05B", "fontColor": "#cc3e44" }, "_mdo_light": { - "fontCharacter": "\\E059", + "fontCharacter": "\\E05C", "fontColor": "#b8383d" }, "_mdo": { - "fontCharacter": "\\E059", + "fontCharacter": "\\E05C", "fontColor": "#cc3e44" }, "_mustache_light": { - "fontCharacter": "\\E05A", + "fontCharacter": "\\E05D", "fontColor": "#cc6d2e" }, "_mustache": { - "fontCharacter": "\\E05A", + "fontCharacter": "\\E05D", "fontColor": "#e37933" }, "_npm_light": { - "fontCharacter": "\\E05C", + "fontCharacter": "\\E05F", "fontColor": "#3b4b52" }, "_npm": { - "fontCharacter": "\\E05C", + "fontCharacter": "\\E05F", "fontColor": "#41535b" }, "_npm_1_light": { - "fontCharacter": "\\E05C", + "fontCharacter": "\\E05F", "fontColor": "#b8383d" }, "_npm_1": { - "fontCharacter": "\\E05C", + "fontCharacter": "\\E05F", "fontColor": "#cc3e44" }, "_npm_ignored_light": { - "fontCharacter": "\\E05D", + "fontCharacter": "\\E060", "fontColor": "#3b4b52" }, "_npm_ignored": { - "fontCharacter": "\\E05D", + "fontCharacter": "\\E060", "fontColor": "#41535b" }, "_nunjucks_light": { - "fontCharacter": "\\E05E", + "fontCharacter": "\\E061", "fontColor": "#7fae42" }, "_nunjucks": { - "fontCharacter": "\\E05E", + "fontCharacter": "\\E061", "fontColor": "#8dc149" }, "_ocaml_light": { - "fontCharacter": "\\E05F", + "fontCharacter": "\\E062", "fontColor": "#cc6d2e" }, "_ocaml": { - "fontCharacter": "\\E05F", + "fontCharacter": "\\E062", "fontColor": "#e37933" }, "_odata_light": { - "fontCharacter": "\\E060", + "fontCharacter": "\\E063", "fontColor": "#cc6d2e" }, "_odata": { - "fontCharacter": "\\E060", + "fontCharacter": "\\E063", "fontColor": "#e37933" }, + "_pddl_light": { + "fontCharacter": "\\E064", + "fontColor": "#9068b0" + }, + "_pddl": { + "fontCharacter": "\\E064", + "fontColor": "#a074c4" + }, "_pdf_light": { - "fontCharacter": "\\E061", + "fontCharacter": "\\E065", "fontColor": "#b8383d" }, "_pdf": { - "fontCharacter": "\\E061", + "fontCharacter": "\\E065", "fontColor": "#cc3e44" }, "_perl_light": { - "fontCharacter": "\\E062", + "fontCharacter": "\\E066", "fontColor": "#498ba7" }, "_perl": { - "fontCharacter": "\\E062", + "fontCharacter": "\\E066", "fontColor": "#519aba" }, "_photoshop_light": { - "fontCharacter": "\\E063", + "fontCharacter": "\\E067", "fontColor": "#498ba7" }, "_photoshop": { - "fontCharacter": "\\E063", + "fontCharacter": "\\E067", "fontColor": "#519aba" }, "_php_light": { - "fontCharacter": "\\E064", + "fontCharacter": "\\E068", "fontColor": "#9068b0" }, "_php": { - "fontCharacter": "\\E064", + "fontCharacter": "\\E068", "fontColor": "#a074c4" }, + "_plan_light": { + "fontCharacter": "\\E069", + "fontColor": "#7fae42" + }, + "_plan": { + "fontCharacter": "\\E069", + "fontColor": "#8dc149" + }, + "_platformio_light": { + "fontCharacter": "\\E06A", + "fontColor": "#cc6d2e" + }, + "_platformio": { + "fontCharacter": "\\E06A", + "fontColor": "#e37933" + }, "_powershell_light": { - "fontCharacter": "\\E065", + "fontCharacter": "\\E06B", "fontColor": "#498ba7" }, "_powershell": { - "fontCharacter": "\\E065", + "fontCharacter": "\\E06B", "fontColor": "#519aba" }, "_pug_light": { - "fontCharacter": "\\E067", + "fontCharacter": "\\E06D", "fontColor": "#b8383d" }, "_pug": { - "fontCharacter": "\\E067", + "fontCharacter": "\\E06D", "fontColor": "#cc3e44" }, "_puppet_light": { - "fontCharacter": "\\E068", + "fontCharacter": "\\E06E", "fontColor": "#b7b73b" }, "_puppet": { - "fontCharacter": "\\E068", + "fontCharacter": "\\E06E", "fontColor": "#cbcb41" }, "_python_light": { - "fontCharacter": "\\E069", + "fontCharacter": "\\E06F", "fontColor": "#498ba7" }, "_python": { - "fontCharacter": "\\E069", + "fontCharacter": "\\E06F", "fontColor": "#519aba" }, "_react_light": { - "fontCharacter": "\\E06B", + "fontCharacter": "\\E071", "fontColor": "#498ba7" }, "_react": { - "fontCharacter": "\\E06B", + "fontCharacter": "\\E071", "fontColor": "#519aba" }, + "_react_1_light": { + "fontCharacter": "\\E071", + "fontColor": "#cc6d2e" + }, + "_react_1": { + "fontCharacter": "\\E071", + "fontColor": "#e37933" + }, + "_react_2_light": { + "fontCharacter": "\\E071", + "fontColor": "#b7b73b" + }, + "_react_2": { + "fontCharacter": "\\E071", + "fontColor": "#cbcb41" + }, + "_reasonml_light": { + "fontCharacter": "\\E072", + "fontColor": "#b8383d" + }, + "_reasonml": { + "fontCharacter": "\\E072", + "fontColor": "#cc3e44" + }, "_rollup_light": { - "fontCharacter": "\\E06C", + "fontCharacter": "\\E073", "fontColor": "#b8383d" }, "_rollup": { - "fontCharacter": "\\E06C", + "fontCharacter": "\\E073", "fontColor": "#cc3e44" }, "_ruby_light": { - "fontCharacter": "\\E06D", + "fontCharacter": "\\E074", "fontColor": "#b8383d" }, "_ruby": { - "fontCharacter": "\\E06D", + "fontCharacter": "\\E074", "fontColor": "#cc3e44" }, "_rust_light": { - "fontCharacter": "\\E06E", + "fontCharacter": "\\E075", "fontColor": "#627379" }, "_rust": { - "fontCharacter": "\\E06E", + "fontCharacter": "\\E075", "fontColor": "#6d8086" }, "_salesforce_light": { - "fontCharacter": "\\E06F", + "fontCharacter": "\\E076", "fontColor": "#498ba7" }, "_salesforce": { - "fontCharacter": "\\E06F", + "fontCharacter": "\\E076", "fontColor": "#519aba" }, "_sass_light": { - "fontCharacter": "\\E070", + "fontCharacter": "\\E077", "fontColor": "#dd4b78" }, "_sass": { - "fontCharacter": "\\E070", + "fontCharacter": "\\E077", "fontColor": "#f55385" }, "_sbt_light": { - "fontCharacter": "\\E071", + "fontCharacter": "\\E078", "fontColor": "#498ba7" }, "_sbt": { - "fontCharacter": "\\E071", + "fontCharacter": "\\E078", "fontColor": "#519aba" }, "_scala_light": { - "fontCharacter": "\\E072", + "fontCharacter": "\\E079", "fontColor": "#b8383d" }, "_scala": { - "fontCharacter": "\\E072", + "fontCharacter": "\\E079", "fontColor": "#cc3e44" }, "_shell_light": { - "fontCharacter": "\\E075", + "fontCharacter": "\\E07C", "fontColor": "#455155" }, "_shell": { - "fontCharacter": "\\E075", + "fontCharacter": "\\E07C", "fontColor": "#4d5a5e" }, "_slim_light": { - "fontCharacter": "\\E076", + "fontCharacter": "\\E07D", "fontColor": "#cc6d2e" }, "_slim": { - "fontCharacter": "\\E076", + "fontCharacter": "\\E07D", "fontColor": "#e37933" }, "_smarty_light": { - "fontCharacter": "\\E077", + "fontCharacter": "\\E07E", "fontColor": "#b7b73b" }, "_smarty": { - "fontCharacter": "\\E077", + "fontCharacter": "\\E07E", "fontColor": "#cbcb41" }, "_spring_light": { - "fontCharacter": "\\E078", + "fontCharacter": "\\E07F", "fontColor": "#7fae42" }, "_spring": { - "fontCharacter": "\\E078", + "fontCharacter": "\\E07F", "fontColor": "#8dc149" }, "_stylelint_light": { - "fontCharacter": "\\E079", + "fontCharacter": "\\E080", "fontColor": "#bfc2c1" }, "_stylelint": { - "fontCharacter": "\\E079", + "fontCharacter": "\\E080", "fontColor": "#d4d7d6" }, "_stylelint_1_light": { - "fontCharacter": "\\E079", + "fontCharacter": "\\E080", "fontColor": "#455155" }, "_stylelint_1": { - "fontCharacter": "\\E079", + "fontCharacter": "\\E080", "fontColor": "#4d5a5e" }, "_stylus_light": { - "fontCharacter": "\\E07A", + "fontCharacter": "\\E081", "fontColor": "#7fae42" }, "_stylus": { - "fontCharacter": "\\E07A", + "fontCharacter": "\\E081", "fontColor": "#8dc149" }, "_sublime_light": { - "fontCharacter": "\\E07B", + "fontCharacter": "\\E082", "fontColor": "#cc6d2e" }, "_sublime": { - "fontCharacter": "\\E07B", + "fontCharacter": "\\E082", "fontColor": "#e37933" }, "_svg_light": { - "fontCharacter": "\\E07C", + "fontCharacter": "\\E083", "fontColor": "#9068b0" }, "_svg": { - "fontCharacter": "\\E07C", + "fontCharacter": "\\E083", "fontColor": "#a074c4" }, "_svg_1_light": { - "fontCharacter": "\\E07C", + "fontCharacter": "\\E083", "fontColor": "#498ba7" }, "_svg_1": { - "fontCharacter": "\\E07C", + "fontCharacter": "\\E083", "fontColor": "#519aba" }, "_swift_light": { - "fontCharacter": "\\E07D", + "fontCharacter": "\\E084", "fontColor": "#cc6d2e" }, "_swift": { - "fontCharacter": "\\E07D", + "fontCharacter": "\\E084", "fontColor": "#e37933" }, "_terraform_light": { - "fontCharacter": "\\E07E", + "fontCharacter": "\\E085", "fontColor": "#9068b0" }, "_terraform": { - "fontCharacter": "\\E07E", + "fontCharacter": "\\E085", "fontColor": "#a074c4" }, "_tex_light": { - "fontCharacter": "\\E07F", + "fontCharacter": "\\E086", "fontColor": "#498ba7" }, "_tex": { - "fontCharacter": "\\E07F", + "fontCharacter": "\\E086", "fontColor": "#519aba" }, "_tex_1_light": { - "fontCharacter": "\\E07F", + "fontCharacter": "\\E086", "fontColor": "#b7b73b" }, "_tex_1": { - "fontCharacter": "\\E07F", + "fontCharacter": "\\E086", "fontColor": "#cbcb41" }, "_tex_2_light": { - "fontCharacter": "\\E07F", + "fontCharacter": "\\E086", "fontColor": "#cc6d2e" }, "_tex_2": { - "fontCharacter": "\\E07F", + "fontCharacter": "\\E086", "fontColor": "#e37933" }, "_tex_3_light": { - "fontCharacter": "\\E07F", + "fontCharacter": "\\E086", "fontColor": "#bfc2c1" }, "_tex_3": { - "fontCharacter": "\\E07F", + "fontCharacter": "\\E086", "fontColor": "#d4d7d6" }, "_todo": { - "fontCharacter": "\\E081" + "fontCharacter": "\\E088" + }, + "_tsconfig_light": { + "fontCharacter": "\\E089", + "fontColor": "#498ba7" + }, + "_tsconfig": { + "fontCharacter": "\\E089", + "fontColor": "#519aba" }, "_twig_light": { - "fontCharacter": "\\E082", + "fontCharacter": "\\E08A", "fontColor": "#7fae42" }, "_twig": { - "fontCharacter": "\\E082", + "fontCharacter": "\\E08A", "fontColor": "#8dc149" }, "_typescript_light": { - "fontCharacter": "\\E083", + "fontCharacter": "\\E08B", "fontColor": "#498ba7" }, "_typescript": { - "fontCharacter": "\\E083", + "fontCharacter": "\\E08B", "fontColor": "#519aba" }, "_typescript_1_light": { - "fontCharacter": "\\E083", + "fontCharacter": "\\E08B", "fontColor": "#b7b73b" }, "_typescript_1": { - "fontCharacter": "\\E083", + "fontCharacter": "\\E08B", "fontColor": "#cbcb41" }, "_vala_light": { - "fontCharacter": "\\E084", + "fontCharacter": "\\E08C", "fontColor": "#627379" }, "_vala": { - "fontCharacter": "\\E084", + "fontCharacter": "\\E08C", "fontColor": "#6d8086" }, "_video_light": { - "fontCharacter": "\\E085", + "fontCharacter": "\\E08D", "fontColor": "#dd4b78" }, "_video": { - "fontCharacter": "\\E085", + "fontCharacter": "\\E08D", "fontColor": "#f55385" }, "_vue_light": { - "fontCharacter": "\\E086", + "fontCharacter": "\\E08E", "fontColor": "#7fae42" }, "_vue": { - "fontCharacter": "\\E086", + "fontCharacter": "\\E08E", "fontColor": "#8dc149" }, "_wasm_light": { - "fontCharacter": "\\E087", + "fontCharacter": "\\E08F", "fontColor": "#9068b0" }, "_wasm": { - "fontCharacter": "\\E087", + "fontCharacter": "\\E08F", "fontColor": "#a074c4" }, "_wat_light": { - "fontCharacter": "\\E088", + "fontCharacter": "\\E090", "fontColor": "#9068b0" }, "_wat": { - "fontCharacter": "\\E088", + "fontCharacter": "\\E090", "fontColor": "#a074c4" }, "_webpack_light": { - "fontCharacter": "\\E089", + "fontCharacter": "\\E091", "fontColor": "#498ba7" }, "_webpack": { - "fontCharacter": "\\E089", + "fontCharacter": "\\E091", "fontColor": "#519aba" }, "_wgt_light": { - "fontCharacter": "\\E08A", + "fontCharacter": "\\E092", "fontColor": "#498ba7" }, "_wgt": { - "fontCharacter": "\\E08A", + "fontCharacter": "\\E092", "fontColor": "#519aba" }, "_windows_light": { - "fontCharacter": "\\E08B", + "fontCharacter": "\\E093", "fontColor": "#498ba7" }, "_windows": { - "fontCharacter": "\\E08B", + "fontCharacter": "\\E093", "fontColor": "#519aba" }, "_word_light": { - "fontCharacter": "\\E08C", + "fontCharacter": "\\E094", "fontColor": "#498ba7" }, "_word": { - "fontCharacter": "\\E08C", + "fontCharacter": "\\E094", "fontColor": "#519aba" }, "_xls_light": { - "fontCharacter": "\\E08D", + "fontCharacter": "\\E095", "fontColor": "#7fae42" }, "_xls": { - "fontCharacter": "\\E08D", + "fontCharacter": "\\E095", "fontColor": "#8dc149" }, "_xml_light": { - "fontCharacter": "\\E08E", + "fontCharacter": "\\E096", "fontColor": "#cc6d2e" }, "_xml": { - "fontCharacter": "\\E08E", + "fontCharacter": "\\E096", "fontColor": "#e37933" }, "_yarn_light": { - "fontCharacter": "\\E08F", + "fontCharacter": "\\E097", "fontColor": "#498ba7" }, "_yarn": { - "fontCharacter": "\\E08F", + "fontCharacter": "\\E097", "fontColor": "#519aba" }, "_yml_light": { - "fontCharacter": "\\E090", + "fontCharacter": "\\E098", "fontColor": "#9068b0" }, "_yml": { - "fontCharacter": "\\E090", + "fontCharacter": "\\E098", "fontColor": "#a074c4" }, "_zip_light": { - "fontCharacter": "\\E091", + "fontCharacter": "\\E099", "fontColor": "#b8383d" }, "_zip": { - "fontCharacter": "\\E091", + "fontCharacter": "\\E099", "fontColor": "#cc3e44" }, "_zip_1_light": { - "fontCharacter": "\\E091", + "fontCharacter": "\\E099", "fontColor": "#627379" }, "_zip_1": { - "fontCharacter": "\\E091", + "fontCharacter": "\\E099", "fontColor": "#6d8086" } }, @@ -1249,6 +1361,10 @@ "asm": "_asm", "s": "_asm", "h": "_c_1", + "aspx": "_html", + "ascx": "_html_1", + "asax": "_html_2", + "master": "_html_2", "hh": "_cpp_1", "hpp": "_cpp_1", "hxx": "_cpp_1", @@ -1286,6 +1402,8 @@ "article": "_go", "gradle": "_gradle", "gsp": "_grails", + "gql": "_graphql", + "graphql": "_graphql", "haml": "_haml", "hs": "_haskell", "lhs": "_haskell", @@ -1297,6 +1415,7 @@ "classpath": "_java", "js.map": "_javascript", "spec.js": "_javascript_1", + "test.js": "_javascript_1", "es": "_javascript", "es5": "_javascript", "es7": "_javascript", @@ -1305,6 +1424,7 @@ "jl": "_julia", "kt": "_kotlin", "kts": "_kotlin", + "dart": "_dart", "liquid": "_liquid", "ls": "_livescript", "argdown": "_argdown", @@ -1326,10 +1446,18 @@ "cmxa": "_ocaml", "odata": "_odata", "php.inc": "_php", + "pddl": "_pddl", + "plan": "_plan", + "happenings": "_happenings", "pug": "_pug", "pp": "_puppet", "epp": "_puppet", + "spec.jsx": "_react_1", + "test.jsx": "_react_1", "cjsx": "_react", + "spec.tsx": "_react_2", + "test.tsx": "_react_2", + "re": "_reasonml", "r": "_R", "erb": "_html_erb", "erb.html": "_html_erb", @@ -1352,6 +1480,7 @@ "toml": "_config", "twig": "_twig", "spec.ts": "_typescript_1", + "test.ts": "_typescript_1", "vala": "_vala", "vapi": "_vala", "vue": "_vue", @@ -1452,6 +1581,7 @@ "gulpfile": "_gulp", "ionic.config.json": "_ionic", "ionic.project": "_ionic", + "platformio.ini": "_platformio", "rollup.config.js": "_rollup", "sass-lint.yml": "_sass", "stylelint.config.js": "_stylelint", @@ -1459,6 +1589,9 @@ "yarn.lock": "_yarn", "webpack.config.js": "_webpack", "webpack.config.build.js": "_webpack", + "webpack.common.js": "_webpack", + "webpack.dev.js": "_webpack", + "webpack.prod.js": "_webpack", "license": "_license", "licence": "_license", "copying": "_license", @@ -1475,6 +1608,7 @@ "bat": "_windows", "clojure": "_clojure", "coffeescript": "_coffee", + "jsonc": "_tsconfig", "c": "_c", "cpp": "_cpp", "csharp": "_c-sharp", @@ -1484,7 +1618,7 @@ "go": "_go2", "groovy": "_grails", "handlebars": "_mustache", - "html": "_html", + "html": "_html_3", "properties": "_java", "java": "_java", "javascriptreact": "_react", @@ -1495,12 +1629,14 @@ "makefile": "_makefile", "markdown": "_markdown", "objective-c": "_c_2", + "objective-cpp": "_cpp_2", "perl": "_perl", "php": "_php", "powershell": "_powershell", "jade": "_jade", "python": "_python", "r": "_R", + "razor": "_html", "ruby": "_ruby", "rust": "_rust", "scss": "_sass", @@ -1539,6 +1675,10 @@ "asm": "_asm_light", "s": "_asm_light", "h": "_c_1_light", + "aspx": "_html_light", + "ascx": "_html_1_light", + "asax": "_html_2_light", + "master": "_html_2_light", "hh": "_cpp_1_light", "hpp": "_cpp_1_light", "hxx": "_cpp_1_light", @@ -1576,6 +1716,8 @@ "article": "_go_light", "gradle": "_gradle_light", "gsp": "_grails_light", + "gql": "_graphql_light", + "graphql": "_graphql_light", "haml": "_haml_light", "hs": "_haskell_light", "lhs": "_haskell_light", @@ -1587,6 +1729,7 @@ "classpath": "_java_light", "js.map": "_javascript_light", "spec.js": "_javascript_1_light", + "test.js": "_javascript_1_light", "es": "_javascript_light", "es5": "_javascript_light", "es7": "_javascript_light", @@ -1595,6 +1738,7 @@ "jl": "_julia_light", "kt": "_kotlin_light", "kts": "_kotlin_light", + "dart": "_dart_light", "liquid": "_liquid_light", "ls": "_livescript_light", "argdown": "_argdown_light", @@ -1616,10 +1760,18 @@ "cmxa": "_ocaml_light", "odata": "_odata_light", "php.inc": "_php_light", + "pddl": "_pddl_light", + "plan": "_plan_light", + "happenings": "_happenings_light", "pug": "_pug_light", "pp": "_puppet_light", "epp": "_puppet_light", + "spec.jsx": "_react_1_light", + "test.jsx": "_react_1_light", "cjsx": "_react_light", + "spec.tsx": "_react_2_light", + "test.tsx": "_react_2_light", + "re": "_reasonml_light", "r": "_R_light", "erb": "_html_erb_light", "erb.html": "_html_erb_light", @@ -1642,6 +1794,7 @@ "toml": "_config_light", "twig": "_twig_light", "spec.ts": "_typescript_1_light", + "test.ts": "_typescript_1_light", "vala": "_vala_light", "vapi": "_vala_light", "vue": "_vue_light", @@ -1718,6 +1871,7 @@ "bat": "_windows_light", "clojure": "_clojure_light", "coffeescript": "_coffee_light", + "jsonc": "_tsconfig_light", "c": "_c_light", "cpp": "_cpp_light", "csharp": "_c-sharp_light", @@ -1727,7 +1881,7 @@ "go": "_go2_light", "groovy": "_grails_light", "handlebars": "_mustache_light", - "html": "_html_light", + "html": "_html_3_light", "properties": "_java_light", "java": "_java_light", "javascriptreact": "_react_light", @@ -1738,12 +1892,14 @@ "makefile": "_makefile_light", "markdown": "_markdown_light", "objective-c": "_c_2_light", + "objective-cpp": "_cpp_2_light", "perl": "_perl_light", "php": "_php_light", "powershell": "_powershell_light", "jade": "_jade_light", "python": "_python_light", "r": "_R_light", + "razor": "_html_light", "ruby": "_ruby_light", "rust": "_rust_light", "scss": "_sass_light", @@ -1801,6 +1957,7 @@ "gulpfile": "_gulp_light", "ionic.config.json": "_ionic_light", "ionic.project": "_ionic_light", + "platformio.ini": "_platformio_light", "rollup.config.js": "_rollup_light", "sass-lint.yml": "_sass_light", "stylelint.config.js": "_stylelint_light", @@ -1808,6 +1965,9 @@ "yarn.lock": "_yarn_light", "webpack.config.js": "_webpack_light", "webpack.config.build.js": "_webpack_light", + "webpack.common.js": "_webpack_light", + "webpack.dev.js": "_webpack_light", + "webpack.prod.js": "_webpack_light", "license": "_license_light", "licence": "_license_light", "copying": "_license_light", @@ -1820,5 +1980,5 @@ "npm-debug.log": "_npm_ignored_light" } }, - "version": "https://github.com/jesseweed/seti-ui/commit/89175d7f9e0c70cd325b80a18a3c77fc8eb7c798" + "version": "https://github.com/jesseweed/seti-ui/commit/904c16acced1134a81b31d71d60293288c31334b" } \ No newline at end of file diff --git a/extensions/theme-seti/package.json b/extensions/theme-seti/package.json index 554119b52..a9721611a 100644 --- a/extensions/theme-seti/package.json +++ b/extensions/theme-seti/package.json @@ -5,6 +5,7 @@ "displayName": "%displayName%", "description": "%description%", "publisher": "vscode", + "license": "MIT", "icon": "icons/seti-circular-128x128.png", "scripts": { "update": "node ./build/update-icon-theme.js" diff --git a/extensions/theme-solarized-dark/package.json b/extensions/theme-solarized-dark/package.json index bb43708ca..427b50fe4 100644 --- a/extensions/theme-solarized-dark/package.json +++ b/extensions/theme-solarized-dark/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "*" }, "contributes": { "themes": [ 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 9336e2ca2..f2ee483be 100644 --- a/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json +++ b/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json @@ -72,7 +72,9 @@ "name": "Class name", "scope": [ "entity.name.class", - "entity.name.type" + "entity.name.type", + "entity.name.namespace", + "entity.name.scope-resolution" ], "settings": { "fontStyle": "", @@ -448,7 +450,7 @@ "statusBar.background": "#00212B", "statusBar.debuggingBackground": "#00212B", "statusBar.noFolderBackground": "#00212B", - "statusBarItem.hostBackground": "#2AA19899", + "statusBarItem.remoteBackground": "#2AA19899", "statusBarItem.prominentBackground": "#003847", "statusBarItem.prominentHoverBackground": "#003847", // "statusBarItem.activeBackground": "", diff --git a/extensions/theme-solarized-light/package.json b/extensions/theme-solarized-light/package.json index 1925afaa3..3afb2b7ed 100644 --- a/extensions/theme-solarized-light/package.json +++ b/extensions/theme-solarized-light/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "*" }, "contributes": { "themes": [ 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 20e50ab36..8cc7e74a7 100644 --- a/extensions/theme-solarized-light/themes/solarized-light-color-theme.json +++ b/extensions/theme-solarized-light/themes/solarized-light-color-theme.json @@ -72,7 +72,9 @@ "name": "Class name", "scope": [ "entity.name.class", - "entity.name.type" + "entity.name.type", + "entity.name.namespace", + "entity.name.scope-resolution" ], "settings": { "foreground": "#268BD2" @@ -219,16 +221,14 @@ "meta.diff.header" ], "settings": { - "background": "#b58900", "fontStyle": "italic", - "foreground": "#E0EDDD" + "foreground": "#268bd2" } }, { "name": "diff: deleted", "scope": "markup.deleted", "settings": { - "background": "#eee8d5", "fontStyle": "", "foreground": "#dc322f" } @@ -237,7 +237,6 @@ "name": "diff: changed", "scope": "markup.changed", "settings": { - "background": "#eee8d5", "fontStyle": "", "foreground": "#cb4b16" } @@ -246,7 +245,6 @@ "name": "diff: inserted", "scope": "markup.inserted", "settings": { - "background": "#eee8d5", "foreground": "#219186" } }, @@ -417,7 +415,7 @@ "tab.activeBackground": "#FDF6E3", "tab.inactiveForeground": "#586E75", "tab.inactiveBackground": "#D3CBB7", - "tab.modifiedBorder": "#cb4b16", + "tab.activeModifiedBorder": "#cb4b16", // "tab.activeBackground": "", // "tab.activeForeground": "", // "tab.inactiveForeground": "", @@ -447,7 +445,7 @@ "statusBar.debuggingBackground": "#EEE8D5", "statusBar.noFolderBackground": "#EEE8D5", // "statusBar.foreground": "", - "statusBarItem.hostBackground": "#AC9D57", + "statusBarItem.remoteBackground": "#AC9D57", "statusBarItem.prominentBackground": "#DDD6C1", "statusBarItem.prominentHoverBackground": "#DDD6C199", // "statusBarItem.activeBackground": "", diff --git a/extensions/theme-tomorrow-night-blue/package.json b/extensions/theme-tomorrow-night-blue/package.json index bed66ce54..1266ac58c 100644 --- a/extensions/theme-tomorrow-night-blue/package.json +++ b/extensions/theme-tomorrow-night-blue/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "*" }, "contributes": { "themes": [ 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 5236bf4a9..6c985d1ea 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 @@ -30,7 +30,7 @@ "debugToolBar.background": "#001c40", "titleBar.activeBackground": "#001126", "statusBar.background": "#001126", - "statusBarItem.hostBackground": "#0e639c", + "statusBarItem.remoteBackground": "#0e639c", "statusBar.noFolderBackground": "#001126", "statusBar.debuggingBackground": "#001126", "activityBar.background": "#001733", @@ -101,7 +101,7 @@ }, { "name": "Class, Support", - "scope": "entity.name.class, entity.name.type, support.type, support.class", + "scope": "entity.name.class, entity.name.type, entity.name.namespace, entity.name.scope-resolution, support.type, support.class", "settings": { "fontStyle": "", "foreground": "#FFEEAD" diff --git a/extensions/typescript-basics/cgmanifest.json b/extensions/typescript-basics/cgmanifest.json index dedb6134e..cd8c1071a 100644 --- a/extensions/typescript-basics/cgmanifest.json +++ b/extensions/typescript-basics/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "TypeScript-TmLanguage", "repositoryUrl": "https://github.com/Microsoft/TypeScript-TmLanguage", - "commitHash": "a4c4dafb226a4c1d037a52434aa1154d9dabad8b" + "commitHash": "cf7b1ec2c20b5fe28695249596128ff514e1a659" } }, "license": "MIT", diff --git a/extensions/typescript-basics/package.json b/extensions/typescript-basics/package.json index f5532d15d..185a8a2bc 100644 --- a/extensions/typescript-basics/package.json +++ b/extensions/typescript-basics/package.json @@ -130,4 +130,4 @@ } ] } -} \ No newline at end of file +} diff --git a/extensions/typescript-basics/syntaxes/TypeScript.tmLanguage.json b/extensions/typescript-basics/syntaxes/TypeScript.tmLanguage.json index 96ee77822..ce5a34d5f 100644 --- a/extensions/typescript-basics/syntaxes/TypeScript.tmLanguage.json +++ b/extensions/typescript-basics/syntaxes/TypeScript.tmLanguage.json @@ -4,7 +4,7 @@ "If you want to provide a fix or improvement, please create a pull request against the original repository.", "Once accepted there, we are happy to receive an update request." ], - "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/a4c4dafb226a4c1d037a52434aa1154d9dabad8b", + "version": "https://github.com/Microsoft/TypeScript-TmLanguage/commit/11b1a4f8dc3a3eaa4df71e8cc1ad6f01a688961d", "name": "TypeScript", "scopeName": "source.ts", "patterns": [ @@ -283,7 +283,7 @@ { "name": "meta.var.expr.ts", "begin": "(?=(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(\\!)?(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "beginCaptures": { "1": { "name": "meta.definition.variable.ts entity.name.function.ts" @@ -432,7 +432,7 @@ "name": "keyword.operator.definiteassignment.ts" } }, - "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", + "end": "(?=$|^|[;,=}]|((?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "beginCaptures": { "1": { "name": "meta.definition.variable.ts variable.other.constant.ts entity.name.function.ts" } }, - "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", + "end": "(?=$|^|[;,=}]|((?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "match": "(?x)(?:(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "1": { "name": "storage.modifier.ts" @@ -1105,7 +1105,7 @@ "include": "#comment" }, { - "match": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?:(\\?)|(\\!))?(?=\\s*\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "match": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?:(\\?)|(\\!))?(?=\\s*\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "1": { "name": "meta.definition.property.ts entity.name.function.ts" @@ -1141,7 +1141,7 @@ "name": "keyword.operator.assignment.ts" } }, - "end": "(?=$|^|[,);}\\]]|(\\s+(of|in)\\s+))", + "end": "(?=$|^|[,);}\\]]|((?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?[\\(])", + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", "beginCaptures": { "1": { "name": "storage.modifier.ts" @@ -1315,7 +1315,7 @@ }, { "name": "meta.method.declaration.ts", - "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?[\\(])", + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", "beginCaptures": { "1": { "name": "storage.modifier.ts" @@ -1347,7 +1347,7 @@ }, "object-literal-method-declaration": { "name": "meta.method.declaration.ts", - "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?[\\(])", + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", "beginCaptures": { "1": { "name": "storage.modifier.async.ts" @@ -1368,7 +1368,7 @@ "include": "#function-body" }, { - "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?[\\(])", + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", "beginCaptures": { "1": { "name": "storage.modifier.async.ts" @@ -1428,7 +1428,7 @@ }, { "name": "meta.arrow.ts", - "begin": "(?x) (?:\n (? is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", + "begin": "(?x) (?:\n (? is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", "beginCaptures": { "1": { "name": "storage.modifier.async.ts" @@ -2413,7 +2413,7 @@ "patterns": [ { "begin": "(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "match": "(?x)(?:([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*:(\\s*\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/)*\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "0": { "name": "meta.object-literal.key.ts" @@ -2692,7 +2692,7 @@ "end": "(?=,|\\})", "patterns": [ { - "begin": "(?<=:)\\s*(async)?(?=\\s*(<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)\\(\\s*([\\{\\[]\\s*)?$)", + "begin": "(?<=:)\\s*(async)?(?=\\s*(<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)\\(\\s*([\\{\\[]\\s*)?$)", "beginCaptures": { "1": { "name": "storage.modifier.async.ts" @@ -2746,6 +2746,9 @@ } ] }, + { + "include": "#possibly-arrow-return-type" + }, { "include": "#expression" } @@ -2866,7 +2869,7 @@ "paren-expression-possibly-arrow": { "patterns": [ { - "begin": "(?<=[(=,])\\s*(async)?(?=\\s*((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?\\(\\s*[\\{\\[]\\s*$)", + "begin": "(?<=[(=,])\\s*(async)?(?=\\s*((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\(\\s*[\\{\\[]\\s*$)", "beginCaptures": { "1": { "name": "storage.modifier.async.ts" @@ -2880,7 +2883,7 @@ ] }, { - "begin": "(?<=[(=,]|=>|^return|[^\\._$[:alnum:]]return)\\s*(async)?(?=\\s*((((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?\\()|(<))\\s*$)", + "begin": "(?<=[(=,]|=>|^return|[^\\._$[:alnum:]]return)\\s*(async)?(?=\\s*((((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\()|(<))\\s*$)", "beginCaptures": { "1": { "name": "storage.modifier.async.ts" @@ -2950,7 +2953,7 @@ } }, { - "match": "(?x)(?:(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "match": "(?x)(?:(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "1": { "name": "storage.modifier.ts" @@ -3221,6 +3224,20 @@ "name": "keyword.operator.arithmetic.ts", "match": "%|\\*|/|-|\\+" }, + { + "begin": "(?<=[_$[:alnum:])\\]])\\s*(?=(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)+(/)(?![/*]))", + "end": "(/)(?!\\*([^\\*]|(\\*[^\\/]))*\\*\\/)", + "endCaptures": { + "1": { + "name": "keyword.operator.arithmetic.ts" + } + }, + "patterns": [ + { + "include": "#comment" + } + ] + }, { "match": "(?<=[_$[:alnum:])\\]])\\s*(/)(?![/*])", "captures": { @@ -3518,7 +3535,7 @@ } }, { - "match": "(?x) (?:(\\.)|(\\?\\.(?!\\s*[[:digit:]]))) \\s* (?:\n (?:(constructor|length|prototype|__proto__)\\b(?!\\$|\\s*(<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\\())\n |\n (?:(EPSILON|MAX_SAFE_INTEGER|MAX_VALUE|MIN_SAFE_INTEGER|MIN_VALUE|NEGATIVE_INFINITY|POSITIVE_INFINITY)\\b(?!\\$)))", + "match": "(?x) (?:(\\.)|(\\?\\.(?!\\s*[[:digit:]]))) \\s* (?:\n (?:(constructor|length|prototype|__proto__)\\b(?!\\$|\\s*(<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\\())\n |\n (?:(EPSILON|MAX_SAFE_INTEGER|MAX_VALUE|MIN_SAFE_INTEGER|MIN_VALUE|NEGATIVE_INFINITY|POSITIVE_INFINITY)\\b(?!\\$)))", "captures": { "1": { "name": "punctuation.accessor.ts" @@ -3590,7 +3607,7 @@ "include": "#object-identifiers" }, { - "match": "(?x)(?:(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))\\s*)?([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", + "match": "(?x)(?:(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))\\s*)?([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", "captures": { "1": { "name": "punctuation.accessor.ts" @@ -3802,7 +3819,7 @@ ] }, "possibly-arrow-return-type": { - "begin": "(?<=\\)|^)\\s*(:)(?=\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*=>)", + "begin": "(?<=\\)|^)\\s*(:)(?=\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*=>)", "beginCaptures": { "1": { "name": "meta.arrow.ts meta.return.type.arrow.ts keyword.operator.type.annotation.ts" @@ -4103,7 +4120,7 @@ }, "patterns": [ { - "match": "(?x)(?:(?)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$))))", + "match": "(?x)(?:(?)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?[\\(]\\s*([\\{\\[]\\s*)?$))))", "captures": { "1": { "name": "storage.modifier.ts" @@ -4578,7 +4595,7 @@ }, { "name": "string.regexp.ts", - "begin": "(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(\\!)?(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "beginCaptures": { "1": { "name": "meta.definition.variable.tsx entity.name.function.tsx" @@ -435,7 +435,7 @@ "name": "keyword.operator.definiteassignment.tsx" } }, - "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", + "end": "(?=$|^|[;,=}]|((?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "begin": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "beginCaptures": { "1": { "name": "meta.definition.variable.tsx variable.other.constant.tsx entity.name.function.tsx" } }, - "end": "(?=$|^|[;,=}]|(\\s+(of|in)\\s+))", + "end": "(?=$|^|[;,=}]|((?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "match": "(?x)(?:(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "1": { "name": "storage.modifier.tsx" @@ -1108,7 +1108,7 @@ "include": "#comment" }, { - "match": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?:(\\?)|(\\!))?(?=\\s*\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "match": "(?x)([_$[:alpha:]][_$[:alnum:]]*)(?:(\\?)|(\\!))?(?=\\s*\\s*\n# function assignment |\n(=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "1": { "name": "meta.definition.property.tsx entity.name.function.tsx" @@ -1144,7 +1144,7 @@ "name": "keyword.operator.assignment.tsx" } }, - "end": "(?=$|^|[,);}\\]]|(\\s+(of|in)\\s+))", + "end": "(?=$|^|[,);}\\]]|((?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?[\\(])", + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", "beginCaptures": { "1": { "name": "storage.modifier.tsx" @@ -1318,7 +1318,7 @@ }, { "name": "meta.method.declaration.tsx", - "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?[\\(])", + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", "beginCaptures": { "1": { "name": "storage.modifier.tsx" @@ -1350,7 +1350,7 @@ }, "object-literal-method-declaration": { "name": "meta.method.declaration.tsx", - "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?[\\(])", + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", "beginCaptures": { "1": { "name": "storage.modifier.async.tsx" @@ -1371,7 +1371,7 @@ "include": "#function-body" }, { - "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?[\\(])", + "begin": "(?x)(?]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?[\\(])", "beginCaptures": { "1": { "name": "storage.modifier.async.tsx" @@ -1431,7 +1431,7 @@ }, { "name": "meta.arrow.tsx", - "begin": "(?x) (?:\n (? is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", + "begin": "(?x) (?:\n (? is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n )\n)", "beginCaptures": { "1": { "name": "storage.modifier.async.tsx" @@ -2416,7 +2416,7 @@ "patterns": [ { "begin": "(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "match": "(?x)(?:([_$[:alpha:]][_$[:alnum:]]*)\\s*(?=(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*:(\\s*\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/)*\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "0": { "name": "meta.object-literal.key.tsx" @@ -2695,7 +2695,7 @@ "end": "(?=,|\\})", "patterns": [ { - "begin": "(?<=:)\\s*(async)?(?=\\s*(<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)\\(\\s*([\\{\\[]\\s*)?$)", + "begin": "(?<=:)\\s*(async)?(?=\\s*(<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)\\(\\s*([\\{\\[]\\s*)?$)", "beginCaptures": { "1": { "name": "storage.modifier.async.tsx" @@ -2749,6 +2749,9 @@ } ] }, + { + "include": "#possibly-arrow-return-type" + }, { "include": "#expression" } @@ -2869,7 +2872,7 @@ "paren-expression-possibly-arrow": { "patterns": [ { - "begin": "(?<=[(=,])\\s*(async)?(?=\\s*((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?\\(\\s*[\\{\\[]\\s*$)", + "begin": "(?<=[(=,])\\s*(async)?(?=\\s*((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\(\\s*[\\{\\[]\\s*$)", "beginCaptures": { "1": { "name": "storage.modifier.async.tsx" @@ -2883,7 +2886,7 @@ ] }, { - "begin": "(?<=[(=,]|=>|^return|[^\\._$[:alnum:]]return)\\s*(async)?(?=\\s*((((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*))?\\()|(<))\\s*$)", + "begin": "(?<=[(=,]|=>|^return|[^\\._$[:alnum:]]return)\\s*(async)?(?=\\s*((((<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*))?\\()|(<))\\s*$)", "beginCaptures": { "1": { "name": "storage.modifier.async.tsx" @@ -2953,7 +2956,7 @@ } }, { - "match": "(?x)(?:(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", + "match": "(?x)(?:(?)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)) |\n# typeannotation is fn type: < | () | (... | (param: | (param, | (param? | (param= | (param) =>\n(:\\s*(\n (<) |\n ([(]\\s*(\n ([)]) |\n (\\.\\.\\.) |\n ([_$[:alnum:]]+\\s*(\n ([:,?=])|\n ([)]\\s*=>)\n ))\n ))\n)) |\n(:\\s*((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$))) |\n(:\\s*(=>|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(<[^<>]*>)|[^<>(),=])+=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n)))", "captures": { "1": { "name": "storage.modifier.tsx" @@ -3172,6 +3175,20 @@ "name": "keyword.operator.arithmetic.tsx", "match": "%|\\*|/|-|\\+" }, + { + "begin": "(?<=[_$[:alnum:])\\]])\\s*(?=(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)+(/)(?![/*]))", + "end": "(/)(?!\\*([^\\*]|(\\*[^\\/]))*\\*\\/)", + "endCaptures": { + "1": { + "name": "keyword.operator.arithmetic.tsx" + } + }, + "patterns": [ + { + "include": "#comment" + } + ] + }, { "match": "(?<=[_$[:alnum:])\\]])\\s*(/)(?![/*])", "captures": { @@ -3469,7 +3486,7 @@ } }, { - "match": "(?x) (?:(\\.)|(\\?\\.(?!\\s*[[:digit:]]))) \\s* (?:\n (?:(constructor|length|prototype|__proto__)\\b(?!\\$|\\s*(<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\\())\n |\n (?:(EPSILON|MAX_SAFE_INTEGER|MAX_VALUE|MIN_SAFE_INTEGER|MIN_VALUE|NEGATIVE_INFINITY|POSITIVE_INFINITY)\\b(?!\\$)))", + "match": "(?x) (?:(\\.)|(\\?\\.(?!\\s*[[:digit:]]))) \\s* (?:\n (?:(constructor|length|prototype|__proto__)\\b(?!\\$|\\s*(<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\\())\n |\n (?:(EPSILON|MAX_SAFE_INTEGER|MAX_VALUE|MIN_SAFE_INTEGER|MIN_VALUE|NEGATIVE_INFINITY|POSITIVE_INFINITY)\\b(?!\\$)))", "captures": { "1": { "name": "punctuation.accessor.tsx" @@ -3541,7 +3558,7 @@ "include": "#object-identifiers" }, { - "match": "(?x)(?:(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))\\s*)?([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", + "match": "(?x)(?:(?:(\\.)|(\\?\\.(?!\\s*[[:digit:]])))\\s*)?([_$[:alpha:]][_$[:alnum:]]*)(?=\\s*=\\s*(\n ((async\\s+)?(\n (function\\s*[(<*]) |\n (function\\s+) |\n ([_$[:alpha:]][_$[:alnum:]]*\\s*=>)\n )) |\n ((async\\s*)?(\n ((<\\s*$)|([\\(]\\s*([\\{\\[]\\s*)?$)) |\n # sure shot arrow functions even if => is on new line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)?\n [(]\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*\n (\n ([)]\\s*:) | # ():\n ((\\.\\.\\.\\s*)?[_$[:alpha:]][_$[:alnum:]]*\\s*:) # [(]param: | [(]...param:\n )\n) |\n(\n [<]\\s*[_$[:alpha:]][_$[:alnum:]]*\\s+extends\\s*[^=>] # < typeparam extends\n) |\n# arrow function possible to detect only with => on same line\n(\n (<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<]|\\<\\s*([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\))|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\]))([^=<>]|=[^<])*\\>)*\\>)*>\\s*)? # typeparameters\n \\(\\s*(\\/\\*([^\\*]|(\\*[^\\/]))*\\*\\/\\s*)*(([_$[:alpha:]]|(\\{([^\\{\\}]|(\\{[^\\{\\}]*\\}))*\\})|(\\[([^\\[\\]]|(\\[[^\\[\\]]*\\]))*\\])|(\\.\\.\\.\\s*[_$[:alpha:]]))([^()]|(\\(([^\\(\\)]|(\\([^\\(\\)]*\\)))*\\)))*)?\\) # parameters\n (\\s*:\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+)? # return type\n \\s*=> # arrow operator\n)\n ))\n))", "captures": { "1": { "name": "punctuation.accessor.tsx" @@ -3753,7 +3770,7 @@ ] }, "possibly-arrow-return-type": { - "begin": "(?<=\\)|^)\\s*(:)(?=\\s*([^<>\\(\\)\\{\\}]|\\<[^<>]+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*=>)", + "begin": "(?<=\\)|^)\\s*(:)(?=\\s*([^<>\\(\\)\\{\\}]|\\<([^<>]|\\<[^<>]+\\>)+\\>|\\([^\\(\\)]+\\)|\\{[^\\{\\}]+\\})+\\s*=>)", "beginCaptures": { "1": { "name": "meta.arrow.tsx meta.return.type.arrow.tsx keyword.operator.type.annotation.tsx" @@ -4529,7 +4546,7 @@ }, { "name": "string.regexp.tsx", - "begin": "(?:*]|&&|\\|\\||\\?|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^yield|[^\\._$[:alnum:]]yield|^)\\s*(?=(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", + "begin": "(?:*]|&&|\\|\\||\\?|\\*\\/|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^yield|[^\\._$[:alnum:]]yield|^)\\s*(?=(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", "end": "(?!(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", "patterns": [ { @@ -5357,7 +5374,7 @@ ] }, "jsx-tag-in-expression": { - "begin": "(?x)\n (?:*]|&&|\\|\\||\\?|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^yield|[^\\._$[:alnum:]]yield|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", + "begin": "(?x)\n (?:*]|&&|\\|\\||\\?|\\*\\/|^await|[^\\._$[:alnum:]]await|^return|[^\\._$[:alnum:]]return|^default|[^\\._$[:alnum:]]default|^yield|[^\\._$[:alnum:]]yield|^)\\s*\n (?!<\\s*[_$[:alpha:]][_$[:alnum:]]*((\\s+extends\\s+[^=>])|,)) # look ahead is not type parameter of arrow\n (?=(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", "end": "(?!(<)\\s*(?:([_$[:alpha:]][-_$[:alnum:].]*)(?))", "patterns": [ { diff --git a/extensions/typescript-language-features/package.json b/extensions/typescript-language-features/package.json index f5516fd5f..fc003585c 100644 --- a/extensions/typescript-language-features/package.json +++ b/extensions/typescript-language-features/package.json @@ -17,13 +17,15 @@ ], "dependencies": { "jsonc-parser": "^2.0.1", + "rimraf": "^2.6.3", "semver": "5.5.1", "vscode-extension-telemetry": "0.1.1", "vscode-nls": "^4.0.0" }, "devDependencies": { - "@types/node": "8.0.33", + "@types/node": "^10.14.8", "@types/semver": "^5.5.0", + "@types/rimraf": "2.0.2", "vscode": "^1.1.10" }, "scripts": { @@ -589,6 +591,12 @@ "default": true, "description": "%configuration.surveys.enabled%", "scope": "window" + }, + "typescript.tsserver.useSeparateSyntaxServer": { + "type": "boolean", + "default": true, + "description": "%configuration.tsserver.useSeparateSyntaxServer%", + "scope": "window" } } }, diff --git a/extensions/typescript-language-features/package.nls.json b/extensions/typescript-language-features/package.nls.json index 29434c7b2..a83acf9c6 100644 --- a/extensions/typescript-language-features/package.nls.json +++ b/extensions/typescript-language-features/package.nls.json @@ -49,6 +49,7 @@ "typescript.problemMatchers.tsc.label": "TypeScript problems", "typescript.problemMatchers.tscWatch.label": "TypeScript problems (watch mode)", "configuration.suggest.paths": "Enable/disable suggestions for paths in import statements and require calls.", + "configuration.tsserver.useSeparateSyntaxServer": "Enable/disable spawning a separate TypeScript server that can more quickly respond to syntax related operations, such as calculating folding or computing document symbols. Requires using TypeScript 3.4.0 or newer in the workspace.", "typescript.locale": "Sets the locale used to report JavaScript and TypeScript errors. Requires using TypeScript 2.6.0 or newer in the workspace. Default of `null` uses VS Code's locale.", "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 using TypeScript 2.3.1 or newer in the workspace.", "configuration.suggest.autoImports": "Enable/disable auto import suggestions. Requires using TypeScript 2.6.1 or newer in the workspace.", @@ -57,7 +58,7 @@ "typescript.suggestionActions.enabled": "Enable/disable suggestion diagnostics for TypeScript files in the editor. Requires using TypeScript 2.8 or newer in the workspace.", "typescript.preferences.quoteStyle": "Preferred quote style to use for quick fixes: `single` quotes, `double` quotes, or `auto` infer quote type from existing imports. Requires using TypeScript 2.9 or newer in the workspace.", "typescript.preferences.importModuleSpecifier": "Preferred path style for auto imports.", - "typescript.preferences.importModuleSpecifier.auto": "Infer the shortest path type.", + "typescript.preferences.importModuleSpecifier.auto": "Automatically select import path style. Prefers using a relative import if `baseUrl` is configured and the relative path has fewer segments than the non-relative import.", "typescript.preferences.importModuleSpecifier.relative": "Relative to the file location.", "typescript.preferences.importModuleSpecifier.nonRelative": "Based on the `baseUrl` configured in your `jsconfig.json` / `tsconfig.json`.", "typescript.updateImportsOnFileMove.enabled": "Enable/disable automatic updating of import paths when you rename or move a file in VS Code. Requires using TypeScript 2.9 or newer in the workspace.", diff --git a/extensions/typescript-language-features/src/extension.ts b/extensions/typescript-language-features/src/extension.ts index 782aa9810..a4ec5f1bc 100644 --- a/extensions/typescript-language-features/src/extension.ts +++ b/extensions/typescript-language-features/src/extension.ts @@ -10,6 +10,8 @@ import { LanguageConfigurationManager } from './features/languageConfiguration'; import TypeScriptTaskProviderManager from './features/task'; import TypeScriptServiceClientHost from './typeScriptServiceClientHost'; import { flatten } from './utils/arrays'; +import * as electron from './utils/electron'; +import * as rimraf from 'rimraf'; import { CommandManager } from './utils/commandManager'; import * as fileSchemes from './utils/fileSchemes'; import { standardLanguageDescriptions } from './utils/languageDescription'; @@ -128,4 +130,8 @@ function isSupportedDocument( return false; } return fileSchemes.isSupportedScheme(document.uri.scheme); +} + +export function deactivate() { + rimraf.sync(electron.getInstanceDir()); } \ No newline at end of file diff --git a/extensions/typescript-language-features/src/features/bufferSyncSupport.ts b/extensions/typescript-language-features/src/features/bufferSyncSupport.ts index 887aec2fa..f662cb21a 100644 --- a/extensions/typescript-language-features/src/features/bufferSyncSupport.ts +++ b/extensions/typescript-language-features/src/features/bufferSyncSupport.ts @@ -34,6 +34,27 @@ function mode2ScriptKind(mode: string): 'TS' | 'TSX' | 'JS' | 'JSX' | undefined return undefined; } +class CloseOperation { + readonly type = 'close'; + constructor( + public readonly args: string + ) { } +} + +class OpenOperation { + readonly type = 'open'; + constructor( + public readonly args: Proto.OpenRequestArgs + ) { } +} + +class ChangeOperation { + readonly type = 'change'; + constructor( + public readonly args: Proto.FileCodeEdits + ) { } +} + /** * Manages synchronization of buffers with the TS server. * @@ -41,8 +62,7 @@ function mode2ScriptKind(mode: string): 'TS' | 'TSX' | 'JS' | 'JSX' | undefined */ class BufferSynchronizer { - private _pending: Proto.UpdateOpenRequestArgs = {}; - private _pendingFiles = new Set(); + private readonly _pending = new Map(); constructor( private readonly client: ITypeScriptServiceClient @@ -51,10 +71,7 @@ class BufferSynchronizer { public open(args: Proto.OpenRequestArgs) { if (this.supportsBatching) { this.updatePending(args.file, pending => { - if (!pending.openFiles) { - pending.openFiles = []; - } - pending.openFiles.push(args); + pending.set(args.file, new OpenOperation(args)); }); } else { this.client.executeWithoutWaitingForResponse('open', args); @@ -64,10 +81,7 @@ class BufferSynchronizer { public close(filepath: string) { if (this.supportsBatching) { this.updatePending(filepath, pending => { - if (!pending.closedFiles) { - pending.closedFiles = []; - } - pending.closedFiles.push(filepath); + pending.set(filepath, new CloseOperation(filepath)); }); } else { const args: Proto.FileRequestArgs = { file: filepath }; @@ -75,25 +89,21 @@ class BufferSynchronizer { } } - public change(filepath: string, events: vscode.TextDocumentContentChangeEvent[]) { + public change(filepath: string, events: readonly vscode.TextDocumentContentChangeEvent[]) { if (!events.length) { return; } if (this.supportsBatching) { this.updatePending(filepath, pending => { - if (!pending.changedFiles) { - pending.changedFiles = []; - } - - pending.changedFiles.push({ + pending.set(filepath, new ChangeOperation({ fileName: filepath, textChanges: events.map((change): Proto.CodeEdit => ({ newText: change.text, start: typeConverters.Position.toLocation(change.range.start), end: typeConverters.Position.toLocation(change.range.end), })).reverse(), // Send the edits end-of-document to start-of-document order - }); + })); }); } else { for (const { range, text } of events) { @@ -117,13 +127,23 @@ class BufferSynchronizer { private flush() { if (!this.supportsBatching) { // We've already eagerly synchronized + this._pending.clear(); return; } - if (this._pending.changedFiles || this._pending.closedFiles || this._pending.openFiles) { - this.client.executeWithoutWaitingForResponse('updateOpen', this._pending); - this._pending = {}; - this._pendingFiles.clear(); + if (this._pending.size > 0) { + const closedFiles: string[] = []; + const openFiles: Proto.OpenRequestArgs[] = []; + const changedFiles: Proto.FileCodeEdits[] = []; + for (const change of this._pending.values()) { + switch (change.type) { + case 'change': changedFiles.push(change.args); break; + case 'open': openFiles.push(change.args); break; + case 'close': closedFiles.push(change.args); break; + } + } + this.client.executeWithoutWaitingForResponse('updateOpen', { changedFiles, closedFiles, openFiles }); + this._pending.clear(); } } @@ -131,15 +151,12 @@ class BufferSynchronizer { return this.client.apiVersion.gte(API.v340) && vscode.workspace.getConfiguration('typescript', null).get('useBatchedBufferSync', true); } - private updatePending(filepath: string, f: (pending: Proto.UpdateOpenRequestArgs) => void): void { - if (this.supportsBatching && this._pendingFiles.has(filepath)) { + private updatePending(filepath: string, f: (pending: Map) => void): void { + if (this._pending.has(filepath)) { + // we saw this file before, make sure we flush before working with it again this.flush(); - this._pendingFiles.clear(); - f(this._pending); - this._pendingFiles.add(filepath); - } else { - f(this._pending); } + f(this._pending); } } @@ -210,7 +227,7 @@ class SyncedBuffer { this.state = BufferState.Closed; } - public onContentChanged(events: vscode.TextDocumentContentChangeEvent[]): void { + public onContentChanged(events: readonly vscode.TextDocumentContentChangeEvent[]): void { if (this.state !== BufferState.Open) { console.error(`Unexpected buffer state: ${this.state}`); } @@ -470,20 +487,20 @@ export default class BufferSyncSupport extends Disposable { private sendPendingDiagnostics(): void { const orderedFileSet = this.pendingDiagnostics.getOrderedFileSet(); + if (this.pendingGetErr) { + this.pendingGetErr.cancel(); + + for (const file of this.pendingGetErr.files.entries) { + orderedFileSet.set(file.resource, undefined); + } + } + // Add all open TS buffers to the geterr request. They might be visible for (const buffer of this.syncedBuffers.values) { orderedFileSet.set(buffer.resource, undefined); } if (orderedFileSet.size) { - if (this.pendingGetErr) { - this.pendingGetErr.cancel(); - - for (const file of this.pendingGetErr.files.entries) { - orderedFileSet.set(file.resource, undefined); - } - } - const getErr = this.pendingGetErr = GetErrRequest.executeGetErrRequest(this.client, orderedFileSet, () => { if (this.pendingGetErr === getErr) { this.pendingGetErr = undefined; diff --git a/extensions/typescript-language-features/src/features/completions.ts b/extensions/typescript-language-features/src/features/completions.ts index dbb83c3f8..fdfabd436 100644 --- a/extensions/typescript-language-features/src/features/completions.ts +++ b/extensions/typescript-language-features/src/features/completions.ts @@ -50,12 +50,7 @@ class MyCompletionItem extends vscode.CompletionItem { ) { super(tsEntry.name, MyCompletionItem.convertKind(tsEntry.kind)); - if (tsEntry.isRecommended) { - // Make sure isRecommended property always comes first - // https://github.com/Microsoft/vscode/issues/40325 - this.sortText = tsEntry.sortText; - this.preselect = true; - } else if (tsEntry.source) { + if (tsEntry.source) { // De-prioritze auto-imports // https://github.com/Microsoft/vscode/issues/40311 this.sortText = '\uffff' + tsEntry.sortText; @@ -63,6 +58,10 @@ class MyCompletionItem extends vscode.CompletionItem { this.sortText = tsEntry.sortText; } + if (tsEntry.isRecommended) { + this.preselect = true; + } + this.position = position; this.useCodeSnippet = useCodeSnippetsOnMethodSuggest && (this.kind === vscode.CompletionItemKind.Function || this.kind === vscode.CompletionItemKind.Method); @@ -75,7 +74,9 @@ class MyCompletionItem extends vscode.CompletionItem { } this.insertText = tsEntry.insertText; - this.filterText = tsEntry.insertText; + // Set filterText for intelliCode and bracket accessors , but not for `this.` completions since it results in + // them being overly prioritized. #74164 + this.filterText = tsEntry.insertText && !/^this\./.test(tsEntry.insertText) ? tsEntry.insertText : undefined; if (completionContext.isMemberCompletion && completionContext.dotAccessorContext) { this.filterText = completionContext.dotAccessorContext.text + (this.insertText || this.label); @@ -87,7 +88,6 @@ class MyCompletionItem extends vscode.CompletionItem { if (tsEntry.kindModifiers) { const kindModifiers = new Set(tsEntry.kindModifiers.split(/\s+/g)); - if (kindModifiers.has(PConst.KindModifiers.optional)) { if (!this.insertText) { this.insertText = this.label; @@ -205,7 +205,6 @@ class MyCompletionItem extends vscode.CompletionItem { case PConst.Kind.enum: case PConst.Kind.interface: commitCharacters.push('.', ';'); - break; case PConst.Kind.module: @@ -400,7 +399,7 @@ class TypeScriptCompletionItemProvider implements vscode.CompletionItemProvider "type" : { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }, "count" : { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" }, "${include}": [ - "${TypeScriptCommonProperties}", + "${TypeScriptCommonProperties}" ] } */ @@ -659,7 +658,7 @@ class TypeScriptCompletionItemProvider implements vscode.CompletionItemProvider token: vscode.CancellationToken ): Promise { // Workaround for https://github.com/Microsoft/TypeScript/issues/12677 - // Don't complete function calls inside of destructive assigments or imports + // Don't complete function calls inside of destructive assignments or imports try { const args: Proto.FileLocationRequestArgs = typeConverters.Position.toFileLocationRequestArgs(filepath, position); const response = await this.client.execute('quickinfo', args, token); diff --git a/extensions/typescript-language-features/src/features/definitions.ts b/extensions/typescript-language-features/src/features/definitions.ts index 5fe72c200..fd3a1f10e 100644 --- a/extensions/typescript-language-features/src/features/definitions.ts +++ b/extensions/typescript-language-features/src/features/definitions.ts @@ -37,10 +37,18 @@ export default class TypeScriptDefinitionProvider extends DefinitionProviderBase return response.body.definitions .map((location): vscode.DefinitionLink => { const target = typeConverters.Location.fromTextSpan(this.client.toResource(location.file), location); + if ((location as any).contextStart) { + return { + originSelectionRange: span, + targetRange: typeConverters.Range.fromLocations((location as any).contextStart, (location as any).contextEnd), + targetUri: target.uri, + targetSelectionRange: target.range, + }; + } return { originSelectionRange: span, targetRange: target.range, - targetUri: target.uri, + targetUri: target.uri }; }); } diff --git a/extensions/typescript-language-features/src/features/diagnostics.ts b/extensions/typescript-language-features/src/features/diagnostics.ts index a9de15ab5..327573e8c 100644 --- a/extensions/typescript-language-features/src/features/diagnostics.ts +++ b/extensions/typescript-language-features/src/features/diagnostics.ts @@ -5,7 +5,27 @@ import * as vscode from 'vscode'; import { ResourceMap } from '../utils/resourceMap'; -import { DiagnosticLanguage, allDiagnosticLanguages } from '../utils/languageDescription'; +import { DiagnosticLanguage } from '../utils/languageDescription'; +import * as arrays from '../utils/arrays'; +import { Disposable } from '../utils/dispose'; + +function diagnosticsEquals(a: vscode.Diagnostic, b: vscode.Diagnostic): boolean { + if (a === b) { + return true; + } + + return a.code === b.code + && a.message === b.message + && a.severity === b.severity + && a.source === b.source + && a.range.isEqual(b.range) + && arrays.equals(a.relatedInformation || arrays.empty, b.relatedInformation || arrays.empty, (a, b) => { + return a.message === b.message + && a.location.range.isEqual(b.location.range) + && a.location.uri.fsPath === b.location.uri.fsPath; + }) + && arrays.equals(a.tags || arrays.empty, b.tags || arrays.empty); +} export const enum DiagnosticKind { Syntax, @@ -14,7 +34,7 @@ export const enum DiagnosticKind { } class FileDiagnostics { - private readonly _diagnostics = new Map(); + private readonly _diagnostics = new Map>(); constructor( public readonly file: vscode.Uri, @@ -24,19 +44,17 @@ class FileDiagnostics { public updateDiagnostics( language: DiagnosticLanguage, kind: DiagnosticKind, - diagnostics: vscode.Diagnostic[] + diagnostics: ReadonlyArray ): boolean { if (language !== this.language) { this._diagnostics.clear(); this.language = language; } - if (diagnostics.length === 0) { - const existing = this._diagnostics.get(kind); - if (!existing || existing && existing.length === 0) { - // No need to update - return false; - } + const existing = this._diagnostics.get(kind); + if (arrays.equals(existing || arrays.empty, diagnostics, diagnosticsEquals)) { + // No need to update + return false; } this._diagnostics.set(kind, diagnostics); @@ -60,13 +78,13 @@ class FileDiagnostics { return this.get(DiagnosticKind.Suggestion).filter(x => { if (!enableSuggestions) { // Still show unused - return x.tags && x.tags.indexOf(vscode.DiagnosticTag.Unnecessary) !== -1; + return x.tags && x.tags.includes(vscode.DiagnosticTag.Unnecessary); } return true; }); } - private get(kind: DiagnosticKind): vscode.Diagnostic[] { + private get(kind: DiagnosticKind): ReadonlyArray { return this._diagnostics.get(kind) || []; } } @@ -76,6 +94,11 @@ interface LanguageDiagnosticSettings { readonly enableSuggestions: boolean; } +function areLanguageDiagnosticSettingsEqual(currentSettings: LanguageDiagnosticSettings, newSettings: LanguageDiagnosticSettings): boolean { + return currentSettings.validate === newSettings.validate + && currentSettings.enableSuggestions && currentSettings.enableSuggestions; +} + class DiagnosticSettings { private static readonly defaultSettings: LanguageDiagnosticSettings = { validate: true, @@ -84,12 +107,6 @@ class DiagnosticSettings { private readonly _languageSettings = new Map(); - constructor() { - for (const language of allDiagnosticLanguages) { - this._languageSettings.set(language, DiagnosticSettings.defaultSettings); - } - } - public getValidate(language: DiagnosticLanguage): boolean { return this.get(language).validate; } @@ -120,12 +137,11 @@ class DiagnosticSettings { const currentSettings = this.get(language); const newSettings = f(currentSettings); this._languageSettings.set(language, newSettings); - return currentSettings.validate === newSettings.validate - && currentSettings.enableSuggestions && currentSettings.enableSuggestions; + return areLanguageDiagnosticSettingsEqual(currentSettings, newSettings); } } -export class DiagnosticsManager { +export class DiagnosticsManager extends Disposable { private readonly _diagnostics = new ResourceMap(); private readonly _settings = new DiagnosticSettings(); private readonly _currentDiagnostics: vscode.DiagnosticCollection; @@ -136,11 +152,12 @@ export class DiagnosticsManager { constructor( owner: string ) { - this._currentDiagnostics = vscode.languages.createDiagnosticCollection(owner); + super(); + this._currentDiagnostics = this._register(vscode.languages.createDiagnosticCollection(owner)); } public dispose() { - this._currentDiagnostics.dispose(); + super.dispose(); for (const value of this._pendingUpdates.values) { clearTimeout(value); @@ -171,7 +188,7 @@ export class DiagnosticsManager { file: vscode.Uri, language: DiagnosticLanguage, kind: DiagnosticKind, - diagnostics: vscode.Diagnostic[] + diagnostics: ReadonlyArray ): void { let didUpdate = false; const entry = this._diagnostics.get(file); @@ -191,7 +208,7 @@ export class DiagnosticsManager { public configFileDiagnosticsReceived( file: vscode.Uri, - diagnostics: vscode.Diagnostic[] + diagnostics: ReadonlyArray ): void { this._currentDiagnostics.set(file, diagnostics); } @@ -201,7 +218,7 @@ export class DiagnosticsManager { this._diagnostics.delete(resource); } - public getDiagnostics(file: vscode.Uri): vscode.Diagnostic[] { + public getDiagnostics(file: vscode.Uri): ReadonlyArray { return this._currentDiagnostics.get(file) || []; } @@ -227,4 +244,4 @@ export class DiagnosticsManager { this._currentDiagnostics.set(fileDiagnostic.file, fileDiagnostic.getDiagnostics(this._settings)); } } -} \ No newline at end of file +} diff --git a/extensions/typescript-language-features/src/features/implementationsCodeLens.ts b/extensions/typescript-language-features/src/features/implementationsCodeLens.ts index 63cfc6222..c732ade52 100644 --- a/extensions/typescript-language-features/src/features/implementationsCodeLens.ts +++ b/extensions/typescript-language-features/src/features/implementationsCodeLens.ts @@ -26,7 +26,7 @@ export default class TypeScriptImplementationsCodeLensProvider extends TypeScrip const codeLens = inputCodeLens as ReferencesCodeLens; const args = typeConverters.Position.toFileLocationRequestArgs(codeLens.file, codeLens.range.start); - const response = await this.client.execute('implementation', args, token, /* lowPriority */ true); + const response = await this.client.execute('implementation', args, token, { lowPriority: true }); if (response.type !== 'response' || !response.body) { codeLens.command = response.type === 'cancelled' ? TypeScriptBaseCodeLensProvider.cancelledCommand diff --git a/extensions/typescript-language-features/src/features/quickFix.ts b/extensions/typescript-language-features/src/features/quickFix.ts index 8972df521..6ce9f1997 100644 --- a/extensions/typescript-language-features/src/features/quickFix.ts +++ b/extensions/typescript-language-features/src/features/quickFix.ts @@ -314,6 +314,7 @@ const preferredFixes = new Set([ 'forgottenThisPropertyAccess', 'spelling', 'unusedIdentifier', + 'addMissingAwait', ]); function isPreferredFix(tsAction: Proto.CodeFixAction): boolean { return preferredFixes.has(tsAction.fixName); diff --git a/extensions/typescript-language-features/src/features/refactor.ts b/extensions/typescript-language-features/src/features/refactor.ts index a3a7bb629..6b0d33a2b 100644 --- a/extensions/typescript-language-features/src/features/refactor.ts +++ b/extensions/typescript-language-features/src/features/refactor.ts @@ -14,6 +14,7 @@ import { VersionDependentRegistration } from '../utils/dependentRegistration'; import TelemetryReporter from '../utils/telemetry'; import * as typeConverters from '../utils/typeConverters'; import FormattingOptionsManager from './fileConfigurationManager'; +import { file } from '../utils/fileSchemes'; const localize = nls.loadMessageBundle(); @@ -79,7 +80,10 @@ class ApplyRefactoringCommand implements Command { private async toWorkspaceEdit(body: Proto.RefactorEditInfo) { const workspaceEdit = new vscode.WorkspaceEdit(); for (const edit of body.edits) { - workspaceEdit.createFile(this.client.toResource(edit.fileName), { ignoreIfExists: true }); + const resource = this.client.toResource(edit.fileName); + if (resource.scheme === file) { + workspaceEdit.createFile(resource, { ignoreIfExists: true }); + } } typeConverters.WorkspaceEdit.withFileCodeEdits(workspaceEdit, this.client, body.edits); return workspaceEdit; @@ -116,6 +120,7 @@ class TypeScriptRefactorProvider implements vscode.CodeActionProvider { private static readonly extractFunctionKind = vscode.CodeActionKind.RefactorExtract.append('function'); private static readonly extractConstantKind = vscode.CodeActionKind.RefactorExtract.append('constant'); + private static readonly extractTypeKind = vscode.CodeActionKind.RefactorExtract.append('type'); private static readonly moveKind = vscode.CodeActionKind.Refactor.append('move'); constructor( @@ -217,6 +222,8 @@ class TypeScriptRefactorProvider implements vscode.CodeActionProvider { return TypeScriptRefactorProvider.extractConstantKind; } else if (refactor.name.startsWith('Move')) { return TypeScriptRefactorProvider.moveKind; + } else if (refactor.name.includes('Extract to type alias')) { + return TypeScriptRefactorProvider.extractTypeKind; } return vscode.CodeActionKind.Refactor; } @@ -227,6 +234,9 @@ class TypeScriptRefactorProvider implements vscode.CodeActionProvider { if (action.name.startsWith('constant_')) { return action.name.endsWith('scope_0'); } + if (action.name.includes('Extract to type alias')) { + return true; + } return false; } } diff --git a/extensions/typescript-language-features/src/features/referencesCodeLens.ts b/extensions/typescript-language-features/src/features/referencesCodeLens.ts index ff09a9a43..65c2cd5eb 100644 --- a/extensions/typescript-language-features/src/features/referencesCodeLens.ts +++ b/extensions/typescript-language-features/src/features/referencesCodeLens.ts @@ -22,7 +22,7 @@ class TypeScriptReferencesCodeLensProvider extends TypeScriptBaseCodeLensProvide public async resolveCodeLens(inputCodeLens: vscode.CodeLens, token: vscode.CancellationToken): Promise { const codeLens = inputCodeLens as ReferencesCodeLens; const args = typeConverters.Position.toFileLocationRequestArgs(codeLens.file, codeLens.range.start); - const response = await this.client.execute('references', args, token, /* lowPriority */ true); + const response = await this.client.execute('references', args, token, { lowPriority: true }); if (response.type !== 'response' || !response.body) { codeLens.command = response.type === 'cancelled' ? TypeScriptBaseCodeLensProvider.cancelledCommand diff --git a/extensions/typescript-language-features/src/features/smartSelect.ts b/extensions/typescript-language-features/src/features/smartSelect.ts index a9a0370be..3d05d1309 100644 --- a/extensions/typescript-language-features/src/features/smartSelect.ts +++ b/extensions/typescript-language-features/src/features/smartSelect.ts @@ -27,7 +27,7 @@ class SmartSelection implements vscode.SelectionRangeProvider { return undefined; } - const args: Proto.FileRequestArgs & { locations: Proto.Location[] } = { + const args: Proto.SelectionRangeRequestArgs = { file, locations: positions.map(typeConverters.Position.toLocation) }; diff --git a/extensions/typescript-language-features/src/features/tagClosing.ts b/extensions/typescript-language-features/src/features/tagClosing.ts index c8db74597..1123b1755 100644 --- a/extensions/typescript-language-features/src/features/tagClosing.ts +++ b/extensions/typescript-language-features/src/features/tagClosing.ts @@ -46,7 +46,7 @@ class TagClosing extends Disposable { private onDidChangeTextDocument( document: vscode.TextDocument, - changes: vscode.TextDocumentContentChangeEvent[] + changes: readonly vscode.TextDocumentContentChangeEvent[] ) { const activeDocument = vscode.window.activeTextEditor && vscode.window.activeTextEditor.document; if (document !== activeDocument || changes.length === 0) { diff --git a/extensions/typescript-language-features/src/features/task.ts b/extensions/typescript-language-features/src/features/task.ts index 1b1d4d3bd..d9fa6f783 100644 --- a/extensions/typescript-language-features/src/features/task.ts +++ b/extensions/typescript-language-features/src/features/task.ts @@ -72,6 +72,12 @@ class TscTaskProvider implements vscode.TaskProvider { } public resolveTask(_task: vscode.Task): vscode.Task | undefined { + const definition = _task.definition; + const badTsconfig = /\\tsconfig.*\.json/; + if (badTsconfig.exec(definition.tsconfig) !== null) { + // Warn that the task has the wrong slash type + vscode.window.showWarningMessage(localize('badTsConfig', "Typescript Task in tasks.json contains \"\\\\\". Typescript tasks tsconfig must use \"/\"")); + } return undefined; } @@ -96,6 +102,7 @@ class TscTaskProvider implements vscode.TaskProvider { const uri = editor.document.uri; return [{ path: uri.fsPath, + posixPath: uri.path, workspaceFolder: vscode.workspace.getWorkspaceFolder(uri) }]; } @@ -121,6 +128,7 @@ class TscTaskProvider implements vscode.TaskProvider { const folder = vscode.workspace.getWorkspaceFolder(uri); return [{ path: normalizedConfigPath, + posixPath: uri.path, workspaceFolder: folder }]; } @@ -232,9 +240,11 @@ class TscTaskProvider implements vscode.TaskProvider { private getLabelForTasks(project: TSConfig): string { if (project.workspaceFolder) { - return path.relative(project.workspaceFolder.uri.fsPath, project.path); + const workspaceNormalizedUri = vscode.Uri.file(path.normalize(project.workspaceFolder.uri.fsPath)); // Make sure the drive letter is lowercase + return path.posix.relative(workspaceNormalizedUri.path, project.posixPath); } - return project.path; + + return project.posixPath; } private onConfigurationChanged(): void { diff --git a/extensions/typescript-language-features/src/test/completions.test.ts b/extensions/typescript-language-features/src/test/completions.test.ts index 563930d78..4d1d79dcc 100644 --- a/extensions/typescript-language-features/src/test/completions.test.ts +++ b/extensions/typescript-language-features/src/test/completions.test.ts @@ -131,6 +131,9 @@ suite('TypeScript Completions', () => { 'const x = { "hello world2": 1 };', `x["hello world2"]${insert}` )); + + disposeAll(_disposables); + await vscode.commands.executeCommand('workbench.action.closeAllEditors'); } }); @@ -160,7 +163,7 @@ suite('TypeScript Completions', () => { `f('abc.abc$0')` ); - const document = await acceptFirstSuggestion(testDocumentUri, _disposables); + const document = await acceptFirstSuggestion(testDocumentUri, _disposables, { useLineRange: true }); assert.strictEqual( document.getText(), joinLines( @@ -264,15 +267,38 @@ suite('TypeScript Completions', () => { `abcdef(1, 2, 3)` )); }); + + test('should not de-prioritized this.member suggestion, #74164', async () => { + await createTestEditor(testDocumentUri, + `class A {`, + ` private detail = '';`, + ` foo() {`, + ` det$0`, + ` }`, + `}`, + ); + + const document = await acceptFirstSuggestion(testDocumentUri, _disposables); + assert.strictEqual( + document.getText(), + joinLines( + `class A {`, + ` private detail = '';`, + ` foo() {`, + ` this.detail`, + ` }`, + `}`, + )); + }); }); const joinLines = (...args: string[]) => args.join('\n'); const wait = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); -async function acceptFirstSuggestion(uri: vscode.Uri, _disposables: vscode.Disposable[]) { +async function acceptFirstSuggestion(uri: vscode.Uri, _disposables: vscode.Disposable[], options?: { useLineRange?: boolean }) { const didChangeDocument = onChangedDocument(uri, _disposables); - const didSuggest = onDidSuggest(_disposables); + const didSuggest = onDidSuggest(_disposables, options); await vscode.commands.executeCommand('editor.action.triggerSuggest'); await didSuggest; // TODO: depends on reverting fix for https://github.com/Microsoft/vscode/issues/64257 @@ -310,12 +336,14 @@ async function createTestEditor(uri: vscode.Uri, ...lines: string[]) { await activeEditor.insertSnippet(new vscode.SnippetString(joinLines(...lines)), new vscode.Range(0, 0, 1000, 0)); } -function onDidSuggest(disposables: vscode.Disposable[]) { +function onDidSuggest(disposables: vscode.Disposable[], options?: { useLineRange?: boolean }) { return new Promise(resolve => disposables.push(vscode.languages.registerCompletionItemProvider('typescript', new class implements vscode.CompletionItemProvider { provideCompletionItems(doc: vscode.TextDocument, position: vscode.Position): vscode.ProviderResult { // Return a fake item that will come first - const range = new vscode.Range(new vscode.Position(position.line, 0), position); + const range = options && options.useLineRange + ? new vscode.Range(new vscode.Position(position.line, 0), position) + : doc.getWordRangeAtPosition(position); return [{ label: '🦄', insertText: doc.getText(range), diff --git a/extensions/typescript-language-features/src/test/functionCallSnippet.test.ts b/extensions/typescript-language-features/src/test/functionCallSnippet.test.ts index 653890616..e053719f3 100644 --- a/extensions/typescript-language-features/src/test/functionCallSnippet.test.ts +++ b/extensions/typescript-language-features/src/test/functionCallSnippet.test.ts @@ -6,7 +6,7 @@ import * as assert from 'assert'; import 'mocha'; import * as vscode from 'vscode'; -import { snippetForFunctionCall } from "../utils/snippetForFunctionCall"; +import { snippetForFunctionCall } from '../utils/snippetForFunctionCall'; suite('typescript function call snippets', () => { test('Should use label as function name', async () => { diff --git a/extensions/typescript-language-features/src/test/server.test.ts b/extensions/typescript-language-features/src/test/server.test.ts new file mode 100644 index 000000000..651967fc1 --- /dev/null +++ b/extensions/typescript-language-features/src/test/server.test.ts @@ -0,0 +1,76 @@ +/*--------------------------------------------------------------------------------------------- + * 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 'mocha'; +import * as stream from 'stream'; +import { PipeRequestCanceller, TsServerProcess, ProcessBasedTsServer } from '../tsServer/server'; +import { nulToken } from '../utils/cancellation'; +import Logger from '../utils/logger'; +import TelemetryReporter from '../utils/telemetry'; +import Tracer from '../utils/tracer'; +import * as Proto from '../protocol'; + + +const NoopTelemetryReporter = new class implements TelemetryReporter { + logTelemetry(): void { /* noop */ } + dispose(): void { /* noop */ } +}; + +class FakeServerProcess implements TsServerProcess { + private readonly _out: stream.PassThrough; + + private readonly writeListeners = new Set<(data: Buffer) => void>(); + public stdout: stream.PassThrough; + + constructor() { + this._out = new stream.PassThrough(); + this.stdout = this._out; + } + + public write(data: Proto.Request) { + const listeners = Array.from(this.writeListeners); + this.writeListeners.clear(); + + setImmediate(() => { + for (const listener of listeners) { + listener(Buffer.from(JSON.stringify(data), 'utf8')); + } + const body = Buffer.from(JSON.stringify({ 'seq': data.seq, 'type': 'response', 'command': data.command, 'request_seq': data.seq, 'success': true }), 'utf8'); + this._out.write(Buffer.from(`Content-Length: ${body.length}\r\n\r\n${body}`, 'utf8')); + }); + } + + + on(_name: any, _handler: any) { /* noop */ } + + kill(): void { /* noop */ } + + public onWrite(): Promise { + return new Promise((resolve) => { + this.writeListeners.add((data) => { + resolve(JSON.parse(data.toString())); + }); + }); + } +} + +suite('Server', () => { + const tracer = new Tracer(new Logger()); + + test('should send requests with increasing sequence numbers', async () => { + const process = new FakeServerProcess(); + const server = new ProcessBasedTsServer('semantic', process, undefined, new PipeRequestCanceller('semantic', undefined, tracer), undefined!, NoopTelemetryReporter, tracer); + + const onWrite1 = process.onWrite(); + server.executeImpl('geterr', {}, { isAsync: false, token: nulToken, expectsResult: true }); + assert.strictEqual((await onWrite1).seq, 0); + + const onWrite2 = process.onWrite(); + server.executeImpl('geterr', {}, { isAsync: false, token: nulToken, expectsResult: true }); + assert.strictEqual((await onWrite2).seq, 1); + }); +}); + diff --git a/extensions/typescript-language-features/src/tsServer/server.ts b/extensions/typescript-language-features/src/tsServer/server.ts index b1cf5b785..f10b02abf 100644 --- a/extensions/typescript-language-features/src/tsServer/server.ts +++ b/extensions/typescript-language-features/src/tsServer/server.ts @@ -3,261 +3,99 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as cp from 'child_process'; import * as fs from 'fs'; -import * as path from 'path'; +import * as stream from 'stream'; import * as vscode from 'vscode'; import * as Proto from '../protocol'; -import { ServerResponse } from '../typescriptService'; -import API from '../utils/api'; -import { TsServerLogLevel, TypeScriptServiceConfiguration } from '../utils/configuration'; +import { ServerResponse, TypeScriptRequests } from '../typescriptService'; import { Disposable } from '../utils/dispose'; -import * as electron from '../utils/electron'; -import LogDirectoryProvider from '../utils/logDirectoryProvider'; -import Logger from '../utils/logger'; -import { TypeScriptPluginPathsProvider } from '../utils/pluginPathsProvider'; -import { PluginManager } from '../utils/plugins'; -import { escapeRegExp } from '../utils/regexp'; import TelemetryReporter from '../utils/telemetry'; import Tracer from '../utils/tracer'; -import { TypeScriptVersion, TypeScriptVersionProvider } from '../utils/versionProvider'; +import { TypeScriptVersion } from '../utils/versionProvider'; import { Reader } from '../utils/wireProtocol'; import { CallbackMap } from './callbackMap'; import { RequestItem, RequestQueue, RequestQueueingType } from './requestQueue'; +import { TypeScriptServerError } from './serverError'; -class TypeScriptServerError extends Error { - - public static create( - version: TypeScriptVersion, - response: Proto.Response, - ): TypeScriptServerError { - const parsedResult = TypeScriptServerError.parseErrorText(version, response); - return new TypeScriptServerError(version, response, - parsedResult ? parsedResult.message : undefined, - parsedResult ? parsedResult.stack : undefined); - } - - constructor( - version: TypeScriptVersion, - private readonly response: Proto.Response, - public readonly serverMessage: string | undefined, - public readonly serverStack: string | undefined, - ) { - super(`TypeScript Server Error (${version.versionString})\n${serverMessage}\n${serverStack}`); - } - - public get serverErrorText() { - return this.response.message; - } - - public get serverCommand() { - return this.response.command; - } - - /** - * Given a `errorText` from a tsserver request indicating failure in handling a request, - * prepares a payload for telemetry-logging. - */ - private static parseErrorText( - version: TypeScriptVersion, - response: Proto.Response, - ) { - const errorText = response.message; - if (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. - return { - message: prefixFreeErrorText.substring(0, newlineIndex), - stack: TypeScriptServerError.normalizeMessageStack(version, prefixFreeErrorText.substring(newlineIndex + 1)) - }; - } - } - } - return undefined; - } - - /** - * Try to replace full TS Server paths with 'tsserver.js' so that we don't have to post process the data as much - */ - private static normalizeMessageStack( - version: TypeScriptVersion, - message: string | undefined, - ) { - if (!message) { - return ''; - } - return message.replace(new RegExp(`${escapeRegExp(version.path)}[/\\\\]tsserver.js:`, 'gi'), 'tsserver.js:'); - } +export interface OngoingRequestCanceller { + tryCancelOngoingRequest(seq: number): boolean; } -export class TypeScriptServerSpawner { +export class PipeRequestCanceller implements OngoingRequestCanceller { public constructor( - private readonly _versionProvider: TypeScriptVersionProvider, - private readonly _logDirectoryProvider: LogDirectoryProvider, - private readonly _pluginPathsProvider: TypeScriptPluginPathsProvider, - private readonly _logger: Logger, - private readonly _telemetryReporter: TelemetryReporter, + private readonly _serverId: string, + private readonly _cancellationPipeName: string | undefined, private readonly _tracer: Tracer, ) { } - public spawn( - version: TypeScriptVersion, - configuration: TypeScriptServiceConfiguration, - pluginManager: PluginManager - ): TypeScriptServer { - const apiVersion = version.version || API.defaultVersion; - - const { args, cancellationPipeName, tsServerLogFile } = this.getTsServerArgs(configuration, version, apiVersion, pluginManager); - - if (TypeScriptServerSpawner.isLoggingEnabled(apiVersion, configuration)) { - if (tsServerLogFile) { - this._logger.info(`TSServer log file: ${tsServerLogFile}`); - } else { - this._logger.error('Could not create TSServer log directory'); - } - } - - this._logger.info('Forking TSServer'); - const childProcess = electron.fork(version.tsServerPath, args, this.getForkOptions()); - this._logger.info('Started TSServer'); - - return new TypeScriptServer(childProcess, tsServerLogFile, cancellationPipeName, version, this._telemetryReporter, this._tracer); - } - - private getForkOptions() { - const debugPort = TypeScriptServerSpawner.getDebugPort(); - const tsServerForkOptions: electron.ForkOptions = { - execArgv: debugPort ? [`--inspect=${debugPort}`] : [], - }; - return tsServerForkOptions; - } - - private getTsServerArgs( - configuration: TypeScriptServiceConfiguration, - currentVersion: TypeScriptVersion, - apiVersion: API, - pluginManager: PluginManager, - ): { args: string[], cancellationPipeName: string | undefined, tsServerLogFile: string | undefined } { - const args: string[] = []; - let cancellationPipeName: string | undefined; - let tsServerLogFile: string | undefined; - - if (apiVersion.gte(API.v206)) { - if (apiVersion.gte(API.v250)) { - args.push('--useInferredProjectPerProjectRoot'); - } else { - args.push('--useSingleInferredProject'); - } - - if (configuration.disableAutomaticTypeAcquisition) { - args.push('--disableAutomaticTypingAcquisition'); - } - } - - if (apiVersion.gte(API.v208)) { - args.push('--enableTelemetry'); - } - - if (apiVersion.gte(API.v222)) { - cancellationPipeName = electron.getTempFile('tscancellation'); - args.push('--cancellationPipeName', cancellationPipeName + '*'); - } - - if (TypeScriptServerSpawner.isLoggingEnabled(apiVersion, configuration)) { - const logDir = this._logDirectoryProvider.getNewLogDirectory(); - if (logDir) { - tsServerLogFile = path.join(logDir, `tsserver.log`); - args.push('--logVerbosity', TsServerLogLevel.toString(configuration.tsServerLogLevel)); - args.push('--logFile', tsServerLogFile); - } + public tryCancelOngoingRequest(seq: number): boolean { + if (!this._cancellationPipeName) { + return false; } - - if (apiVersion.gte(API.v230)) { - const pluginPaths = this._pluginPathsProvider.getPluginPaths(); - - if (pluginManager.plugins.length) { - args.push('--globalPlugins', pluginManager.plugins.map(x => x.name).join(',')); - - const isUsingBundledTypeScriptVersion = currentVersion.path === this._versionProvider.defaultVersion.path; - for (const plugin of pluginManager.plugins) { - if (isUsingBundledTypeScriptVersion || plugin.enableForWorkspaceTypeScriptVersions) { - pluginPaths.push(plugin.path); - } - } - } - - if (pluginPaths.length !== 0) { - args.push('--pluginProbeLocations', pluginPaths.join(',')); - } + this._tracer.logTrace(this._serverId, `TypeScript Server: trying to cancel ongoing request with sequence number ${seq}`); + try { + fs.writeFileSync(this._cancellationPipeName + seq, ''); + } catch { + // noop } + return true; + } +} - if (apiVersion.gte(API.v234)) { - if (configuration.npmLocation) { - args.push('--npmLocation', `"${configuration.npmLocation}"`); - } - } +export interface ITypeScriptServer { + readonly onEvent: vscode.Event; + readonly onExit: vscode.Event; + readonly onError: vscode.Event; + readonly onReaderError: vscode.Event; - if (apiVersion.gte(API.v260)) { - args.push('--locale', TypeScriptServerSpawner.getTsLocale(configuration)); - } + readonly tsServerLogFile: string | undefined; - if (apiVersion.gte(API.v291)) { - args.push('--noGetErrOnBackgroundUpdate'); - } + kill(): void; - if (apiVersion.gte(API.v345)) { - args.push('--validateDefaultNpmLocation'); - } + executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: false, lowPriority?: boolean }): undefined; + executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise>; + executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise> | undefined; - return { args, cancellationPipeName, tsServerLogFile }; - } + dispose(): void; +} - private static getDebugPort(): number | undefined { - const value = process.env['TSS_DEBUG']; - if (value) { - const port = parseInt(value); - if (!isNaN(port)) { - return port; - } - } - return undefined; - } +export interface TsServerProcess { + readonly stdout: stream.Readable; + write(serverRequest: Proto.Request): void; - private static isLoggingEnabled(apiVersion: API, configuration: TypeScriptServiceConfiguration) { - return apiVersion.gte(API.v222) && - configuration.tsServerLogLevel !== TsServerLogLevel.Off; - } + on(name: 'exit', handler: (code: number | null) => void): void; + on(name: 'error', handler: (error: Error) => void): void; - private static getTsLocale(configuration: TypeScriptServiceConfiguration): string { - return configuration.locale - ? configuration.locale - : vscode.env.language; - } + kill(): void; } -export class TypeScriptServer extends Disposable { +export class ProcessBasedTsServer extends Disposable implements ITypeScriptServer { private readonly _reader: Reader; private readonly _requestQueue = new RequestQueue(); private readonly _callbacks = new CallbackMap(); private readonly _pendingResponses = new Set(); constructor( - private readonly _childProcess: cp.ChildProcess, + private readonly _serverId: string, + private readonly _process: TsServerProcess, private readonly _tsServerLogFile: string | undefined, - private readonly _cancellationPipeName: string | undefined, + private readonly _requestCanceller: OngoingRequestCanceller, private readonly _version: TypeScriptVersion, private readonly _telemetryReporter: TelemetryReporter, private readonly _tracer: Tracer, ) { super(); - this._reader = this._register(new Reader(this._childProcess.stdout)); + this._reader = this._register(new Reader(this._process.stdout!)); this._reader.onData(msg => this.dispatchMessage(msg)); - this._childProcess.on('exit', code => this.handleExit(code)); - this._childProcess.on('error', error => this.handleError(error)); + + this._process.on('exit', code => { + this._onExit.fire(code); + this._callbacks.destroy('server exited'); + }); + this._process.on('error', error => { + this._onError.fire(error); + this._callbacks.destroy('server errored'); + }); } private readonly _onEvent = this._register(new vscode.EventEmitter()); @@ -273,8 +111,8 @@ export class TypeScriptServer extends Disposable { public get tsServerLogFile() { return this._tsServerLogFile; } - public write(serverRequest: Proto.Request) { - this._childProcess.stdin.write(JSON.stringify(serverRequest) + '\r\n', 'utf8'); + private write(serverRequest: Proto.Request) { + this._process.write(serverRequest); } public dispose() { @@ -284,17 +122,7 @@ export class TypeScriptServer extends Disposable { } public kill() { - this._childProcess.kill(); - } - - private handleExit(error: any) { - this._onExit.fire(error); - this._callbacks.destroy('server exited'); - } - - private handleError(error: any) { - this._onError.fire(error); - this._callbacks.destroy('server errored'); + this._process.kill(); } private dispatchMessage(message: Proto.Message) { @@ -310,11 +138,11 @@ export class TypeScriptServer extends Disposable { const seq = (event as Proto.RequestCompletedEvent).body.request_seq; const p = this._callbacks.fetch(seq); if (p) { - this._tracer.traceRequestCompleted('requestCompleted', seq, p.startTime); + this._tracer.traceRequestCompleted(this._serverId, 'requestCompleted', seq, p.startTime); p.onSuccess(undefined); } } else { - this._tracer.traceEvent(event); + this._tracer.traceEvent(this._serverId, event); this._onEvent.fire(event); } break; @@ -330,21 +158,15 @@ export class TypeScriptServer extends Disposable { private tryCancelRequest(seq: number, command: string): boolean { try { if (this._requestQueue.tryDeletePendingRequest(seq)) { - this._tracer.logTrace(`TypeScript Server: canceled request with sequence number ${seq}`); + this.logTrace(`Canceled request with sequence number ${seq}`); return true; } - if (this._cancellationPipeName) { - this._tracer.logTrace(`TypeScript Server: trying to cancel ongoing request with sequence number ${seq}`); - try { - fs.writeFileSync(this._cancellationPipeName + seq, ''); - } catch { - // noop - } + if (this._requestCanceller.tryCancelOngoingRequest(seq)) { return true; } - this._tracer.logTrace(`TypeScript Server: tried to cancel request with sequence number ${seq}. But request got already delivered.`); + this.logTrace(`Tried to cancel request with sequence number ${seq}. But request got already delivered.`); return false; } finally { const callback = this.fetchCallback(seq); @@ -360,26 +182,26 @@ export class TypeScriptServer extends Disposable { return; } - this._tracer.traceResponse(response, callback.startTime); + this._tracer.traceResponse(this._serverId, response, callback.startTime); if (response.success) { callback.onSuccess(response); } else if (response.message === 'No content available.') { // Special case where response itself is successful but there is not any data to return. callback.onSuccess(ServerResponse.NoContent); } else { - callback.onError(TypeScriptServerError.create(this._version, response)); + callback.onError(TypeScriptServerError.create(this._serverId, this._version, response)); } } - public executeImpl(command: string, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: false, lowPriority?: boolean }): undefined; - public executeImpl(command: string, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise>; - public executeImpl(command: string, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise> | undefined { + public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: false, lowPriority?: boolean }): undefined; + public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise>; + public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise> | undefined { const request = this._requestQueue.createRequest(command, args); const requestInfo: RequestItem = { request, expectsResponse: executeInfo.expectsResult, isAsync: executeInfo.isAsync, - queueingType: getQueueingType(command, executeInfo.lowPriority) + queueingType: ProcessBasedTsServer.getQueueingType(command, executeInfo.lowPriority) }; let result: Promise> | undefined; if (executeInfo.expectsResult) { @@ -435,7 +257,7 @@ export class TypeScriptServer extends Disposable { private sendRequest(requestItem: RequestItem): void { const serverRequest = requestItem.request; - this._tracer.traceRequest(serverRequest, requestItem.expectsResponse, this._requestQueue.length); + this._tracer.traceRequest(this._serverId, serverRequest, requestItem.expectsResponse, this._requestQueue.length); if (requestItem.expectsResponse && !requestItem.isAsync) { this._pendingResponses.add(requestItem.request.seq); @@ -460,17 +282,115 @@ export class TypeScriptServer extends Disposable { this._pendingResponses.delete(seq); return callback; } -} -const fenceCommands = new Set(['change', 'close', 'open', 'updateOpen']); + private logTrace(message: string) { + this._tracer.logTrace(this._serverId, message); + } + + private static readonly fenceCommands = new Set(['change', 'close', 'open', 'updateOpen']); -function getQueueingType( - command: string, - lowPriority?: boolean -): RequestQueueingType { - if (fenceCommands.has(command)) { - return RequestQueueingType.Fence; + private static getQueueingType( + command: string, + lowPriority?: boolean + ): RequestQueueingType { + if (ProcessBasedTsServer.fenceCommands.has(command)) { + return RequestQueueingType.Fence; + } + return lowPriority ? RequestQueueingType.LowPriority : RequestQueueingType.Normal; } - return lowPriority ? RequestQueueingType.LowPriority : RequestQueueingType.Normal; } + +export class SyntaxRoutingTsServer extends Disposable implements ITypeScriptServer { + public constructor( + private readonly syntaxServer: ITypeScriptServer, + private readonly semanticServer: ITypeScriptServer, + ) { + super(); + + this._register(syntaxServer.onEvent(e => this._onEvent.fire(e))); + this._register(semanticServer.onEvent(e => this._onEvent.fire(e))); + + this._register(semanticServer.onExit(e => { + this._onExit.fire(e); + this.syntaxServer.kill(); + })); + this._register(semanticServer.onError(e => this._onError.fire(e))); + } + + private readonly _onEvent = this._register(new vscode.EventEmitter()); + public readonly onEvent = this._onEvent.event; + + private readonly _onExit = this._register(new vscode.EventEmitter()); + public readonly onExit = this._onExit.event; + + private readonly _onError = this._register(new vscode.EventEmitter()); + public readonly onError = this._onError.event; + + public get onReaderError() { return this.semanticServer.onReaderError; } + + public get tsServerLogFile() { return this.semanticServer.tsServerLogFile; } + + public kill(): void { + this.syntaxServer.kill(); + this.semanticServer.kill(); + } + + private static readonly syntaxCommands = new Set([ + 'navtree', + 'getOutliningSpans', + 'jsxClosingTag', + 'selectionRange', + 'format', + 'formatonkey', + 'docCommentTemplate', + ]); + private static readonly sharedCommands = new Set([ + 'change', + 'close', + 'open', + 'updateOpen', + 'configure', + 'configurePlugin', + ]); + + public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: false, lowPriority?: boolean }): undefined; + public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise>; + public executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise> | undefined { + if (SyntaxRoutingTsServer.syntaxCommands.has(command)) { + return this.syntaxServer.executeImpl(command, args, executeInfo); + } else if (SyntaxRoutingTsServer.sharedCommands.has(command)) { + // Dispatch to both server but only return from syntax one + + // Also make sure we never cancel requests to just one server + let hasCompletedSyntax = false; + let hasCompletedSemantic = false; + let token: vscode.CancellationToken | undefined = undefined; + if (executeInfo.token) { + const source = new vscode.CancellationTokenSource(); + executeInfo.token.onCancellationRequested(() => { + if (hasCompletedSyntax && !hasCompletedSemantic || hasCompletedSemantic && !hasCompletedSyntax) { + // Don't cancel. + // One of the servers completed this request so we don't want to leave the other + // in a different state + return; + } + source.cancel(); + }); + token = source.token; + } + + const semanticRequest = this.semanticServer.executeImpl(command, args, { ...executeInfo, token }); + if (semanticRequest) { + semanticRequest.finally(() => { hasCompletedSemantic = true; }); + } + const syntaxRequest = this.syntaxServer.executeImpl(command, args, { ...executeInfo, token }); + if (syntaxRequest) { + syntaxRequest.finally(() => { hasCompletedSyntax = true; }); + } + return syntaxRequest; + } else { + return this.semanticServer.executeImpl(command, args, executeInfo); + } + } +} diff --git a/extensions/typescript-language-features/src/tsServer/serverError.ts b/extensions/typescript-language-features/src/tsServer/serverError.ts new file mode 100644 index 000000000..cb5cb8035 --- /dev/null +++ b/extensions/typescript-language-features/src/tsServer/serverError.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. + *--------------------------------------------------------------------------------------------*/ + +import * as Proto from '../protocol'; +import { escapeRegExp } from '../utils/regexp'; +import { TypeScriptVersion } from '../utils/versionProvider'; + +export class TypeScriptServerError extends Error { + public static create( + serverId: string, + version: TypeScriptVersion, + response: Proto.Response + ): TypeScriptServerError { + const parsedResult = TypeScriptServerError.parseErrorText(version, response); + return new TypeScriptServerError(serverId, version, response, parsedResult ? parsedResult.message : undefined, parsedResult ? parsedResult.stack : undefined); + } + + private constructor( + serverId: string, + version: TypeScriptVersion, + private readonly response: Proto.Response, + public readonly serverMessage: string | undefined, + public readonly serverStack: string | undefined + ) { + super(`<${serverId}> TypeScript Server Error (${version.versionString})\n${serverMessage}\n${serverStack}`); + } + + public get serverErrorText() { return this.response.message; } + + public get serverCommand() { return this.response.command; } + + /** + * Given a `errorText` from a tsserver request indicating failure in handling a request, + * prepares a payload for telemetry-logging. + */ + private static parseErrorText(version: TypeScriptVersion, response: Proto.Response) { + const errorText = response.message; + if (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. + return { + message: prefixFreeErrorText.substring(0, newlineIndex), + stack: TypeScriptServerError.normalizeMessageStack(version, prefixFreeErrorText.substring(newlineIndex + 1)) + }; + } + } + } + return undefined; + } + + /** + * Try to replace full TS Server paths with 'tsserver.js' so that we don't have to post process the data as much + */ + private static normalizeMessageStack(version: TypeScriptVersion, message: string | undefined) { + if (!message) { + return ''; + } + return message.replace(new RegExp(`${escapeRegExp(version.path)}[/\\\\]tsserver.js:`, 'gi'), 'tsserver.js:'); + } +} diff --git a/extensions/typescript-language-features/src/tsServer/spawner.ts b/extensions/typescript-language-features/src/tsServer/spawner.ts new file mode 100644 index 000000000..599abe32c --- /dev/null +++ b/extensions/typescript-language-features/src/tsServer/spawner.ts @@ -0,0 +1,229 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as child_process from 'child_process'; +import * as path from 'path'; +import * as stream from 'stream'; +import * as vscode from 'vscode'; +import * as Proto from '../protocol'; +import API from '../utils/api'; +import { TsServerLogLevel, TypeScriptServiceConfiguration } from '../utils/configuration'; +import * as electron from '../utils/electron'; +import LogDirectoryProvider from '../utils/logDirectoryProvider'; +import Logger from '../utils/logger'; +import { TypeScriptPluginPathsProvider } from '../utils/pluginPathsProvider'; +import { PluginManager } from '../utils/plugins'; +import TelemetryReporter from '../utils/telemetry'; +import Tracer from '../utils/tracer'; +import { TypeScriptVersion, TypeScriptVersionProvider } from '../utils/versionProvider'; +import { ITypeScriptServer, PipeRequestCanceller, ProcessBasedTsServer, SyntaxRoutingTsServer, TsServerProcess } from './server'; + +type ServerKind = 'main' | 'syntax' | 'semantic'; + +export class TypeScriptServerSpawner { + public constructor( + private readonly _versionProvider: TypeScriptVersionProvider, + private readonly _logDirectoryProvider: LogDirectoryProvider, + private readonly _pluginPathsProvider: TypeScriptPluginPathsProvider, + private readonly _logger: Logger, + private readonly _telemetryReporter: TelemetryReporter, + private readonly _tracer: Tracer, + ) { } + + public spawn( + version: TypeScriptVersion, + configuration: TypeScriptServiceConfiguration, + pluginManager: PluginManager + ): ITypeScriptServer { + if (this.shouldUseSeparateSyntaxServer(version, configuration)) { + const syntaxServer = this.spawnTsServer('syntax', version, configuration, pluginManager); + const semanticServer = this.spawnTsServer('semantic', version, configuration, pluginManager); + return new SyntaxRoutingTsServer(syntaxServer, semanticServer); + } + + return this.spawnTsServer('main', version, configuration, pluginManager); + } + + private shouldUseSeparateSyntaxServer( + version: TypeScriptVersion, + configuration: TypeScriptServiceConfiguration, + ): boolean { + return configuration.useSeparateSyntaxServer && !!version.apiVersion && version.apiVersion.gte(API.v340); + } + + private spawnTsServer( + kind: ServerKind, + version: TypeScriptVersion, + configuration: TypeScriptServiceConfiguration, + pluginManager: PluginManager, + ): ITypeScriptServer { + const apiVersion = version.apiVersion || API.defaultVersion; + + const { args, cancellationPipeName, tsServerLogFile } = this.getTsServerArgs(kind, configuration, version, apiVersion, pluginManager); + + if (TypeScriptServerSpawner.isLoggingEnabled(apiVersion, configuration)) { + if (tsServerLogFile) { + this._logger.info(`<${kind}> Log file: ${tsServerLogFile}`); + } else { + this._logger.error(`<${kind}> Could not create log directory`); + } + } + + this._logger.info(`<${kind}> Forking...`); + const childProcess = electron.fork(version.tsServerPath, args, this.getForkOptions(kind)); + this._logger.info(`<${kind}> Starting...`); + + return new ProcessBasedTsServer( + kind, + new ChildServerProcess(childProcess), + tsServerLogFile, + new PipeRequestCanceller(kind, cancellationPipeName, this._tracer), + version, + this._telemetryReporter, + this._tracer); + } + + private getForkOptions(kind: ServerKind) { + const debugPort = TypeScriptServerSpawner.getDebugPort(kind); + const tsServerForkOptions: electron.ForkOptions = { + execArgv: debugPort ? [`--inspect=${debugPort}`] : [], + }; + return tsServerForkOptions; + } + + private getTsServerArgs( + kind: ServerKind, + configuration: TypeScriptServiceConfiguration, + currentVersion: TypeScriptVersion, + apiVersion: API, + pluginManager: PluginManager, + ): { args: string[], cancellationPipeName: string | undefined, tsServerLogFile: string | undefined } { + const args: string[] = []; + let cancellationPipeName: string | undefined; + let tsServerLogFile: string | undefined; + + if (kind === 'syntax') { + args.push('--syntaxOnly'); + } + + if (apiVersion.gte(API.v206)) { + if (apiVersion.gte(API.v250)) { + args.push('--useInferredProjectPerProjectRoot'); + } else { + args.push('--useSingleInferredProject'); + } + + if (configuration.disableAutomaticTypeAcquisition || kind === 'syntax') { + args.push('--disableAutomaticTypingAcquisition'); + } + } + + if (apiVersion.gte(API.v208) && kind !== 'syntax') { + args.push('--enableTelemetry'); + } + + if (apiVersion.gte(API.v222)) { + cancellationPipeName = electron.getTempFile('tscancellation'); + args.push('--cancellationPipeName', cancellationPipeName + '*'); + } + + if (TypeScriptServerSpawner.isLoggingEnabled(apiVersion, configuration)) { + const logDir = this._logDirectoryProvider.getNewLogDirectory(); + if (logDir) { + tsServerLogFile = path.join(logDir, `tsserver.log`); + args.push('--logVerbosity', TsServerLogLevel.toString(configuration.tsServerLogLevel)); + args.push('--logFile', tsServerLogFile); + } + } + + if (apiVersion.gte(API.v230)) { + const pluginPaths = this._pluginPathsProvider.getPluginPaths(); + + if (pluginManager.plugins.length) { + args.push('--globalPlugins', pluginManager.plugins.map(x => x.name).join(',')); + + const isUsingBundledTypeScriptVersion = currentVersion.path === this._versionProvider.defaultVersion.path; + for (const plugin of pluginManager.plugins) { + if (isUsingBundledTypeScriptVersion || plugin.enableForWorkspaceTypeScriptVersions) { + pluginPaths.push(plugin.path); + } + } + } + + if (pluginPaths.length !== 0) { + args.push('--pluginProbeLocations', pluginPaths.join(',')); + } + } + + if (apiVersion.gte(API.v234)) { + if (configuration.npmLocation) { + args.push('--npmLocation', `"${configuration.npmLocation}"`); + } + } + + if (apiVersion.gte(API.v260)) { + args.push('--locale', TypeScriptServerSpawner.getTsLocale(configuration)); + } + + if (apiVersion.gte(API.v291)) { + args.push('--noGetErrOnBackgroundUpdate'); + } + + if (apiVersion.gte(API.v345)) { + args.push('--validateDefaultNpmLocation'); + } + + return { args, cancellationPipeName, tsServerLogFile }; + } + + private static getDebugPort(kind: ServerKind): number | undefined { + if (kind === 'syntax') { + // We typically only want to debug the main semantic server + return undefined; + } + const value = process.env['TSS_DEBUG']; + if (value) { + const port = parseInt(value); + if (!isNaN(port)) { + return port; + } + } + return undefined; + } + + private static isLoggingEnabled(apiVersion: API, configuration: TypeScriptServiceConfiguration) { + return apiVersion.gte(API.v222) && + configuration.tsServerLogLevel !== TsServerLogLevel.Off; + } + + private static getTsLocale(configuration: TypeScriptServiceConfiguration): string { + return configuration.locale + ? configuration.locale + : vscode.env.language; + } +} + +class ChildServerProcess implements TsServerProcess { + + public constructor( + private readonly _process: child_process.ChildProcess, + ) { } + + get stdout(): stream.Readable { return this._process.stdout!; } + + write(serverRequest: Proto.Request): void { + this._process.stdin!.write(JSON.stringify(serverRequest) + '\r\n', 'utf8'); + } + + on(name: 'exit', handler: (code: number | null) => void): void; + on(name: 'error', handler: (error: Error) => void): void; + on(name: any, handler: any) { + this._process.on(name, handler); + } + + kill(): void { + this._process.kill(); + } +} \ No newline at end of file diff --git a/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts b/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts index b11259f22..2571d395a 100644 --- a/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts +++ b/extensions/typescript-language-features/src/typeScriptServiceClientHost.ts @@ -24,6 +24,7 @@ import { PluginManager } from './utils/plugins'; import * as typeConverters from './utils/typeConverters'; import TypingsStatus, { AtaProgressReporter } from './utils/typingsStatus'; import VersionStatus from './utils/versionStatus'; +import { flatten } from './utils/arrays'; // Style check diagnostics that can be reported as warnings const styleCheckDiagnostics = [ @@ -68,7 +69,7 @@ export default class TypeScriptServiceClientHost extends Disposable { configFileWatcher.onDidDelete(handleProjectCreateOrDelete, this, this._disposables); configFileWatcher.onDidChange(handleProjectChange, this, this._disposables); - const allModeIds = this.getAllModeIds(descriptions); + const allModeIds = this.getAllModeIds(descriptions, pluginManager); this.client = this._register(new TypeScriptServiceClient( workspaceState, version => this.versionStatus.onDidChangeTypeScriptVersion(version), @@ -138,11 +139,11 @@ export default class TypeScriptServiceClientHost extends Disposable { this.configurationChanged(); } - private getAllModeIds(descriptions: LanguageDescription[]) { - const allModeIds: string[] = []; - for (const description of descriptions) { - allModeIds.push(...description.modeIds); - } + private getAllModeIds(descriptions: LanguageDescription[], pluginManager: PluginManager) { + const allModeIds = flatten([ + ...descriptions.map(x => x.modeIds), + ...pluginManager.plugins.map(x => x.languages) + ]); return allModeIds; } diff --git a/extensions/typescript-language-features/src/typescriptService.ts b/extensions/typescript-language-features/src/typescriptService.ts index 32ed3a600..ba396ad2f 100644 --- a/extensions/typescript-language-features/src/typescriptService.ts +++ b/extensions/typescript-language-features/src/typescriptService.ts @@ -11,17 +11,6 @@ import { TypeScriptServiceConfiguration } from './utils/configuration'; import Logger from './utils/logger'; import { PluginManager } from './utils/plugins'; -declare module './protocol' { - interface SelectionRange { - textSpan: Proto.TextSpan; - parent?: SelectionRange; - } - - interface SelectionRangeResponse extends Proto.Response { - body?: ReadonlyArray; - } -} - export namespace ServerResponse { export class Cancelled { @@ -37,7 +26,7 @@ export namespace ServerResponse { export type Response = T | Cancelled | typeof NoContent; } -export interface TypeScriptRequestTypes { +interface StandardTsServerRequests { 'applyCodeActionCommand': [Proto.ApplyCodeActionCommandRequestArgs, Proto.ApplyCodeActionCommandResponse]; 'completionEntryDetails': [Proto.CompletionDetailsRequestArgs, Proto.CompletionDetailsResponse]; 'completionInfo': [Proto.CompletionsRequestArgs, Proto.CompletionInfoResponse]; @@ -65,11 +54,31 @@ export interface TypeScriptRequestTypes { 'quickinfo': [Proto.FileLocationRequestArgs, Proto.QuickInfoResponse]; 'references': [Proto.FileLocationRequestArgs, Proto.ReferencesResponse]; 'rename': [Proto.RenameRequestArgs, Proto.RenameResponse]; - 'selectionRange': [Proto.FileRequestArgs & { locations: Proto.Location[] }, Proto.SelectionRangeResponse]; + 'selectionRange': [Proto.SelectionRangeRequestArgs, Proto.SelectionRangeResponse]; 'signatureHelp': [Proto.SignatureHelpRequestArgs, Proto.SignatureHelpResponse]; 'typeDefinition': [Proto.FileLocationRequestArgs, Proto.TypeDefinitionResponse]; } +interface NoResponseTsServerRequests { + 'open': [Proto.OpenRequestArgs, null]; + 'close': [Proto.FileRequestArgs]; + 'change': [Proto.ChangeRequestArgs, null]; + 'updateOpen': [Proto.UpdateOpenRequestArgs, null]; + 'compilerOptionsForInferredProjects': [Proto.SetCompilerOptionsForInferredProjectsArgs, null]; + 'reloadProjects': [null, null]; + 'configurePlugin': [Proto.ConfigurePluginRequest, Proto.ConfigurePluginResponse]; +} + +interface AsyncTsServerRequests { + 'geterr': [Proto.GeterrRequestArgs, Proto.Response]; +} + +export type TypeScriptRequests = StandardTsServerRequests & NoResponseTsServerRequests & AsyncTsServerRequests; + +export type ExecConfig = { + lowPriority?: boolean; +}; + export interface ITypeScriptServiceClient { /** * Convert a resource (VS Code) to a normalized path (TypeScript). @@ -111,19 +120,17 @@ export interface ITypeScriptServiceClient { readonly logger: Logger; readonly bufferSyncSupport: BufferSyncSupport; - execute( + execute( command: K, - args: TypeScriptRequestTypes[K][0], + args: StandardTsServerRequests[K][0], token: vscode.CancellationToken, - lowPriority?: boolean - ): Promise>; - - executeWithoutWaitingForResponse(command: 'open', args: Proto.OpenRequestArgs): void; - executeWithoutWaitingForResponse(command: 'close', args: Proto.FileRequestArgs): void; - executeWithoutWaitingForResponse(command: 'change', args: Proto.ChangeRequestArgs): void; - executeWithoutWaitingForResponse(command: 'updateOpen', args: Proto.UpdateOpenRequestArgs): void; - executeWithoutWaitingForResponse(command: 'compilerOptionsForInferredProjects', args: Proto.SetCompilerOptionsForInferredProjectsArgs): void; - executeWithoutWaitingForResponse(command: 'reloadProjects', args: null): void; + config?: ExecConfig + ): Promise>; + + executeWithoutWaitingForResponse( + command: K, + args: NoResponseTsServerRequests[K][0] + ): void; executeAsync(command: 'geterr', args: Proto.GeterrRequestArgs, token: vscode.CancellationToken): Promise>; diff --git a/extensions/typescript-language-features/src/typescriptServiceClient.ts b/extensions/typescript-language-features/src/typescriptServiceClient.ts index 8f8f45aaa..996478d6c 100644 --- a/extensions/typescript-language-features/src/typescriptServiceClient.ts +++ b/extensions/typescript-language-features/src/typescriptServiceClient.ts @@ -10,8 +10,8 @@ import * as nls from 'vscode-nls'; import BufferSyncSupport from './features/bufferSyncSupport'; import { DiagnosticKind, DiagnosticsManager } from './features/diagnostics'; import * as Proto from './protocol'; -import { TypeScriptServer, TypeScriptServerSpawner } from './tsServer/server'; -import { ITypeScriptServiceClient, ServerResponse } from './typescriptService'; +import { ITypeScriptServer } from './tsServer/server'; +import { ITypeScriptServiceClient, ServerResponse, TypeScriptRequests, ExecConfig } from './typescriptService'; import API from './utils/api'; import { TsServerLogLevel, TypeScriptServiceConfiguration } from './utils/configuration'; import { Disposable } from './utils/dispose'; @@ -20,11 +20,12 @@ import LogDirectoryProvider from './utils/logDirectoryProvider'; import Logger from './utils/logger'; import { TypeScriptPluginPathsProvider } from './utils/pluginPathsProvider'; import { PluginManager } from './utils/plugins'; -import TelemetryReporter from './utils/telemetry'; +import TelemetryReporter, { VSCodeTelemetryReporter } from './utils/telemetry'; import Tracer from './utils/tracer'; import { inferredProjectConfig } from './utils/tsconfig'; import { TypeScriptVersionPicker } from './utils/versionPicker'; import { TypeScriptVersion, TypeScriptVersionProvider } from './utils/versionProvider'; +import { TypeScriptServerSpawner } from './tsServer/spawner'; const localize = nls.loadMessageBundle(); @@ -46,7 +47,7 @@ namespace ServerState { export class Running { readonly type = Type.Running; constructor( - public readonly server: TypeScriptServer, + public readonly server: ITypeScriptServer, /** * API version obtained from the version picker after checking the corresponding path exists. @@ -152,7 +153,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType } }, this, this._disposables); - this.telemetryReporter = this._register(new TelemetryReporter(() => { + this.telemetryReporter = this._register(new VSCodeTelemetryReporter(() => { if (this.serverState.type === ServerState.Type.Running) { if (this.serverState.tsserverVersion) { return this.serverState.tsserverVersion; @@ -284,7 +285,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType currentVersion = this.versionPicker.currentVersion; } - const apiVersion = this.versionPicker.currentVersion.version || API.defaultVersion; + const apiVersion = this.versionPicker.currentVersion.apiVersion || API.defaultVersion; this.onDidChangeTypeScriptVersion(currentVersion); let mytoken = ++this.token; @@ -352,7 +353,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType handle.onEvent(event => this.dispatchEvent(event)); this._onReady!.resolve(); - this._onTsServerStarted.fire(currentVersion.version); + this._onTsServerStarted.fire(currentVersion.apiVersion); if (apiVersion.gte(API.v300)) { this.loadingIndicator.startedLoadingProject(undefined /* projectName */); @@ -606,16 +607,16 @@ export default class TypeScriptServiceClient extends Disposable implements IType return undefined; } - public execute(command: string, args: any, token: vscode.CancellationToken, lowPriority?: boolean): Promise> { + public execute(command: keyof TypeScriptRequests, args: any, token: vscode.CancellationToken, config?: ExecConfig): Promise> { return this.executeImpl(command, args, { isAsync: false, token, expectsResult: true, - lowPriority + lowPriority: config ? config.lowPriority : undefined }); } - public executeWithoutWaitingForResponse(command: string, args: any): void { + public executeWithoutWaitingForResponse(command: keyof TypeScriptRequests, args: any): void { this.executeImpl(command, args, { isAsync: false, token: undefined, @@ -623,7 +624,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType }); } - public executeAsync(command: string, args: Proto.GeterrRequestArgs, token: vscode.CancellationToken): Promise> { + public executeAsync(command: keyof TypeScriptRequests, args: Proto.GeterrRequestArgs, token: vscode.CancellationToken): Promise> { return this.executeImpl(command, args, { isAsync: true, token, @@ -631,9 +632,9 @@ export default class TypeScriptServiceClient extends Disposable implements IType }); } - private executeImpl(command: string, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: false, lowPriority?: boolean }): undefined; - private executeImpl(command: string, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise>; - private executeImpl(command: string, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise> | undefined { + private executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: false, lowPriority?: boolean }): undefined; + private executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise>; + private executeImpl(command: keyof TypeScriptRequests, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise> | undefined { this.bufferSyncSupport.beforeCommand(command); const runningServerState = this.service(); return runningServerState.server.executeImpl(command, args, executeInfo); @@ -768,7 +769,6 @@ export default class TypeScriptServiceClient extends Disposable implements IType this.logTelemetry(telemetryData.telemetryEventName, properties); } - private configurePlugin(pluginName: string, configuration: {}): any { if (this.apiVersion.gte(API.v314)) { this.executeWithoutWaitingForResponse('configurePlugin', { pluginName, configuration }); diff --git a/extensions/typescript-language-features/src/typings/ref.d.ts b/extensions/typescript-language-features/src/typings/ref.d.ts index 954bab971..c9849d48e 100644 --- a/extensions/typescript-language-features/src/typings/ref.d.ts +++ b/extensions/typescript-language-features/src/typings/ref.d.ts @@ -5,4 +5,3 @@ /// /// -/// diff --git a/extensions/typescript-language-features/src/utils/arrays.ts b/extensions/typescript-language-features/src/utils/arrays.ts index bf403c3af..f9435fe9b 100644 --- a/extensions/typescript-language-features/src/utils/arrays.ts +++ b/extensions/typescript-language-features/src/utils/arrays.ts @@ -2,20 +2,23 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -export function equals(one: ReadonlyArray, other: ReadonlyArray, itemEquals: (a: T, b: T) => boolean = (a, b) => a === b): boolean { - if (one.length !== other.length) { - return false; - } - for (let i = 0, len = one.length; i < len; i++) { - if (!itemEquals(one[i], other[i])) { - return false; - } - } +export const empty = Object.freeze([]); - return true; +export function equals( + a: ReadonlyArray, + b: ReadonlyArray, + itemEquals: (a: T, b: T) => boolean = (a, b) => a === b +): boolean { + if (a === b) { + return true; + } + if (a.length !== b.length) { + return false; + } + return a.every((x, i) => itemEquals(x, b[i])); } export function flatten(arr: ReadonlyArray[]): T[] { - return ([] as T[]).concat.apply([], arr); + return Array.prototype.concat.apply([], arr); } \ No newline at end of file diff --git a/extensions/typescript-language-features/src/utils/configuration.ts b/extensions/typescript-language-features/src/utils/configuration.ts index 3babc53c9..f0e602e81 100644 --- a/extensions/typescript-language-features/src/utils/configuration.ts +++ b/extensions/typescript-language-features/src/utils/configuration.ts @@ -54,6 +54,7 @@ export class TypeScriptServiceConfiguration { public readonly checkJs: boolean; public readonly experimentalDecorators: boolean; public readonly disableAutomaticTypeAcquisition: boolean; + public readonly useSeparateSyntaxServer: boolean; public static loadFromWorkspace(): TypeScriptServiceConfiguration { return new TypeScriptServiceConfiguration(); @@ -71,6 +72,7 @@ export class TypeScriptServiceConfiguration { this.checkJs = TypeScriptServiceConfiguration.readCheckJs(configuration); this.experimentalDecorators = TypeScriptServiceConfiguration.readExperimentalDecorators(configuration); this.disableAutomaticTypeAcquisition = TypeScriptServiceConfiguration.readDisableAutomaticTypeAcquisition(configuration); + this.useSeparateSyntaxServer = TypeScriptServiceConfiguration.readUseSeparateSyntaxServer(configuration); } public isEqualTo(other: TypeScriptServiceConfiguration): boolean { @@ -82,7 +84,8 @@ export class TypeScriptServiceConfiguration { && this.checkJs === other.checkJs && this.experimentalDecorators === other.experimentalDecorators && this.disableAutomaticTypeAcquisition === other.disableAutomaticTypeAcquisition - && arrays.equals(this.tsServerPluginPaths, other.tsServerPluginPaths); + && arrays.equals(this.tsServerPluginPaths, other.tsServerPluginPaths) + && this.useSeparateSyntaxServer === other.useSeparateSyntaxServer; } private static fixPathPrefixes(inspectValue: string): string { @@ -139,4 +142,8 @@ export class TypeScriptServiceConfiguration { private static extractLocale(configuration: vscode.WorkspaceConfiguration): string | null { return configuration.get('typescript.locale', null); } + + private static readUseSeparateSyntaxServer(configuration: vscode.WorkspaceConfiguration): boolean { + return configuration.get('typescript.tsserver.useSeparateSyntaxServer', true); + } } diff --git a/extensions/typescript-language-features/src/utils/electron.ts b/extensions/typescript-language-features/src/utils/electron.ts index ff69c8c8c..ea16bae42 100644 --- a/extensions/typescript-language-features/src/utils/electron.ts +++ b/extensions/typescript-language-features/src/utils/electron.ts @@ -7,13 +7,27 @@ import * as temp from './temp'; import path = require('path'); import fs = require('fs'); import cp = require('child_process'); +import process = require('process'); const getRootTempDir = (() => { let dir: string | undefined; return () => { if (!dir) { - dir = temp.getTempFile(`vscode-typescript`); + dir = temp.getTempFile(`vscode-typescript${process.platform !== 'win32' && process.getuid ? process.getuid() : ''}`); + } + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir); + } + return dir; + }; +})(); + +export const getInstanceDir = (() => { + let dir: string | undefined; + return () => { + if (!dir) { + dir = path.join(getRootTempDir(), temp.makeRandomHexString(20)); } if (!fs.existsSync(dir)) { fs.mkdirSync(dir); @@ -23,7 +37,7 @@ const getRootTempDir = (() => { })(); export function getTempFile(prefix: string): string { - return path.join(getRootTempDir(), `${prefix}-${temp.makeRandomHexString(20)}.tmp`); + return path.join(getInstanceDir(), `${prefix}-${temp.makeRandomHexString(20)}.tmp`); } function generatePatchedEnv(env: any, modulePath: string): any { diff --git a/extensions/typescript-language-features/src/utils/pluginPathsProvider.ts b/extensions/typescript-language-features/src/utils/pluginPathsProvider.ts index 547660f06..de6d03cd9 100644 --- a/extensions/typescript-language-features/src/utils/pluginPathsProvider.ts +++ b/extensions/typescript-language-features/src/utils/pluginPathsProvider.ts @@ -9,7 +9,6 @@ import { RelativeWorkspacePathResolver } from './relativePathResolver'; export class TypeScriptPluginPathsProvider { - public readonly relativePathResolver: RelativeWorkspacePathResolver = new RelativeWorkspacePathResolver(); public constructor( private configuration: TypeScriptServiceConfiguration @@ -32,7 +31,7 @@ export class TypeScriptPluginPathsProvider { return [pluginPath]; } - const workspacePath = this.relativePathResolver.asAbsoluteWorkspacePath(pluginPath); + const workspacePath = RelativeWorkspacePathResolver.asAbsoluteWorkspacePath(pluginPath); if (workspacePath !== undefined) { return [workspacePath]; } diff --git a/extensions/typescript-language-features/src/utils/projectStatus.ts b/extensions/typescript-language-features/src/utils/projectStatus.ts index 4eb9b8c76..15aa72a80 100644 --- a/extensions/typescript-language-features/src/utils/projectStatus.ts +++ b/extensions/typescript-language-features/src/utils/projectStatus.ts @@ -23,7 +23,12 @@ class ExcludeHintItem { constructor( private readonly telemetryReporter: TelemetryReporter ) { - this._item = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 98 /* to the right of typescript version status (99) */); + this._item = vscode.window.createStatusBarItem({ + id: 'status.typescript.exclude', + name: localize('statusExclude', "TypeScript: Configure Excludes"), + alignment: vscode.StatusBarAlignment.Right, + priority: 98 /* to the right of typescript version status (99) */ + }); this._item.command = 'js.projectStatus.command'; } diff --git a/extensions/typescript-language-features/src/utils/relativePathResolver.ts b/extensions/typescript-language-features/src/utils/relativePathResolver.ts index 85b72a55d..64dff66fb 100644 --- a/extensions/typescript-language-features/src/utils/relativePathResolver.ts +++ b/extensions/typescript-language-features/src/utils/relativePathResolver.ts @@ -6,7 +6,7 @@ import * as path from 'path'; import * as vscode from 'vscode'; export class RelativeWorkspacePathResolver { - public asAbsoluteWorkspacePath(relativePath: string): string | undefined { + public static asAbsoluteWorkspacePath(relativePath: string): string | undefined { for (const root of vscode.workspace.workspaceFolders || []) { const rootPrefixes = [`./${root.name}/`, `${root.name}/`, `.\\${root.name}\\`, `${root.name}\\`]; for (const rootPrefix of rootPrefixes) { diff --git a/extensions/typescript-language-features/src/utils/surveyor.ts b/extensions/typescript-language-features/src/utils/surveyor.ts index bf3ba4ad6..2af183be1 100644 --- a/extensions/typescript-language-features/src/utils/surveyor.ts +++ b/extensions/typescript-language-features/src/utils/surveyor.ts @@ -103,7 +103,7 @@ class Survey { } private get triggerCount(): number { - const count = this.memento.get(this.triggerCountMementoKey); + const count = this.memento.get(this.triggerCountMementoKey); return !count || isNaN(+count) ? 0 : +count; } diff --git a/extensions/typescript-language-features/src/utils/telemetry.ts b/extensions/typescript-language-features/src/utils/telemetry.ts index e3b5f09ad..fe6ea8d29 100644 --- a/extensions/typescript-language-features/src/utils/telemetry.ts +++ b/extensions/typescript-language-features/src/utils/telemetry.ts @@ -13,15 +13,14 @@ interface PackageInfo { readonly aiKey: string; } -export default class TelemetryReporter { - private _reporter: VsCodeTelemetryReporter | null = null; +export default interface TelemetryReporter { + logTelemetry(eventName: string, properties?: { [prop: string]: string }): void; - dispose() { - if (this._reporter) { - this._reporter.dispose(); - this._reporter = null; - } - } + dispose(): void; +} + +export class VSCodeTelemetryReporter implements TelemetryReporter { + private _reporter: VsCodeTelemetryReporter | null = null; constructor( private readonly clientVersionDelegate: () => string @@ -45,6 +44,13 @@ export default class TelemetryReporter { } } + public dispose() { + if (this._reporter) { + this._reporter.dispose(); + this._reporter = null; + } + } + @memoize private get reporter(): VsCodeTelemetryReporter | null { if (this.packageInfo && this.packageInfo.aiKey) { diff --git a/extensions/typescript-language-features/src/utils/tracer.ts b/extensions/typescript-language-features/src/utils/tracer.ts index c80254c79..f7ca0d674 100644 --- a/extensions/typescript-language-features/src/utils/tracer.ts +++ b/extensions/typescript-language-features/src/utils/tracer.ts @@ -50,7 +50,7 @@ export default class Tracer { return result; } - public traceRequest(request: Proto.Request, responseExpected: boolean, queueLength: number): void { + public traceRequest(serverId: string, request: Proto.Request, responseExpected: boolean, queueLength: number): void { if (this.trace === Trace.Off) { return; } @@ -58,10 +58,10 @@ export default class Tracer { if (this.trace === Trace.Verbose && request.arguments) { data = `Arguments: ${JSON.stringify(request.arguments, null, 4)}`; } - this.logTrace(`Sending request: ${request.command} (${request.seq}). Response expected: ${responseExpected ? 'yes' : 'no'}. Current queue length: ${queueLength}`, data); + this.logTrace(serverId, `Sending request: ${request.command} (${request.seq}). Response expected: ${responseExpected ? 'yes' : 'no'}. Current queue length: ${queueLength}`, data); } - public traceResponse(response: Proto.Response, startTime: number): void { + public traceResponse(serverId: string, response: Proto.Response, startTime: number): void { if (this.trace === Trace.Off) { return; } @@ -69,17 +69,17 @@ export default class Tracer { if (this.trace === Trace.Verbose && response.body) { data = `Result: ${JSON.stringify(response.body, null, 4)}`; } - this.logTrace(`Response received: ${response.command} (${response.request_seq}). Request took ${Date.now() - startTime} ms. Success: ${response.success} ${!response.success ? '. Message: ' + response.message : ''}`, data); + this.logTrace(serverId, `Response received: ${response.command} (${response.request_seq}). Request took ${Date.now() - startTime} ms. Success: ${response.success} ${!response.success ? '. Message: ' + response.message : ''}`, data); } - public traceRequestCompleted(command: string, request_seq: number, startTime: number): any { + public traceRequestCompleted(serverId: string, command: string, request_seq: number, startTime: number): any { if (this.trace === Trace.Off) { return; } - this.logTrace(`Async response received: ${command} (${request_seq}). Request took ${Date.now() - startTime} ms.`); + this.logTrace(serverId, `Async response received: ${command} (${request_seq}). Request took ${Date.now() - startTime} ms.`); } - public traceEvent(event: Proto.Event): void { + public traceEvent(serverId: string, event: Proto.Event): void { if (this.trace === Trace.Off) { return; } @@ -87,12 +87,12 @@ export default class Tracer { if (this.trace === Trace.Verbose && event.body) { data = `Data: ${JSON.stringify(event.body, null, 4)}`; } - this.logTrace(`Event received: ${event.event} (${event.seq}).`, data); + this.logTrace(serverId, `Event received: ${event.event} (${event.seq}).`, data); } - public logTrace(message: string, data?: any): void { + public logTrace(serverId: string, message: string, data?: any): void { if (this.trace !== Trace.Off) { - this.logger.logLevel('Trace', message, data); + this.logger.logLevel('Trace', `<${serverId}> ${message}`, data); } } } \ No newline at end of file diff --git a/extensions/typescript-language-features/src/utils/tsconfigProvider.ts b/extensions/typescript-language-features/src/utils/tsconfigProvider.ts index 7e2b85ef2..fe9390320 100644 --- a/extensions/typescript-language-features/src/utils/tsconfigProvider.ts +++ b/extensions/typescript-language-features/src/utils/tsconfigProvider.ts @@ -6,6 +6,7 @@ import * as vscode from 'vscode'; export interface TSConfig { readonly path: string; + readonly posixPath: string; readonly workspaceFolder?: vscode.WorkspaceFolder; } @@ -20,6 +21,7 @@ export default class TsConfigProvider { if (root) { configs.set(config.fsPath, { path: config.fsPath, + posixPath: config.path, workspaceFolder: root }); } diff --git a/extensions/typescript-language-features/src/utils/typeConverters.ts b/extensions/typescript-language-features/src/utils/typeConverters.ts index eaa6a96c8..37947b388 100644 --- a/extensions/typescript-language-features/src/utils/typeConverters.ts +++ b/extensions/typescript-language-features/src/utils/typeConverters.ts @@ -13,9 +13,12 @@ import { ITypeScriptServiceClient } from '../typescriptService'; export namespace Range { export const fromTextSpan = (span: Proto.TextSpan): vscode.Range => + fromLocations(span.start, span.end); + + export const fromLocations = (start: Proto.Location, end: Proto.Location): vscode.Range => new vscode.Range( - Math.max(0, span.start.line - 1), Math.max(span.start.offset - 1, 0), - Math.max(0, span.end.line - 1), Math.max(0, span.end.offset - 1)); + Math.max(0, start.line - 1), Math.max(start.offset - 1, 0), + Math.max(0, end.line - 1), Math.max(0, end.offset - 1)); export const toFileRangeRequestArgs = (file: string, range: vscode.Range): Proto.FileRangeRequestArgs => ({ file, diff --git a/extensions/typescript-language-features/src/utils/versionPicker.ts b/extensions/typescript-language-features/src/utils/versionPicker.ts index afbda6ef2..d1827002e 100644 --- a/extensions/typescript-language-features/src/utils/versionPicker.ts +++ b/extensions/typescript-language-features/src/utils/versionPicker.ts @@ -113,7 +113,7 @@ export class TypeScriptVersionPicker { return { oldVersion: previousVersion, newVersion: shippedVersion }; case MessageAction.learnMore: - vscode.commands.executeCommand('vscode.open', vscode.Uri.parse('https://go.microsoft.com/fwlink/?linkid=839919')); + vscode.env.openExternal(vscode.Uri.parse('https://go.microsoft.com/fwlink/?linkid=839919')); return { oldVersion: this.currentVersion }; default: diff --git a/extensions/typescript-language-features/src/utils/versionProvider.ts b/extensions/typescript-language-features/src/utils/versionProvider.ts index eb50009cf..8e9e9a2a8 100644 --- a/extensions/typescript-language-features/src/utils/versionProvider.ts +++ b/extensions/typescript-language-features/src/utils/versionProvider.ts @@ -9,8 +9,8 @@ import * as nls from 'vscode-nls'; import API from './api'; import { TypeScriptServiceConfiguration } from './configuration'; import { RelativeWorkspacePathResolver } from './relativePathResolver'; -const localize = nls.loadMessageBundle(); +const localize = nls.loadMessageBundle(); export class TypeScriptVersion { constructor( @@ -27,10 +27,10 @@ export class TypeScriptVersion { } public get isValid(): boolean { - return this.version !== undefined; + return this.apiVersion !== undefined; } - public get version(): API | undefined { + public get apiVersion(): API | undefined { const version = this.getTypeScriptVersion(this.tsServerPath); if (version) { return version; @@ -46,7 +46,7 @@ export class TypeScriptVersion { } public get versionString(): string { - const version = this.version; + const version = this.apiVersion; return version ? version.versionString : localize( 'couldNotLoadTsVersion', 'Could not load the TypeScript version at this path'); } @@ -88,7 +88,6 @@ export class TypeScriptVersion { } export class TypeScriptVersionProvider { - private readonly relativePathResolver: RelativeWorkspacePathResolver = new RelativeWorkspacePathResolver(); public constructor( private configuration: TypeScriptServiceConfiguration @@ -109,7 +108,7 @@ export class TypeScriptVersionProvider { return globals[0]; } } - return undefined; + return this.contributedTsNextVersion; } public get localVersion(): TypeScriptVersion | undefined { @@ -138,22 +137,37 @@ export class TypeScriptVersionProvider { } public get bundledVersion(): TypeScriptVersion { - try { - const { extensionPath } = vscode.extensions.getExtension('vscode.typescript-language-features')!; - const typescriptPath = path.join(extensionPath, '../node_modules/typescript/lib'); - const bundledVersion = new TypeScriptVersion(typescriptPath, ''); - if (bundledVersion.isValid) { - return bundledVersion; - } - } catch (e) { - // noop + const version = this.getContributedVersion('vscode.typescript-language-features', ['..', 'node_modules']); + if (version) { + return version; } + vscode.window.showErrorMessage(localize( 'noBundledServerFound', 'VS Code\'s tsserver was deleted by another application such as a misbehaving virus detection tool. Please reinstall VS Code.')); throw new Error('Could not find bundled tsserver.js'); } + private get contributedTsNextVersion(): TypeScriptVersion | undefined { + return this.getContributedVersion('ms-vscode.vscode-typescript-next', ['node_modules']); + } + + private getContributedVersion(extensionId: string, pathToTs: readonly string[]): TypeScriptVersion | undefined { + try { + const extension = vscode.extensions.getExtension(extensionId); + if (extension) { + const typescriptPath = path.join(extension.extensionPath, ...pathToTs, 'typescript', 'lib'); + const bundledVersion = new TypeScriptVersion(typescriptPath, ''); + if (bundledVersion.isValid) { + return bundledVersion; + } + } + } catch { + // noop + } + return undefined; + } + private get localTsdkVersions(): TypeScriptVersion[] { const localTsdk = this.configuration.localTsdk; return localTsdk ? this.loadVersionsFromSetting(localTsdk) : []; @@ -164,7 +178,7 @@ export class TypeScriptVersionProvider { return [new TypeScriptVersion(tsdkPathSetting)]; } - const workspacePath = this.relativePathResolver.asAbsoluteWorkspacePath(tsdkPathSetting); + const workspacePath = RelativeWorkspacePathResolver.asAbsoluteWorkspacePath(tsdkPathSetting); if (workspacePath !== undefined) { return [new TypeScriptVersion(workspacePath, tsdkPathSetting)]; } diff --git a/extensions/typescript-language-features/src/utils/versionStatus.ts b/extensions/typescript-language-features/src/utils/versionStatus.ts index 0b3e34126..07bd2e592 100644 --- a/extensions/typescript-language-features/src/utils/versionStatus.ts +++ b/extensions/typescript-language-features/src/utils/versionStatus.ts @@ -7,6 +7,9 @@ import * as vscode from 'vscode'; import * as languageModeIds from './languageModeIds'; import { TypeScriptVersion } from './versionProvider'; import { Disposable } from './dispose'; +import * as nls from 'vscode-nls'; + +const localize = nls.loadMessageBundle(); export default class VersionStatus extends Disposable { private readonly _versionBarEntry: vscode.StatusBarItem; @@ -15,7 +18,12 @@ export default class VersionStatus extends Disposable { private readonly _normalizePath: (resource: vscode.Uri) => string | undefined ) { super(); - this._versionBarEntry = this._register(vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 99 /* to the right of editor status (100) */)); + this._versionBarEntry = this._register(vscode.window.createStatusBarItem({ + id: 'status.typescript.version', + name: localize('typescriptVersion', "TypeScript: Version"), + alignment: vscode.StatusBarAlignment.Right, + priority: 99 /* to the right of editor status (100) */ + })); vscode.window.onDidChangeActiveTextEditor(this.showHideStatus, this, this._disposables); } diff --git a/extensions/typescript-language-features/yarn.lock b/extensions/typescript-language-features/yarn.lock index 62a9ee588..683f002c7 100644 --- a/extensions/typescript-language-features/yarn.lock +++ b/extensions/typescript-language-features/yarn.lock @@ -2,10 +2,42 @@ # yarn lockfile v1 -"@types/node@8.0.33": - version "8.0.33" - resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.33.tgz#1126e94374014e54478092830704f6ea89df04cd" - integrity sha512-vmCdO8Bm1ExT+FWfC9sd9r4jwqM7o97gGy2WBshkkXbf/2nLAJQUrZfIhw27yVOtLUev6kSZc4cav/46KbDd8A== +"@types/events@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" + integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g== + +"@types/glob@*": + version "7.1.1" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575" + integrity sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w== + dependencies: + "@types/events" "*" + "@types/minimatch" "*" + "@types/node" "*" + +"@types/minimatch@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" + integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== + +"@types/node@*": + version "12.0.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.0.2.tgz#3452a24edf9fea138b48fad4a0a028a683da1e40" + integrity sha512-5tabW/i+9mhrfEOUcLDu2xBPsHJ+X5Orqy9FKpale3SjDA17j5AEpYq5vfy3oAeAHGcvANRCO3NV3d2D6q3NiA== + +"@types/node@^10.14.8": + version "10.14.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9" + integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw== + +"@types/rimraf@2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-2.0.2.tgz#7f0fc3cf0ff0ad2a99bb723ae1764f30acaf8b6e" + integrity sha512-Hm/bnWq0TCy7jmjeN5bKYij9vw5GrDFWME4IuxV08278NtU/VdGbzsBohcCUJ7+QMqmUq5hpRKB39HeQWJjztQ== + dependencies: + "@types/glob" "*" + "@types/node" "*" "@types/semver@^5.5.0": version "5.5.0" @@ -630,6 +662,18 @@ glob@^5.0.3: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^7.1.3: + version "7.1.4" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" + integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + glogg@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/glogg/-/glogg-1.0.1.tgz#dcf758e44789cc3f3d32c1f3562a3676e6a34810" @@ -1490,6 +1534,13 @@ rimraf@2: dependencies: glob "^7.0.5" +rimraf@^2.6.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== + dependencies: + glob "^7.1.3" + safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" diff --git a/extensions/vb/package.json b/extensions/vb/package.json index 3aed441f9..f41732e9d 100644 --- a/extensions/vb/package.json +++ b/extensions/vb/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "*" }, "scripts": { "update-grammar": "node ../../build/npm/update-grammar.js textmate/asp.vb.net.tmbundle Syntaxes/ASP%20VB.net.plist ./syntaxes/asp-vb-net.tmlanguage.json" diff --git a/extensions/vscode-api-tests/package.json b/extensions/vscode-api-tests/package.json index e1716b855..beaa216d7 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", + "license": "MIT", "enableProposedApi": true, "private": true, "main": "horse", @@ -49,7 +50,7 @@ }, "devDependencies": { "@types/mocha": "2.2.43", - "@types/node": "^10.12.21", + "@types/node": "^10.14.8", "mocha-junit-reporter": "^1.17.0", "mocha-multi-reporters": "^1.1.7", "typescript": "^1.6.2", diff --git a/extensions/vscode-api-tests/src/memfs.ts b/extensions/vscode-api-tests/src/memfs.ts new file mode 100644 index 000000000..2b4a5f751 --- /dev/null +++ b/extensions/vscode-api-tests/src/memfs.ts @@ -0,0 +1,229 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + + +import * as path from 'path'; +import * as vscode from 'vscode'; + +class File implements vscode.FileStat { + + type: vscode.FileType; + ctime: number; + mtime: number; + size: number; + + name: string; + data?: Uint8Array; + + constructor(name: string) { + this.type = vscode.FileType.File; + this.ctime = Date.now(); + this.mtime = Date.now(); + this.size = 0; + this.name = name; + } +} + +class Directory implements vscode.FileStat { + + type: vscode.FileType; + ctime: number; + mtime: number; + size: number; + + name: string; + entries: Map; + + constructor(name: string) { + this.type = vscode.FileType.Directory; + this.ctime = Date.now(); + this.mtime = Date.now(); + this.size = 0; + this.name = name; + this.entries = new Map(); + } +} + +export type Entry = File | Directory; + +export class MemFS implements vscode.FileSystemProvider { + + readonly scheme = 'fake-fs'; + + readonly root = new Directory(''); + + // --- manage file metadata + + stat(uri: vscode.Uri): vscode.FileStat { + return this._lookup(uri, false); + } + + readDirectory(uri: vscode.Uri): [string, vscode.FileType][] { + const entry = this._lookupAsDirectory(uri, false); + let result: [string, vscode.FileType][] = []; + for (const [name, child] of entry.entries) { + result.push([name, child.type]); + } + return result; + } + + // --- manage file contents + + readFile(uri: vscode.Uri): Uint8Array { + const data = this._lookupAsFile(uri, false).data; + if (data) { + return data; + } + throw vscode.FileSystemError.FileNotFound(); + } + + writeFile(uri: vscode.Uri, content: Uint8Array, options: { create: boolean, overwrite: boolean }): void { + let basename = path.posix.basename(uri.path); + let parent = this._lookupParentDirectory(uri); + let entry = parent.entries.get(basename); + if (entry instanceof Directory) { + throw vscode.FileSystemError.FileIsADirectory(uri); + } + if (!entry && !options.create) { + throw vscode.FileSystemError.FileNotFound(uri); + } + if (entry && options.create && !options.overwrite) { + throw vscode.FileSystemError.FileExists(uri); + } + if (!entry) { + entry = new File(basename); + parent.entries.set(basename, entry); + this._fireSoon({ type: vscode.FileChangeType.Created, uri }); + } + entry.mtime = Date.now(); + entry.size = content.byteLength; + entry.data = content; + + this._fireSoon({ type: vscode.FileChangeType.Changed, uri }); + } + + // --- manage files/folders + + rename(oldUri: vscode.Uri, newUri: vscode.Uri, options: { overwrite: boolean }): void { + + if (!options.overwrite && this._lookup(newUri, true)) { + throw vscode.FileSystemError.FileExists(newUri); + } + + let entry = this._lookup(oldUri, false); + let oldParent = this._lookupParentDirectory(oldUri); + + let newParent = this._lookupParentDirectory(newUri); + let newName = path.posix.basename(newUri.path); + + oldParent.entries.delete(entry.name); + entry.name = newName; + newParent.entries.set(newName, entry); + + this._fireSoon( + { type: vscode.FileChangeType.Deleted, uri: oldUri }, + { type: vscode.FileChangeType.Created, uri: newUri } + ); + } + + delete(uri: vscode.Uri): void { + let dirname = uri.with({ path: path.posix.dirname(uri.path) }); + let basename = path.posix.basename(uri.path); + let parent = this._lookupAsDirectory(dirname, false); + if (!parent.entries.has(basename)) { + throw vscode.FileSystemError.FileNotFound(uri); + } + parent.entries.delete(basename); + parent.mtime = Date.now(); + parent.size -= 1; + this._fireSoon({ type: vscode.FileChangeType.Changed, uri: dirname }, { uri, type: vscode.FileChangeType.Deleted }); + } + + createDirectory(uri: vscode.Uri): void { + let basename = path.posix.basename(uri.path); + let dirname = uri.with({ path: path.posix.dirname(uri.path) }); + let parent = this._lookupAsDirectory(dirname, false); + + let entry = new Directory(basename); + parent.entries.set(entry.name, entry); + parent.mtime = Date.now(); + parent.size += 1; + this._fireSoon({ type: vscode.FileChangeType.Changed, uri: dirname }, { type: vscode.FileChangeType.Created, uri }); + } + + // --- lookup + + private _lookup(uri: vscode.Uri, silent: false): Entry; + private _lookup(uri: vscode.Uri, silent: boolean): Entry | undefined; + private _lookup(uri: vscode.Uri, silent: boolean): Entry | undefined { + let parts = uri.path.split('/'); + let entry: Entry = this.root; + for (const part of parts) { + if (!part) { + continue; + } + let child: Entry | undefined; + if (entry instanceof Directory) { + child = entry.entries.get(part); + } + if (!child) { + if (!silent) { + throw vscode.FileSystemError.FileNotFound(uri); + } else { + return undefined; + } + } + entry = child; + } + return entry; + } + + private _lookupAsDirectory(uri: vscode.Uri, silent: boolean): Directory { + let entry = this._lookup(uri, silent); + if (entry instanceof Directory) { + return entry; + } + throw vscode.FileSystemError.FileNotADirectory(uri); + } + + private _lookupAsFile(uri: vscode.Uri, silent: boolean): File { + let entry = this._lookup(uri, silent); + if (entry instanceof File) { + return entry; + } + throw vscode.FileSystemError.FileIsADirectory(uri); + } + + private _lookupParentDirectory(uri: vscode.Uri): Directory { + const dirname = uri.with({ path: path.posix.dirname(uri.path) }); + return this._lookupAsDirectory(dirname, false); + } + + // --- manage file events + + private _emitter = new vscode.EventEmitter(); + private _bufferedEvents: vscode.FileChangeEvent[] = []; + private _fireSoonHandle?: NodeJS.Timer; + + readonly onDidChangeFile: vscode.Event = this._emitter.event; + + watch(_resource: vscode.Uri): vscode.Disposable { + // ignore, fires for all changes... + return new vscode.Disposable(() => { }); + } + + private _fireSoon(...events: vscode.FileChangeEvent[]): void { + this._bufferedEvents.push(...events); + + if (this._fireSoonHandle) { + clearTimeout(this._fireSoonHandle); + } + + this._fireSoonHandle = setTimeout(() => { + this._emitter.fire(this._bufferedEvents); + this._bufferedEvents.length = 0; + }, 5); + } +} diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/commands.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/commands.test.ts index a3d5690b9..9ea76e6a1 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/commands.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/commands.test.ts @@ -113,4 +113,31 @@ suite('commands namespace tests', () => { return Promise.all([a, b, c, d]); }); -}); \ No newline at end of file + + test('onDidExecuteCommand', async function () { + let args: any[]; + let d1 = commands.registerCommand('t1', function () { + args = [...arguments]; + }); + + + const p = new Promise((resolve, reject) => { + + let d2 = commands.onDidExecuteCommand(event => { + d2.dispose(); + d1.dispose(); + + try { + assert.equal(event.command, 't1'); + assert.deepEqual(args, event.arguments); + resolve(); + } catch (e) { + reject(e); + } + }); + }); + + await commands.executeCommand('t1', { foo: 1 }); + await p; + }); +}); diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/editor.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/editor.test.ts index 80ad28ddf..9b6c6d828 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/editor.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/editor.test.ts @@ -195,4 +195,27 @@ suite('editor tests', () => { ); }); }); + + test('throw when using invalid edit', async function () { + + await withRandomFileEditor('foo', editor => { + + return new Promise((resolve, reject) => { + + editor.edit(edit => { + edit.insert(new Position(0, 0), 'bar'); + setTimeout(() => { + try { + edit.insert(new Position(0, 0), 'bar'); + reject(new Error('expected error')); + } catch (err) { + assert.ok(true); + resolve(); + } + }, 0); + }); + }); + }); + + }); }); diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/env.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/env.test.ts index 31d6d4ce3..112c76139 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/env.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/env.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { env } from 'vscode'; +import { env, extensions, ExtensionKind } from 'vscode'; suite('env-namespace', () => { @@ -14,6 +14,7 @@ suite('env-namespace', () => { assert.equal(typeof env.appName, 'string'); assert.equal(typeof env.machineId, 'string'); assert.equal(typeof env.sessionId, 'string'); + assert.equal(typeof env.shell, 'string'); }); test('env is readonly', function () { @@ -22,6 +23,25 @@ suite('env-namespace', () => { assert.throws(() => (env as any).appName = '234'); assert.throws(() => (env as any).machineId = '234'); assert.throws(() => (env as any).sessionId = '234'); + assert.throws(() => (env as any).shell = '234'); + }); + + test('env.remoteName', function () { + const remoteName = env.remoteName; + const apiTestExtension = extensions.getExtension('vscode.vscode-api-tests'); + const testResolverExtension = extensions.getExtension('vscode.vscode-test-resolver'); + if (typeof remoteName === 'undefined') { + assert.ok(apiTestExtension); + assert.ok(testResolverExtension); + assert.equal(ExtensionKind.UI, apiTestExtension!.extensionKind); + assert.equal(ExtensionKind.UI, testResolverExtension!.extensionKind); + } else if (typeof remoteName === 'string') { + assert.ok(apiTestExtension); + assert.ok(!testResolverExtension); // we currently can only access extensions that run on same host + assert.equal(ExtensionKind.Workspace, apiTestExtension!.extensionKind); + } else { + assert.fail(); + } }); }); diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/languages.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/languages.test.ts index 81c9c2eea..0a828ad8d 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/languages.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/languages.test.ts @@ -6,7 +6,7 @@ import * as assert from 'assert'; import { join } from 'path'; import * as vscode from 'vscode'; -import { createRandomFile } from '../utils'; +import { createRandomFile, testFs } from '../utils'; suite('languages namespace tests', () => { @@ -103,7 +103,7 @@ suite('languages namespace tests', () => { return [new vscode.DocumentLink(range, target)]; } }; - vscode.languages.registerDocumentLinkProvider({ language: 'java', scheme: 'file' }, linkProvider); + vscode.languages.registerDocumentLinkProvider({ language: 'java', scheme: testFs.scheme }, linkProvider); const links = await vscode.commands.executeCommand('vscode.executeLinkProvider', doc.uri); assert.equal(2, links && links.length); diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts new file mode 100644 index 000000000..dc281a06f --- /dev/null +++ b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts @@ -0,0 +1,353 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { window, Terminal, Pseudoterminal, EventEmitter, TerminalDimensions, workspace, ConfigurationTarget } from 'vscode'; +import { doesNotThrow, equal, ok } from 'assert'; + +suite('window namespace tests', () => { + suiteSetup(async () => { + // Disable conpty in integration tests because of https://github.com/microsoft/vscode/issues/76548 + await workspace.getConfiguration('terminal.integrated').update('windowsEnableConpty', false, ConfigurationTarget.Global); + }); + suite('Terminal', () => { + test('sendText immediately after createTerminal should not throw', (done) => { + const reg1 = window.onDidOpenTerminal(term => { + equal(terminal, term); + terminal.dispose(); + reg1.dispose(); + const reg2 = window.onDidCloseTerminal(() => { + reg2.dispose(); + done(); + }); + }); + const terminal = window.createTerminal(); + doesNotThrow(terminal.sendText.bind(terminal, 'echo "foo"')); + }); + + test('onDidCloseTerminal event fires when terminal is disposed', (done) => { + const reg1 = window.onDidOpenTerminal(term => { + equal(terminal, term); + terminal.dispose(); + reg1.dispose(); + const reg2 = window.onDidCloseTerminal(() => { + reg2.dispose(); + done(); + }); + }); + const terminal = window.createTerminal(); + }); + + test('processId immediately after createTerminal should fetch the pid', (done) => { + const reg1 = window.onDidOpenTerminal(term => { + equal(terminal, term); + reg1.dispose(); + terminal.processId.then(id => { + ok(id > 0); + terminal.dispose(); + const reg2 = window.onDidCloseTerminal(() => { + reg2.dispose(); + done(); + }); + }); + }); + const terminal = window.createTerminal(); + }); + + test('name in constructor should set terminal.name', (done) => { + const reg1 = window.onDidOpenTerminal(term => { + equal(terminal, term); + terminal.dispose(); + reg1.dispose(); + const reg2 = window.onDidCloseTerminal(() => { + reg2.dispose(); + done(); + }); + }); + const terminal = window.createTerminal('a'); + equal(terminal.name, 'a'); + }); + + test('onDidOpenTerminal should fire when a terminal is created', (done) => { + const reg1 = window.onDidOpenTerminal(term => { + equal(term.name, 'b'); + reg1.dispose(); + const reg2 = window.onDidCloseTerminal(() => { + reg2.dispose(); + done(); + }); + terminal.dispose(); + }); + const terminal = window.createTerminal('b'); + }); + + test('Terminal.sendText should fire Terminal.onInput', (done) => { + const reg1 = window.onDidOpenTerminal(terminal => { + reg1.dispose(); + const reg2 = renderer.onDidAcceptInput(data => { + equal(data, 'bar'); + reg2.dispose(); + const reg3 = window.onDidCloseTerminal(() => { + reg3.dispose(); + done(); + }); + terminal.dispose(); + }); + terminal.sendText('bar', false); + }); + const renderer = window.createTerminalRenderer('foo'); + }); + + // test('onDidChangeActiveTerminal should fire when new terminals are created', (done) => { + // const reg1 = window.onDidChangeActiveTerminal((active: Terminal | undefined) => { + // equal(active, terminal); + // equal(active, window.activeTerminal); + // reg1.dispose(); + // const reg2 = window.onDidChangeActiveTerminal((active: Terminal | undefined) => { + // equal(active, undefined); + // equal(active, window.activeTerminal); + // reg2.dispose(); + // done(); + // }); + // terminal.dispose(); + // }); + // const terminal = window.createTerminal(); + // terminal.show(); + // }); + + // test('onDidChangeTerminalDimensions should fire when new terminals are created', (done) => { + // const reg1 = window.onDidChangeTerminalDimensions(async (event: TerminalDimensionsChangeEvent) => { + // equal(event.terminal, terminal1); + // equal(typeof event.dimensions.columns, 'number'); + // equal(typeof event.dimensions.rows, 'number'); + // ok(event.dimensions.columns > 0); + // ok(event.dimensions.rows > 0); + // reg1.dispose(); + // let terminal2: Terminal; + // const reg2 = window.onDidOpenTerminal((newTerminal) => { + // // This is guarantees to fire before dimensions change event + // if (newTerminal !== terminal1) { + // terminal2 = newTerminal; + // reg2.dispose(); + // } + // }); + // let firstCalled = false; + // let secondCalled = false; + // const reg3 = window.onDidChangeTerminalDimensions((event: TerminalDimensionsChangeEvent) => { + // if (event.terminal === terminal1) { + // // The original terminal should fire dimension change after a split + // firstCalled = true; + // } else if (event.terminal !== terminal1) { + // // The new split terminal should fire dimension change + // secondCalled = true; + // } + // if (firstCalled && secondCalled) { + // let firstDisposed = false; + // let secondDisposed = false; + // const reg4 = window.onDidCloseTerminal(term => { + // if (term === terminal1) { + // firstDisposed = true; + // } + // if (term === terminal2) { + // secondDisposed = true; + // } + // if (firstDisposed && secondDisposed) { + // reg4.dispose(); + // done(); + // } + // }); + // terminal1.dispose(); + // terminal2.dispose(); + // reg3.dispose(); + // } + // }); + // await timeout(500); + // commands.executeCommand('workbench.action.terminal.split'); + // }); + // const terminal1 = window.createTerminal({ name: 'test' }); + // terminal1.show(); + // }); + + suite('hideFromUser', () => { + // test('should fire onDidWriteData correctly', done => { + // const terminal = window.createTerminal({ name: 'bg', hideFromUser: true }); + // let data = ''; + // terminal.onDidWriteData(e => { + // data += e; + // if (data.indexOf('foo') !== -1) { + // const reg3 = window.onDidCloseTerminal(() => { + // reg3.dispose(); + // done(); + // }); + // terminal.dispose(); + // } + // }); + // terminal.sendText('foo'); + // }); + + test('should be available to terminals API', done => { + const terminal = window.createTerminal({ name: 'bg', hideFromUser: true }); + window.onDidOpenTerminal(t => { + equal(t, terminal); + equal(t.name, 'bg'); + ok(window.terminals.indexOf(terminal) !== -1); + const reg3 = window.onDidCloseTerminal(() => { + reg3.dispose(); + done(); + }); + terminal.dispose(); + }); + }); + }); + + suite('Terminal renderers (deprecated)', () => { + test('should fire onDidOpenTerminal and onDidCloseTerminal from createTerminalRenderer terminal', (done) => { + const reg1 = window.onDidOpenTerminal(term => { + equal(term.name, 'c'); + reg1.dispose(); + const reg2 = window.onDidCloseTerminal(() => { + reg2.dispose(); + done(); + }); + term.dispose(); + }); + window.createTerminalRenderer('c'); + }); + + test('should get maximum dimensions set when shown', (done) => { + let terminal: Terminal; + const reg1 = window.onDidOpenTerminal(term => { + reg1.dispose(); + term.show(); + terminal = term; + }); + const renderer = window.createTerminalRenderer('foo'); + const reg2 = renderer.onDidChangeMaximumDimensions(dimensions => { + ok(dimensions.columns > 0); + ok(dimensions.rows > 0); + reg2.dispose(); + const reg3 = window.onDidCloseTerminal(() => { + reg3.dispose(); + done(); + }); + terminal.dispose(); + }); + }); + + test('should fire Terminal.onData on write', (done) => { + const reg1 = window.onDidOpenTerminal(terminal => { + reg1.dispose(); + const reg2 = terminal.onDidWriteData(data => { + equal(data, 'bar'); + reg2.dispose(); + const reg3 = window.onDidCloseTerminal(() => { + reg3.dispose(); + done(); + }); + terminal.dispose(); + }); + renderer.write('bar'); + }); + const renderer = window.createTerminalRenderer('foo'); + }); + }); + + suite('Virtual process terminals', () => { + test('should fire onDidOpenTerminal and onDidCloseTerminal', (done) => { + const reg1 = window.onDidOpenTerminal(term => { + equal(term.name, 'c'); + reg1.dispose(); + const reg2 = window.onDidCloseTerminal(() => { + reg2.dispose(); + done(); + }); + term.dispose(); + }); + const pty: Pseudoterminal = { + onDidWrite: new EventEmitter().event, + open: () => {}, + close: () => {} + }; + window.createTerminal({ name: 'c', pty }); + }); + + test('should fire Terminal.onData on write', (done) => { + const reg1 = window.onDidOpenTerminal(async term => { + equal(terminal, term); + reg1.dispose(); + const reg2 = terminal.onDidWriteData(data => { + equal(data, 'bar'); + reg2.dispose(); + const reg3 = window.onDidCloseTerminal(() => { + reg3.dispose(); + done(); + }); + terminal.dispose(); + }); + await startPromise; + writeEmitter.fire('bar'); + }); + let startResolve: () => void; + const startPromise: Promise = new Promise(r => startResolve = r); + const writeEmitter = new EventEmitter(); + const pty: Pseudoterminal = { + onDidWrite: writeEmitter.event, + open: () => startResolve(), + close: () => {} + }; + const terminal = window.createTerminal({ name: 'foo', pty }); + }); + + test('should fire provide dimensions on start as the terminal has been shown', (done) => { + const reg1 = window.onDidOpenTerminal(term => { + equal(terminal, term); + reg1.dispose(); + }); + const pty: Pseudoterminal = { + onDidWrite: new EventEmitter().event, + open: (dimensions) => { + ok(dimensions!.columns > 0); + ok(dimensions!.rows > 0); + const reg3 = window.onDidCloseTerminal(() => { + reg3.dispose(); + done(); + }); + terminal.dispose(); + }, + close: () => {} + }; + const terminal = window.createTerminal({ name: 'foo', pty }); + }); + + test('should respect dimension overrides', (done) => { + const reg1 = window.onDidOpenTerminal(term => { + equal(terminal, term); + reg1.dispose(); + term.show(); + const reg2 = window.onDidChangeTerminalDimensions(e => { + equal(e.dimensions.columns, 10); + equal(e.dimensions.rows, 5); + equal(e.terminal, terminal); + reg2.dispose(); + const reg3 = window.onDidCloseTerminal(() => { + reg3.dispose(); + done(); + }); + terminal.dispose(); + }); + overrideDimensionsEmitter.fire({ columns: 10, rows: 5 }); + }); + const writeEmitter = new EventEmitter(); + const overrideDimensionsEmitter = new EventEmitter(); + const pty: Pseudoterminal = { + onDidWrite: writeEmitter.event, + onDidOverrideDimensions: overrideDimensionsEmitter.event, + open: () => {}, + close: () => {} + }; + const terminal = window.createTerminal({ name: 'foo', pty }); + }); + }); + }); +}); diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/webview.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/webview.test.ts index 5e28b247b..4be0218ab 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/webview.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/webview.test.ts @@ -132,24 +132,7 @@ suite('Webview tests', () => { // Open webview in same column const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, { enableScripts: true })); const ready = getMesssage(webview); - webview.webview.html = createHtmlDocumentWithBody(/*html*/` - `); + webview.webview.html = statefulWebviewHtml; await ready; const firstResponse = await sendRecieveMessage(webview, { type: 'add' }); @@ -167,25 +150,7 @@ suite('Webview tests', () => { const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, { enableScripts: true, retainContextWhenHidden: true })); const ready = getMesssage(webview); - webview.webview.html = createHtmlDocumentWithBody(/*html*/` - `); + webview.webview.html = statefulWebviewHtml; await ready; const firstResponse = await sendRecieveMessage(webview, { type: 'add' }); @@ -244,6 +209,33 @@ suite('Webview tests', () => { assert.strictEqual(secondResponse.value, 100); }); + conditionalTest('webviews with retainContextWhenHidden should be able to recive messages while hidden', async () => { + const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, { enableScripts: true, retainContextWhenHidden: true })); + const ready = getMesssage(webview); + + webview.webview.html = statefulWebviewHtml; + await ready; + + const firstResponse = await sendRecieveMessage(webview, { type: 'add' }); + assert.strictEqual((await firstResponse).value, 1); + + // Swap away from the webview + const doc = await vscode.workspace.openTextDocument(testDocument); + await vscode.window.showTextDocument(doc); + + // Try posting a message to our hidden webview + const secondResponse = await sendRecieveMessage(webview, { type: 'add' }); + assert.strictEqual((await secondResponse).value, 2); + + // Now show webview again + webview.reveal(vscode.ViewColumn.One); + + // We should still have old state + const thirdResponse = await sendRecieveMessage(webview, { type: 'get' }); + assert.strictEqual(thirdResponse.value, 2); + }); + + conditionalTest('webviews should only be able to load resources from workspace by default', async () => { const webview = _register(vscode.window.createWebviewPanel(webviewId, 'title', { viewColumn: vscode.ViewColumn.One }, { enableScripts: true })); @@ -259,15 +251,18 @@ suite('Webview tests', () => { }); `); - const workspaceRootUri = vscode.Uri.file(vscode.workspace.rootPath!).with({ scheme: 'vscode-resource' }); + async function toWebviewResource(path: string) { + const root = await webview.webview.toWebviewResource(vscode.Uri.file(vscode.workspace.rootPath!)); + return root.toString() + path; + } { - const imagePath = workspaceRootUri.toString() + '/image.png'; + const imagePath = await toWebviewResource('/image.png'); const response = sendRecieveMessage(webview, { src: imagePath }); assert.strictEqual((await response).value, true); } { - const imagePath = workspaceRootUri.toString() + '/no-such-image.png'; + const imagePath = await toWebviewResource('/no-such-image.png'); const response = sendRecieveMessage(webview, { src: imagePath }); assert.strictEqual((await response).value, false); } @@ -356,6 +351,27 @@ function createHtmlDocumentWithBody(body: string): string { `; } +const statefulWebviewHtml = createHtmlDocumentWithBody(/*html*/ ` + `); + + function getMesssage(webview: vscode.WebviewPanel): Promise { return new Promise(resolve => { const sub = webview.webview.onDidReceiveMessage(message => { diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/window.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/window.test.ts index f68441620..c2ec4f136 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/window.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/window.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { workspace, window, commands, ViewColumn, TextEditorViewColumnChangeEvent, Uri, Selection, Position, CancellationTokenSource, TextEditorSelectionChangeKind, Terminal, TerminalDimensionsChangeEvent } from 'vscode'; +import { workspace, window, commands, ViewColumn, TextEditorViewColumnChangeEvent, Uri, Selection, Position, CancellationTokenSource, TextEditorSelectionChangeKind } from 'vscode'; import { join } from 'path'; import { closeAllEditors, pathEquals, createRandomFile } from '../utils'; @@ -568,178 +568,4 @@ suite('window namespace tests', () => { }); }); - - suite('Terminal', () => { - test('sendText immediately after createTerminal should not throw', () => { - const terminal = window.createTerminal(); - assert.doesNotThrow(terminal.sendText.bind(terminal, 'echo "foo"')); - terminal.dispose(); - }); - - test('onDidCloseTerminal event fires when terminal is disposed', (done) => { - const terminal = window.createTerminal(); - const reg = window.onDidCloseTerminal((eventTerminal) => { - assert.equal(terminal, eventTerminal); - reg.dispose(); - done(); - }); - terminal.dispose(); - }); - - test('processId immediately after createTerminal should fetch the pid', (done) => { - const terminal = window.createTerminal(); - terminal.processId.then(id => { - assert.ok(id > 0); - terminal.dispose(); - done(); - }); - }); - - test('name in constructor should set terminal.name', () => { - const terminal = window.createTerminal('a'); - assert.equal(terminal.name, 'a'); - terminal.dispose(); - }); - - test('onDidOpenTerminal should fire when a terminal is created', (done) => { - const reg1 = window.onDidOpenTerminal(term => { - assert.equal(term.name, 'b'); - reg1.dispose(); - const reg2 = window.onDidCloseTerminal(() => { - reg2.dispose(); - done(); - }); - terminal.dispose(); - }); - const terminal = window.createTerminal('b'); - }); - - test('createTerminalRenderer should fire onDidOpenTerminal and onDidCloseTerminal', (done) => { - const reg1 = window.onDidOpenTerminal(term => { - assert.equal(term.name, 'c'); - reg1.dispose(); - const reg2 = window.onDidCloseTerminal(() => { - reg2.dispose(); - done(); - }); - term.dispose(); - }); - window.createTerminalRenderer('c'); - }); - - test('terminal renderers should get maximum dimensions set when shown', (done) => { - let terminal: Terminal; - const reg1 = window.onDidOpenTerminal(term => { - reg1.dispose(); - term.show(); - terminal = term; - }); - const renderer = window.createTerminalRenderer('foo'); - const reg2 = renderer.onDidChangeMaximumDimensions(dimensions => { - assert.ok(dimensions.columns > 0); - assert.ok(dimensions.rows > 0); - reg2.dispose(); - const reg3 = window.onDidCloseTerminal(() => { - reg3.dispose(); - done(); - }); - terminal.dispose(); - }); - }); - - test('TerminalRenderer.write should fire Terminal.onData', (done) => { - const reg1 = window.onDidOpenTerminal(terminal => { - reg1.dispose(); - const reg2 = terminal.onDidWriteData(data => { - assert.equal(data, 'bar'); - reg2.dispose(); - const reg3 = window.onDidCloseTerminal(() => { - reg3.dispose(); - done(); - }); - terminal.dispose(); - }); - renderer.write('bar'); - }); - const renderer = window.createTerminalRenderer('foo'); - }); - - test('Terminal.sendText should fire Terminal.onInput', (done) => { - const reg1 = window.onDidOpenTerminal(terminal => { - reg1.dispose(); - const reg2 = renderer.onDidAcceptInput(data => { - assert.equal(data, 'bar'); - reg2.dispose(); - const reg3 = window.onDidCloseTerminal(() => { - reg3.dispose(); - done(); - }); - terminal.dispose(); - }); - terminal.sendText('bar', false); - }); - const renderer = window.createTerminalRenderer('foo'); - }); - - test('onDidChangeActiveTerminal should fire when new terminals are created', (done) => { - const reg1 = window.onDidChangeActiveTerminal((active: Terminal | undefined) => { - assert.equal(active, terminal); - assert.equal(active, window.activeTerminal); - reg1.dispose(); - const reg2 = window.onDidChangeActiveTerminal((active: Terminal | undefined) => { - assert.equal(active, undefined); - assert.equal(active, window.activeTerminal); - reg2.dispose(); - done(); - }); - terminal.dispose(); - }); - const terminal = window.createTerminal(); - terminal.show(); - }); - - test('onDidChangeTerminalDimensions should fire when new terminals are created', (done) => { - const reg1 = window.onDidChangeTerminalDimensions(async (event: TerminalDimensionsChangeEvent) => { - assert.equal(event.terminal, terminal1); - assert.equal(typeof event.dimensions.columns, 'number'); - assert.equal(typeof event.dimensions.rows, 'number'); - assert.ok(event.dimensions.columns > 0); - assert.ok(event.dimensions.rows > 0); - reg1.dispose(); - let terminal2: Terminal; - const reg2 = window.onDidOpenTerminal((newTerminal) => { - // This is guarantees to fire before dimensions change event - if (newTerminal !== terminal1) { - terminal2 = newTerminal; - reg2.dispose(); - } - }); - let firstCalled = false; - let secondCalled = false; - const reg3 = window.onDidChangeTerminalDimensions((event: TerminalDimensionsChangeEvent) => { - if (event.terminal === terminal1) { - // The original terminal should fire dimension change after a split - firstCalled = true; - } else if (event.terminal !== terminal1) { - // The new split terminal should fire dimension change - secondCalled = true; - } - if (firstCalled && secondCalled) { - terminal1.dispose(); - terminal2.dispose(); - reg3.dispose(); - done(); - } - }); - await timeout(500); - commands.executeCommand('workbench.action.terminal.split'); - }); - const terminal1 = window.createTerminal({ name: 'test' }); - terminal1.show(); - }); - }); }); - -async function timeout(ms = 0): Promise { - return new Promise(resolve => setTimeout(() => resolve(), ms)); -} \ No newline at end of file diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.fs.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.fs.test.ts new file mode 100644 index 000000000..06728e206 --- /dev/null +++ b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.fs.test.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. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import * as vscode from 'vscode'; +import { posix } from 'path'; + +suite('workspace-fs', () => { + + let root: vscode.Uri; + + suiteSetup(function () { + root = vscode.workspace.workspaceFolders![0]!.uri; + }); + + test('fs.stat', async function () { + const stat = await vscode.workspace.fs.stat(root); + assert.equal(stat.type, vscode.FileType.Directory); + + assert.equal(typeof stat.size, 'number'); + assert.equal(typeof stat.mtime, 'number'); + assert.equal(typeof stat.ctime, 'number'); + + + const entries = await vscode.workspace.fs.readDirectory(root); + assert.ok(entries.length > 0); + + // find far.js + const tuple = entries.find(tuple => tuple[0] === 'far.js')!; + assert.ok(tuple); + assert.equal(tuple[0], 'far.js'); + assert.equal(tuple[1], vscode.FileType.File); + }); + + test('fs.stat - bad scheme', async function () { + try { + await vscode.workspace.fs.stat(vscode.Uri.parse('foo:/bar/baz/test.txt')); + assert.ok(false); + } catch { + assert.ok(true); + } + }); + + test('fs.stat - missing file', async function () { + try { + await vscode.workspace.fs.stat(root.with({ path: root.path + '.bad' })); + assert.ok(false); + } catch (e) { + assert.ok(true); + } + }); + + test('fs.write/stat/delete', async function () { + + const uri = root.with({ path: posix.join(root.path, 'new.file') }); + await vscode.workspace.fs.writeFile(uri, Buffer.from('HELLO')); + + const stat = await vscode.workspace.fs.stat(uri); + assert.equal(stat.type, vscode.FileType.File); + + await vscode.workspace.fs.delete(uri); + + try { + await vscode.workspace.fs.stat(uri); + assert.ok(false); + } catch { + assert.ok(true); + } + }); + + test('fs.delete folder', async function () { + + const folder = root.with({ path: posix.join(root.path, 'folder') }); + const file = root.with({ path: posix.join(root.path, 'folder/file') }); + + await vscode.workspace.fs.createDirectory(folder); + await vscode.workspace.fs.writeFile(file, Buffer.from('FOO')); + + await vscode.workspace.fs.stat(folder); + await vscode.workspace.fs.stat(file); + + // ensure non empty folder cannot be deleted + try { + await vscode.workspace.fs.delete(folder, { recursive: false, useTrash: false }); + assert.ok(false); + } catch { + await vscode.workspace.fs.stat(folder); + await vscode.workspace.fs.stat(file); + } + + // ensure non empty folder cannot be deleted is DEFAULT + try { + await vscode.workspace.fs.delete(folder); // recursive: false as default + assert.ok(false); + } catch { + await vscode.workspace.fs.stat(folder); + await vscode.workspace.fs.stat(file); + } + + // delete non empty folder with recursive-flag + await vscode.workspace.fs.delete(folder, { recursive: true, useTrash: false }); + + // esnure folder/file are gone + try { + await vscode.workspace.fs.stat(folder); + assert.ok(false); + } catch { + assert.ok(true); + } + try { + await vscode.workspace.fs.stat(file); + assert.ok(false); + } catch { + assert.ok(true); + } + }); + + test('throws FileSystemError', async function () { + + try { + await vscode.workspace.fs.stat(vscode.Uri.file(`/c468bf16-acfd-4591-825e-2bcebba508a3/71b1f274-91cb-4c19-af00-8495eaab4b73/4b60cb48-a6f2-40ea-9085-0936f4a8f59a.tx6`)); + assert.ok(false); + } catch (e) { + assert.ok(e instanceof vscode.FileSystemError); + assert.equal(e.name, vscode.FileSystemError.FileNotFound().name); + } + }); + + test('throws FileSystemError', async function () { + + try { + await vscode.workspace.fs.stat(vscode.Uri.parse('foo:/bar')); + assert.ok(false); + } catch (e) { + assert.ok(e instanceof vscode.FileSystemError); + assert.equal(e.name, vscode.FileSystemError.Unavailable().name); + } + }); +}); diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts new file mode 100644 index 000000000..daef12076 --- /dev/null +++ b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts @@ -0,0 +1,63 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import * as vscode from 'vscode'; + +suite('workspace-namespace', () => { + + suite('Tasks', () => { + + test('CustomExecution2 task should start and shutdown successfully', (done) => { + interface CustomTestingTaskDefinition extends vscode.TaskDefinition { + /** + * One of the task properties. This can be used to customize the task in the tasks.json + */ + customProp1: string; + } + const taskType: string = 'customTesting'; + const taskName = 'First custom task'; + const reg1 = vscode.window.onDidOpenTerminal(term => { + reg1.dispose(); + const reg2 = term.onDidWriteData(e => { + reg2.dispose(); + assert.equal(e, 'testing\r\n'); + term.dispose(); + }); + }); + const taskProvider = vscode.tasks.registerTaskProvider(taskType, { + provideTasks: () => { + const result: vscode.Task[] = []; + const kind: CustomTestingTaskDefinition = { + type: taskType, + customProp1: 'testing task one' + }; + const writeEmitter = new vscode.EventEmitter(); + const execution = new vscode.CustomExecution2((): Thenable => { + const pty: vscode.Pseudoterminal = { + onDidWrite: writeEmitter.event, + open: () => { + writeEmitter.fire('testing\r\n'); + }, + close: () => { + taskProvider.dispose(); + done(); + } + }; + return Promise.resolve(pty); + }); + const task = new vscode.Task2(kind, vscode.TaskScope.Workspace, taskName, taskType, execution); + result.push(task); + return result; + }, + resolveTask(_task: vscode.Task): vscode.Task | undefined { + assert.fail('resolveTask should not trigger during the test'); + return undefined; + } + }); + vscode.commands.executeCommand('workbench.action.tasks.runTask', `${taskType}: ${taskName}`); + }); + }); +}); diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts index b3b91a036..3617b55f4 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts @@ -5,10 +5,9 @@ import * as assert from 'assert'; import * as vscode from 'vscode'; -import { createRandomFile, deleteFile, closeAllEditors, pathEquals, rndName, disposeAll } from '../utils'; +import { createRandomFile, deleteFile, closeAllEditors, pathEquals, rndName, disposeAll, testFs } from '../utils'; import { join, posix, basename } from 'path'; import * as fs from 'fs'; -import * as os from 'os'; suite('workspace-namespace', () => { @@ -131,8 +130,7 @@ suite('workspace-namespace', () => { assert.ok(fs.existsSync(path)); d0.dispose(); - - return deleteFile(vscode.Uri.file(join(vscode.workspace.rootPath || '', './newfile.txt'))); + fs.unlinkSync(join(vscode.workspace.rootPath || '', './newfile.txt')); }); }); @@ -287,6 +285,30 @@ suite('workspace-namespace', () => { }); }); + test('events: onDidSaveTextDocument fires even for non dirty file when saved', () => { + return createRandomFile().then(file => { + let disposables: vscode.Disposable[] = []; + + let onDidSaveTextDocument = false; + disposables.push(vscode.workspace.onDidSaveTextDocument(e => { + assert.ok(pathEquals(e.uri.fsPath, file.fsPath)); + onDidSaveTextDocument = true; + })); + + return vscode.workspace.openTextDocument(file).then(doc => { + return vscode.window.showTextDocument(doc).then(() => { + return vscode.commands.executeCommand('workbench.action.files.save').then(() => { + assert.ok(onDidSaveTextDocument); + + disposeAll(disposables); + + return deleteFile(file); + }); + }); + }); + }); + }); + test('openTextDocument, with selection', function () { return createRandomFile('foo\nbar\nbar').then(file => { return vscode.workspace.openTextDocument(file).then(doc => { @@ -496,6 +518,20 @@ suite('workspace-namespace', () => { }); }); + test('findFiles - null exclude', async () => { + await vscode.workspace.findFiles('**/file.txt').then((res) => { + // search.exclude folder is still searched, files.exclude folder is not + assert.equal(res.length, 1); + assert.equal(basename(vscode.workspace.asRelativePath(res[0])), 'file.txt'); + }); + + await vscode.workspace.findFiles('**/file.txt', null).then((res) => { + // search.exclude and files.exclude folders are both searched + assert.equal(res.length, 2); + assert.equal(basename(vscode.workspace.asRelativePath(res[0])), 'file.txt'); + }); + }); + test('findFiles - exclude', () => { return vscode.workspace.findFiles('**/*.png').then((res) => { assert.equal(res.length, 2); @@ -664,10 +700,8 @@ suite('workspace-namespace', () => { test('WorkspaceEdit: edit and rename parent folder duplicates resource #42641', async function () { - let dir = join(os.tmpdir(), 'before-' + rndName()); - if (!fs.existsSync(dir)) { - fs.mkdirSync(dir); - } + let dir = vscode.Uri.parse(`${testFs.scheme}:/before-${rndName()}`); + await testFs.createDirectory(dir); let docUri = await createRandomFile('', dir); let docParent = docUri.with({ path: posix.dirname(docUri.path) }); @@ -772,4 +806,29 @@ suite('workspace-namespace', () => { we.deleteFile(docUri, { ignoreIfNotExists: true }); assert.ok(await vscode.workspace.applyEdit(we)); }); + + test('The api workspace.applyEdit drops the TextEdit if there is a RenameFile later #77735', async function () { + + let [f1, f2, f3] = await Promise.all([createRandomFile(), createRandomFile(), createRandomFile()]); + + let we = new vscode.WorkspaceEdit(); + we.insert(f1, new vscode.Position(0, 0), 'f1'); + we.insert(f2, new vscode.Position(0, 0), 'f2'); + we.insert(f3, new vscode.Position(0, 0), 'f3'); + + let f1_ = nameWithUnderscore(f1); + we.renameFile(f1, f1_); + + assert.ok(await vscode.workspace.applyEdit(we)); + + assert.equal((await vscode.workspace.openTextDocument(f3)).getText(), 'f3'); + assert.equal((await vscode.workspace.openTextDocument(f2)).getText(), 'f2'); + assert.equal((await vscode.workspace.openTextDocument(f1_)).getText(), 'f1'); + try { + await vscode.workspace.fs.stat(f1); + assert.ok(false); + } catch { + assert.ok(true); + } + }); }); diff --git a/extensions/vscode-api-tests/src/utils.ts b/extensions/vscode-api-tests/src/utils.ts index d9fda3bb7..38ede8488 100644 --- a/extensions/vscode-api-tests/src/utils.ts +++ b/extensions/vscode-api-tests/src/utils.ts @@ -4,25 +4,35 @@ *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; -import * as fs from 'fs'; -import * as os from 'os'; -import { join } from 'path'; +import { MemFS } from './memfs'; +import * as assert from 'assert'; export function rndName() { return Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 10); } -export function createRandomFile(contents = '', dir: string = os.tmpdir(), ext = ''): Thenable { - return new Promise((resolve, reject) => { - const tmpFile = join(dir, rndName() + ext); - fs.writeFile(tmpFile, contents, (error) => { - if (error) { - return reject(error); - } +export const testFs = new MemFS(); +vscode.workspace.registerFileSystemProvider(testFs.scheme, testFs); - resolve(vscode.Uri.file(tmpFile)); - }); - }); +export async function createRandomFile(contents = '', dir: vscode.Uri | undefined = undefined, ext = ''): Promise { + let fakeFile: vscode.Uri; + if (dir) { + assert.equal(dir.scheme, testFs.scheme); + fakeFile = dir.with({ path: dir.path + '/' + rndName() + ext }); + } else { + fakeFile = vscode.Uri.parse(`${testFs.scheme}:/${rndName() + ext}`); + } + await testFs.writeFile(fakeFile, Buffer.from(contents), { create: true, overwrite: true }); + return fakeFile; +} + +export async function deleteFile(file: vscode.Uri): Promise { + try { + await testFs.delete(file); + return true; + } catch { + return false; + } } export function pathEquals(path1: string, path2: string): boolean { @@ -34,30 +44,13 @@ export function pathEquals(path1: string, path2: string): boolean { return path1 === path2; } -export function deleteFile(file: vscode.Uri): Thenable { - return new Promise((resolve, reject) => { - fs.unlink(file.fsPath, (err) => { - if (err) { - reject(err); - } else { - resolve(true); - } - }); - }); -} - export function closeAllEditors(): Thenable { return vscode.commands.executeCommand('workbench.action.closeAllEditors'); } export function disposeAll(disposables: vscode.Disposable[]) { - while (disposables.length) { - let item = disposables.pop(); - if (item) { - item.dispose(); - } - } + vscode.Disposable.from(...disposables).dispose(); } export function conditionalTest(name: string, testCallback: (done: MochaDone) => void | Thenable) { @@ -73,4 +66,4 @@ export function conditionalTest(name: string, testCallback: (done: MochaDone) => function isTestTypeActive(): boolean { return !!vscode.extensions.getExtension('vscode-resolver-test'); -} \ No newline at end of file +} diff --git a/extensions/vscode-api-tests/testWorkspace/.vscode/settings.json b/extensions/vscode-api-tests/testWorkspace/.vscode/settings.json new file mode 100644 index 000000000..e9f6fb821 --- /dev/null +++ b/extensions/vscode-api-tests/testWorkspace/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "search.exclude": { + "**/search-exclude/**": true + }, + "files.exclude": { + "**/files-exclude/**": true + } +} \ No newline at end of file diff --git a/extensions/vscode-api-tests/testWorkspace/files-exclude/file.txt b/extensions/vscode-api-tests/testWorkspace/files-exclude/file.txt new file mode 100644 index 000000000..1a010b1c0 --- /dev/null +++ b/extensions/vscode-api-tests/testWorkspace/files-exclude/file.txt @@ -0,0 +1 @@ +file \ No newline at end of file diff --git a/extensions/vscode-api-tests/testWorkspace/search-exclude/file.txt b/extensions/vscode-api-tests/testWorkspace/search-exclude/file.txt new file mode 100644 index 000000000..1a010b1c0 --- /dev/null +++ b/extensions/vscode-api-tests/testWorkspace/search-exclude/file.txt @@ -0,0 +1 @@ +file \ No newline at end of file diff --git a/extensions/vscode-api-tests/yarn.lock b/extensions/vscode-api-tests/yarn.lock index c7841be13..758584125 100644 --- a/extensions/vscode-api-tests/yarn.lock +++ b/extensions/vscode-api-tests/yarn.lock @@ -7,10 +7,10 @@ resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.43.tgz#03c54589c43ad048cbcbfd63999b55d0424eec27" integrity sha512-xNlAmH+lRJdUMXClMTI9Y0pRqIojdxfm7DHsIxoB2iTzu3fnPmSMEN8SsSx0cdwV36d02PWCWaDUoZPDSln+xw== -"@types/node@^10.12.21": - version "10.12.21" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.21.tgz#7e8a0c34cf29f4e17a36e9bd0ea72d45ba03908e" - integrity sha512-CBgLNk4o3XMnqMc0rhb6lc77IwShMEglz05deDcn2lQxyXEZivfwgYJu7SMha9V5XcrP6qZuevTHV/QrN2vjKQ== +"@types/node@^10.14.8": + version "10.14.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9" + integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw== ajv@^5.1.0: version "5.3.0" diff --git a/extensions/vscode-colorize-tests/package.json b/extensions/vscode-colorize-tests/package.json index 763513a59..702e36e66 100644 --- a/extensions/vscode-colorize-tests/package.json +++ b/extensions/vscode-colorize-tests/package.json @@ -3,16 +3,16 @@ "description": "Colorize tests for VS Code", "version": "0.0.1", "publisher": "vscode", + "license": "MIT", "private": true, "engines": { "vscode": "*" }, "scripts": { - "vscode:prepublish": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../build/gulpfile.extensions.js compile-extension:vscode-colorize-tests ./tsconfig.json", - "postinstall": "node ./node_modules/vscode/bin/install" + "vscode:prepublish": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../build/gulpfile.extensions.js compile-extension:vscode-colorize-tests ./tsconfig.json" }, "devDependencies": { - "@types/node": "^10.12.21", + "@types/node": "^10.14.8", "mocha-junit-reporter": "^1.17.0", "mocha-multi-reporters": "^1.1.7", "vscode": "1.1.5" diff --git a/extensions/vscode-colorize-tests/src/typings/ref.d.ts b/extensions/vscode-colorize-tests/src/typings/ref.d.ts index 8ea9f802a..a45a0c635 100644 --- a/extensions/vscode-colorize-tests/src/typings/ref.d.ts +++ b/extensions/vscode-colorize-tests/src/typings/ref.d.ts @@ -4,3 +4,4 @@ *--------------------------------------------------------------------------------------------*/ /// +/// diff --git a/extensions/vscode-colorize-tests/yarn.lock b/extensions/vscode-colorize-tests/yarn.lock index 46684d06b..368b81f2f 100644 --- a/extensions/vscode-colorize-tests/yarn.lock +++ b/extensions/vscode-colorize-tests/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@types/node@^10.12.21": - version "10.12.21" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.21.tgz#7e8a0c34cf29f4e17a36e9bd0ea72d45ba03908e" - integrity sha512-CBgLNk4o3XMnqMc0rhb6lc77IwShMEglz05deDcn2lQxyXEZivfwgYJu7SMha9V5XcrP6qZuevTHV/QrN2vjKQ== +"@types/node@^10.14.8": + version "10.14.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9" + integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw== ajv@^5.1.0: version "5.3.0" diff --git a/extensions/vscode-test-resolver/.gitignore b/extensions/vscode-test-resolver/.gitignore new file mode 100644 index 000000000..8e5962ee7 --- /dev/null +++ b/extensions/vscode-test-resolver/.gitignore @@ -0,0 +1,2 @@ +out +node_modules \ No newline at end of file diff --git a/extensions/vscode-test-resolver/.vscode/launch.json b/extensions/vscode-test-resolver/.vscode/launch.json new file mode 100644 index 000000000..042a8d1fd --- /dev/null +++ b/extensions/vscode-test-resolver/.vscode/launch.json @@ -0,0 +1,22 @@ +// A launch configuration that compiles the extension and then opens it inside a new window +// Use IntelliSense to learn about possible attributes. +// Hover to view descriptions of existing attributes. +// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Extension", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": [ + "--extensionDevelopmentPath=${workspaceFolder}", + "--remote=test+test" + ], + "outFiles": [ + "${workspaceFolder}/out/**/*.js" + ] + } + ] +} \ No newline at end of file diff --git a/extensions/vscode-test-resolver/.vscodeignore b/extensions/vscode-test-resolver/.vscodeignore new file mode 100644 index 000000000..eb6a48615 --- /dev/null +++ b/extensions/vscode-test-resolver/.vscodeignore @@ -0,0 +1,6 @@ +.vscode/** +typings/** +**/*.ts +**/*.map +.gitignore +tsconfig.json diff --git a/extensions/vscode-test-resolver/package.json b/extensions/vscode-test-resolver/package.json new file mode 100644 index 000000000..0d93c4ea6 --- /dev/null +++ b/extensions/vscode-test-resolver/package.json @@ -0,0 +1,93 @@ +{ + "name": "vscode-test-resolver", + "description": "Test resolver for VS Code", + "version": "0.0.1", + "publisher": "vscode", + "enableProposedApi": true, + "private": true, + "engines": { + "vscode": "^1.25.0" + }, + "extensionKind": "ui", + "scripts": { + "compile": "node ./node_modules/vscode/bin/compile -watch -p ./", + "vscode:prepublish": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../build/gulpfile.extensions.js compile-extension:vscode-test-resolver ./tsconfig.json" + }, + "activationEvents": [ + "onResolveRemoteAuthority:test", + "onCommand:vscode-testresolver.newWindow", + "onCommand:vscode-testresolver.newWindowWithError", + "onCommand:vscode-testresolver.showLog" + ], + "main": "./out/extension", + "devDependencies": { + "@types/node": "^10.14.8", + "vscode": "1.1.5" + }, + "contributes": { + "resourceLabelFormatters": [ + { + "scheme": "vscode-remote", + "authority": "test+*", + "formatting": { + "label": "${path}", + "separator": "/", + "tildify": true, + "workspaceSuffix": "TestResolver" + } + } + ], + "commands": [ + { + "title": "New Window", + "category": "Remote-TestResolver", + "command": "vscode-testresolver.newWindow" + }, + { + "title": "Show Log", + "category": "Remote-TestResolver", + "command": "vscode-testresolver.showLog" + } + ], + "menus": { + "statusBar/windowIndicator": [ + { + "command": "vscode-testresolver.newWindow", + "when": "!remoteName", + "group": "9_local_testresolver@2" + }, + { + "command": "vscode-testresolver.showLog", + "when": "remoteName == test", + "group": "1_remote_testresolver_open@3" + }, + { + "command": "vscode-testresolver.newWindow", + "when": "remoteName == test", + "group": "1_remote_testresolver_open@1" + } + ] + }, + "configuration": { + "properties": { + "testresolver.startupDelay": { + "description": "If set, the resolver will delay for the given amount of seconds. Use ths setting for testing a slow resolver", + "type": "number", + "default": 0 + }, + "testresolver.startupError": { + "description": "If set, the resolver will fail. Use ths setting for testing the failure of a resolver.", + "type": "boolean", + "default": false + }, + "testresolver.pause": { + "description": "If set, connection is paused", + "type": "boolean", + "default": false + } + } + } + } + + +} \ No newline at end of file diff --git a/extensions/vscode-test-resolver/scripts/terminateProcess.sh b/extensions/vscode-test-resolver/scripts/terminateProcess.sh new file mode 100755 index 000000000..908a68287 --- /dev/null +++ b/extensions/vscode-test-resolver/scripts/terminateProcess.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +terminateTree() { + for cpid in $(/usr/bin/pgrep -P $1); do + terminateTree $cpid + done + kill -9 $1 > /dev/null 2>&1 +} + +for pid in $*; do + terminateTree $pid +done \ No newline at end of file diff --git a/extensions/vscode-test-resolver/src/download.ts b/extensions/vscode-test-resolver/src/download.ts new file mode 100644 index 000000000..d94ea2122 --- /dev/null +++ b/extensions/vscode-test-resolver/src/download.ts @@ -0,0 +1,117 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as https from 'https'; +import * as fs from 'fs'; +import * as path from 'path'; +import * as cp from 'child_process'; +import { parse as parseUrl } from 'url'; + +function ensureFolderExists(loc: string) { + if (!fs.existsSync(loc)) { + const parent = path.dirname(loc); + if (parent) { + ensureFolderExists(parent); + } + fs.mkdirSync(loc); + } +} + +function getDownloadUrl(updateUrl: string, commit: string, platform: string, quality: string): string { + return `${updateUrl}/commit:${commit}/server-${platform}/${quality}`; +} + +async function downloadVSCodeServerArchive(updateUrl: string, commit: string, quality: string, destDir: string): Promise { + ensureFolderExists(destDir); + + const platform = process.platform === 'win32' ? 'win32-x64' : process.platform === 'darwin' ? 'darwin' : 'linux-x64'; + const downloadUrl = getDownloadUrl(updateUrl, commit, platform, quality); + + return new Promise((resolve, reject) => { + console.log(`Downloading VS Code Server from: ${downloadUrl}`); + const requestOptions: https.RequestOptions = parseUrl(downloadUrl); + + https.get(requestOptions, res => { + if (res.statusCode !== 302) { + reject('Failed to get VS Code server archive location'); + } + const archiveUrl = res.headers.location; + if (!archiveUrl) { + reject('Failed to get VS Code server archive location'); + return; + } + + const archiveRequestOptions: https.RequestOptions = parseUrl(archiveUrl); + if (archiveUrl.endsWith('.zip')) { + const archivePath = path.resolve(destDir, `vscode-server-${commit}.zip`); + const outStream = fs.createWriteStream(archivePath); + outStream.on('close', () => { + resolve(archivePath); + }); + https.get(archiveRequestOptions, res => { + res.pipe(outStream); + }); + } else { + const zipPath = path.resolve(destDir, `vscode-server-${commit}.tgz`); + const outStream = fs.createWriteStream(zipPath); + https.get(archiveRequestOptions, res => { + res.pipe(outStream); + }); + outStream.on('close', () => { + resolve(zipPath); + }); + } + }); + }); +} + +/** + * Unzip a .zip or .tar.gz VS Code archive + */ +function unzipVSCodeServer(vscodeArchivePath: string, extractDir: string) { + if (vscodeArchivePath.endsWith('.zip')) { + const tempDir = fs.mkdtempSync('vscode-server'); + if (process.platform === 'win32') { + cp.spawnSync('powershell.exe', [ + '-NoProfile', + '-ExecutionPolicy', 'Bypass', + '-NonInteractive', + '-NoLogo', + '-Command', + `Microsoft.PowerShell.Archive\\Expand-Archive -Path "${vscodeArchivePath}" -DestinationPath "${tempDir}"` + ]); + } else { + cp.spawnSync('unzip', [vscodeArchivePath, '-d', `${tempDir}`]); + } + fs.renameSync(path.join(tempDir, process.platform === 'win32' ? 'vscode-server-win32-x64' : 'vscode-server-darwin'), extractDir); + } else { + // tar does not create extractDir by default + if (!fs.existsSync(extractDir)) { + fs.mkdirSync(extractDir); + } + cp.spawnSync('tar', ['-xzf', vscodeArchivePath, '-C', extractDir, '--strip-components', '1']); + } +} + +export async function downloadAndUnzipVSCodeServer(updateUrl: string, commit: string, quality: string = 'stable', destDir: string): Promise { + + const extractDir = path.join(destDir, commit); + if (fs.existsSync(extractDir)) { + console.log(`Found ${extractDir}. Skipping download.`); + } else { + console.log(`Downloading VS Code Server ${quality} - ${commit} into ${extractDir}.`); + try { + const vscodeArchivePath = await downloadVSCodeServerArchive(updateUrl, commit, quality, destDir); + if (fs.existsSync(vscodeArchivePath)) { + unzipVSCodeServer(vscodeArchivePath, extractDir); + // Remove archive + fs.unlinkSync(vscodeArchivePath); + } + } catch (err) { + throw Error(`Failed to download and unzip VS Code ${quality} - ${commit}`); + } + } + return Promise.resolve(extractDir); +} \ No newline at end of file diff --git a/extensions/vscode-test-resolver/src/extension.ts b/extensions/vscode-test-resolver/src/extension.ts new file mode 100644 index 000000000..0520edcff --- /dev/null +++ b/extensions/vscode-test-resolver/src/extension.ts @@ -0,0 +1,284 @@ +/*--------------------------------------------------------------------------------------------- + * 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 cp from 'child_process'; +import * as path from 'path'; +import * as fs from 'fs'; +import * as os from 'os'; +import * as net from 'net'; +import { downloadAndUnzipVSCodeServer } from './download'; +import { terminateProcess } from './util/processes'; + +let extHostProcess: cp.ChildProcess | undefined; +const enum CharCode { + Backspace = 8, + LineFeed = 10 +} + +let outputChannel: vscode.OutputChannel; + +export function activate(context: vscode.ExtensionContext) { + + function doResolve(_authority: string, progress: vscode.Progress<{ message?: string; increment?: number }>): Promise { + const serverPromise = new Promise(async (res, rej) => { + progress.report({ message: 'Starting Test Resolver' }); + outputChannel = vscode.window.createOutputChannel('TestResolver'); + + let isResolved = false; + async function processError(message: string) { + outputChannel.appendLine(message); + if (!isResolved) { + isResolved = true; + outputChannel.show(); + + const result = await vscode.window.showErrorMessage(message, { modal: true }, ...getActions()); + if (result) { + await result.execute(); + } + rej(vscode.RemoteAuthorityResolverError.NotAvailable(message, true)); + } + } + + let lastProgressLine = ''; + function processOutput(output: string) { + outputChannel.append(output); + for (let i = 0; i < output.length; i++) { + const chr = output.charCodeAt(i); + if (chr === CharCode.LineFeed) { + const match = lastProgressLine.match(/Extension host agent listening on (\d+)/); + if (match) { + isResolved = true; + res(new vscode.ResolvedAuthority('localhost', parseInt(match[1], 10))); // success! + } + lastProgressLine = ''; + } else if (chr === CharCode.Backspace) { + lastProgressLine = lastProgressLine.substr(0, lastProgressLine.length - 1); + } else { + lastProgressLine += output.charAt(i); + } + } + } + const delay = getConfiguration('startupDelay'); + if (typeof delay === 'number') { + let remaining = Math.ceil(delay); + outputChannel.append(`Delaying startup by ${remaining} seconds (configured by "testresolver.startupDelay").`); + while (remaining > 0) { + progress.report({ message: `Delayed resolving: Remaining ${remaining}s` }); + await (sleep(1000)); + remaining--; + } + } + + if (getConfiguration('startupError') === true) { + processError('Test Resolver failed for testing purposes (configured by "testresolver.startupError").'); + return; + } + + const { updateUrl, commit, quality, serverDataFolderName, dataFolderName } = getProductConfiguration(); + const serverCommand = process.platform === 'win32' ? 'server.bat' : 'server.sh'; + const commandArgs = ['--port=0', '--disable-telemetry']; + const env = getNewEnv(); + const remoteDataDir = process.env['TESTRESOLVER_DATA_FOLDER'] || path.join(os.homedir(), serverDataFolderName || `${dataFolderName}-testresolver`); + env['VSCODE_AGENT_FOLDER'] = remoteDataDir; + outputChannel.appendLine(`Using data folder at ${remoteDataDir}`); + + if (!commit) { // dev mode + const vscodePath = path.resolve(path.join(context.extensionPath, '..', '..')); + const serverCommandPath = path.join(vscodePath, 'resources', 'server', 'bin-dev', serverCommand); + extHostProcess = cp.spawn(serverCommandPath, commandArgs, { env, cwd: vscodePath }); + } else { + const serverBin = path.join(remoteDataDir, 'bin'); + progress.report({ message: 'Installing VSCode Server' }); + const serverLocation = await downloadAndUnzipVSCodeServer(updateUrl, commit, quality, serverBin); + outputChannel.appendLine(`Using server build at ${serverLocation}`); + + extHostProcess = cp.spawn(path.join(serverLocation, serverCommand), commandArgs, { env, cwd: serverLocation }); + } + extHostProcess.stdout.on('data', (data: Buffer) => processOutput(data.toString())); + extHostProcess.stderr.on('data', (data: Buffer) => processOutput(data.toString())); + extHostProcess.on('error', (error: Error) => { + processError(`server failed with error:\n${error.message}`); + extHostProcess = undefined; + }); + extHostProcess.on('close', (code: number) => { + processError(`server closed unexpectedly.\nError code: ${code}`); + extHostProcess = undefined; + }); + context.subscriptions.push({ + dispose: () => { + if (extHostProcess) { + terminateProcess(extHostProcess, context.extensionPath); + } + } + }); + }); + return serverPromise.then(serverAddr => { + return new Promise(async (res, _rej) => { + const proxyServer = net.createServer(proxySocket => { + outputChannel.appendLine(`Proxy connection accepted`); + let remoteReady = true, localReady = true; + const remoteSocket = net.createConnection({ port: serverAddr.port }); + + let isDisconnected = getConfiguration('pause') === true; + vscode.workspace.onDidChangeConfiguration(_ => { + let newIsDisconnected = getConfiguration('pause') === true; + if (isDisconnected !== newIsDisconnected) { + outputChannel.appendLine(`Connection state: ${newIsDisconnected ? 'open' : 'paused'}`); + isDisconnected = newIsDisconnected; + if (!isDisconnected) { + outputChannel.appendLine(`Resume remote and proxy sockets.`); + if (remoteSocket.isPaused() && localReady) { + remoteSocket.resume(); + } + if (proxySocket.isPaused() && remoteReady) { + proxySocket.resume(); + } + } else { + outputChannel.appendLine(`Pausing remote and proxy sockets.`); + if (!remoteSocket.isPaused()) { + remoteSocket.pause(); + } + if (!proxySocket.isPaused()) { + proxySocket.pause(); + } + } + } + }); + + proxySocket.on('data', (data) => { + remoteReady = remoteSocket.write(data); + if (!remoteReady) { + proxySocket.pause(); + } + }); + remoteSocket.on('data', (data) => { + localReady = proxySocket.write(data); + if (!localReady) { + remoteSocket.pause(); + } + }); + proxySocket.on('drain', () => { + localReady = true; + if (!isDisconnected) { + remoteSocket.resume(); + } + }); + remoteSocket.on('drain', () => { + remoteReady = true; + if (!isDisconnected) { + proxySocket.resume(); + } + }); + proxySocket.on('close', () => { + outputChannel.appendLine(`Proxy socket closed, closing remote socket.`); + remoteSocket.end(); + }); + remoteSocket.on('close', () => { + outputChannel.appendLine(`Remote socket closed, closing proxy socket.`); + proxySocket.end(); + }); + context.subscriptions.push({ + dispose: () => { + proxySocket.end(); + remoteSocket.end(); + } + }); + }); + proxyServer.listen(0, () => { + const port = (proxyServer.address()).port; + outputChannel.appendLine(`Going through proxy at port ${port}`); + res({ host: '127.0.0.1', port }); + }); + context.subscriptions.push({ + dispose: () => { + proxyServer.close(); + } + }); + }); + }); + } + + vscode.workspace.registerRemoteAuthorityResolver('test', { + resolve(_authority: string): Thenable { + return vscode.window.withProgress({ + location: vscode.ProgressLocation.Notification, + title: 'Open TestResolver Remote ([details](command:remote-testresolver.showLog))', + cancellable: false + }, (progress) => doResolve(_authority, progress)); + } + }); + + vscode.commands.registerCommand('vscode-testresolver.newWindow', () => { + return vscode.commands.executeCommand('vscode.newWindow', { remoteAuthority: 'test+test' }); + }); + vscode.commands.registerCommand('vscode-testresolver.newWindowWithError', () => { + return vscode.commands.executeCommand('vscode.newWindow', { remoteAuthority: 'test+error' }); + }); + vscode.commands.registerCommand('vscode-testresolver.showLog', () => { + if (outputChannel) { + outputChannel.show(); + } + }); +} + +type ActionItem = (vscode.MessageItem & { execute: () => void; }); + +function getActions(): ActionItem[] { + const actions: ActionItem[] = []; + const isDirty = vscode.workspace.textDocuments.some(d => d.isDirty) || vscode.workspace.workspaceFile && vscode.workspace.workspaceFile.scheme === 'untitled'; + + actions.push({ + title: 'Retry', + execute: async () => { + await vscode.commands.executeCommand('workbench.action.reloadWindow'); + } + }); + if (!isDirty) { + actions.push({ + title: 'Close Remote', + execute: async () => { + await vscode.commands.executeCommand('vscode.newWindow', { reuseWindow: true }); + } + }); + } + actions.push({ + title: 'Ignore', + isCloseAffordance: true, + execute: async () => { + vscode.commands.executeCommand('vscode-testresolver.showLog'); // no need to wait + } + }); + return actions; +} + +export interface IProductConfiguration { + updateUrl: string; + commit: string; + quality: string; + dataFolderName: string; + serverDataFolderName?: string; +} + +function getProductConfiguration(): IProductConfiguration { + const content = fs.readFileSync(path.join(vscode.env.appRoot, 'product.json')).toString(); + return JSON.parse(content) as IProductConfiguration; +} + +function getNewEnv(): { [x: string]: string | undefined } { + const env = { ...process.env }; + delete env['ELECTRON_RUN_AS_NODE']; + return env; +} + +function sleep(ms: number): Promise { + return new Promise(resolve => { + setTimeout(resolve, ms); + }); +} + +function getConfiguration(id: string): T | undefined { + return vscode.workspace.getConfiguration('testresolver').get(id); +} diff --git a/extensions/vscode-test-resolver/src/typings/ref.d.ts b/extensions/vscode-test-resolver/src/typings/ref.d.ts new file mode 100644 index 000000000..e3e47385d --- /dev/null +++ b/extensions/vscode-test-resolver/src/typings/ref.d.ts @@ -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. + *--------------------------------------------------------------------------------------------*/ + +/// +/// +/// diff --git a/extensions/vscode-test-resolver/src/util/processes.ts b/extensions/vscode-test-resolver/src/util/processes.ts new file mode 100644 index 000000000..d5af12566 --- /dev/null +++ b/extensions/vscode-test-resolver/src/util/processes.ts @@ -0,0 +1,37 @@ +/*--------------------------------------------------------------------------------------------- + * 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 * as path from 'path'; + +export interface TerminateResponse { + success: boolean; + error?: any; +} + +export function terminateProcess(p: cp.ChildProcess, extensionPath: string): TerminateResponse { + if (process.platform === 'win32') { + try { + const options: any = { + stdio: ['pipe', 'pipe', 'ignore'] + }; + cp.execFileSync('taskkill', ['/T', '/F', '/PID', p.pid.toString()], options); + } catch (err) { + return { success: false, error: err }; + } + } else if (process.platform === 'darwin' || process.platform === 'linux') { + try { + const cmd = path.join(extensionPath, 'scripts', 'terminateProcess.sh'); + const result = cp.spawnSync(cmd, [process.pid.toString()]); + if (result.error) { + return { success: false, error: result.error }; + } + } catch (err) { + return { success: false, error: err }; + } + } else { + p.kill('SIGKILL'); + } + return { success: true }; +} \ No newline at end of file diff --git a/extensions/vscode-test-resolver/tsconfig.json b/extensions/vscode-test-resolver/tsconfig.json new file mode 100644 index 000000000..296ddb38f --- /dev/null +++ b/extensions/vscode-test-resolver/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../shared.tsconfig.json", + "compilerOptions": { + "outDir": "./out" + }, + "include": [ + "src/**/*" + ] +} \ No newline at end of file diff --git a/extensions/vscode-test-resolver/yarn.lock b/extensions/vscode-test-resolver/yarn.lock new file mode 100644 index 000000000..925cef2c1 --- /dev/null +++ b/extensions/vscode-test-resolver/yarn.lock @@ -0,0 +1,1879 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@types/node@^10.14.8": + version "10.14.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9" + integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw== + +ajv@^6.5.5: + version "6.10.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.0.tgz#90d0d54439da587cd7e843bfb7045f50bd22bdf1" + integrity sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg== + dependencies: + fast-deep-equal "^2.0.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-cyan@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-cyan/-/ansi-cyan-0.1.1.tgz#538ae528af8982f28ae30d86f2f17456d2609873" + integrity sha1-U4rlKK+JgvKK4w2G8vF0VtJgmHM= + dependencies: + ansi-wrap "0.1.0" + +ansi-gray@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-gray/-/ansi-gray-0.1.1.tgz#2962cf54ec9792c48510a3deb524436861ef7251" + integrity sha1-KWLPVOyXksSFEKPetSRDaGHvclE= + dependencies: + ansi-wrap "0.1.0" + +ansi-red@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-red/-/ansi-red-0.1.1.tgz#8c638f9d1080800a353c9c28c8a81ca4705d946c" + integrity sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw= + dependencies: + ansi-wrap "0.1.0" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= + +ansi-wrap@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" + integrity sha1-qCJQ3bABXponyoLoLqYDu/pF768= + +arr-diff@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-1.1.0.tgz#687c32758163588fef7de7b36fabe495eb1a399a" + integrity sha1-aHwydYFjWI/vfeezb6vklesaOZo= + dependencies: + arr-flatten "^1.0.1" + array-slice "^0.2.3" + +arr-diff@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + integrity sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8= + dependencies: + arr-flatten "^1.0.1" + +arr-flatten@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== + +arr-union@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-2.1.0.tgz#20f9eab5ec70f5c7d215b1077b1c39161d292c7d" + integrity sha1-IPnqtexw9cfSFbEHexw5Fh0pLH0= + +array-differ@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031" + integrity sha1-7/UuN1gknTO+QCuLuOVkuytdQDE= + +array-slice@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-0.2.3.tgz#dd3cfb80ed7973a75117cdac69b0b99ec86186f5" + integrity sha1-3Tz7gO15c6dRF82sabC5nshhhvU= + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1, array-uniq@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= + +array-unique@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + integrity sha1-odl8yvy8JiXMcPrc6zalDFiwGlM= + +arrify@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= + +asn1@~0.2.3: + version "0.2.4" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== + dependencies: + safer-buffer "~2.1.0" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= + +aws4@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" + integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= + dependencies: + tweetnacl "^0.14.3" + +beeper@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/beeper/-/beeper-1.1.1.tgz#e6d5ea8c5dad001304a70b22638447f69cb2f809" + integrity sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak= + +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo= + dependencies: + inherits "~2.0.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^1.8.2: + version "1.8.5" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + integrity sha1-uneWLhLf+WnWt2cR6RS3N4V79qc= + dependencies: + expand-range "^1.8.1" + preserve "^0.2.0" + repeat-element "^1.1.2" + +browser-stdout@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.0.tgz#f351d32969d32fa5d7a5567154263d928ae3bd1f" + integrity sha1-81HTKWnTL6XXpVZxVCY9korjvR8= + +buffer-crc32@~0.2.3: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= + +chalk@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +clone-buffer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58" + integrity sha1-4+JbIHrE5wGvch4staFnksrD3Fg= + +clone-stats@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-0.0.1.tgz#b88f94a82cf38b8791d58046ea4029ad88ca99d1" + integrity sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE= + +clone-stats@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680" + integrity sha1-s3gt/4u1R04Yuba/D9/ngvh3doA= + +clone@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/clone/-/clone-0.2.0.tgz#c6126a90ad4f72dbf5acdb243cc37724fe93fc1f" + integrity sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8= + +clone@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= + +cloneable-readable@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/cloneable-readable/-/cloneable-readable-1.1.2.tgz#d591dee4a8f8bc15da43ce97dceeba13d43e2a65" + integrity sha512-Bq6+4t+lbM8vhTs/Bef5c5AdEMtapp/iFb6+s4/Hh9MVTt8OLKH7ZOOZSCT+Ys7hsHvqv0GuMPJ1lnQJVHvxpg== + dependencies: + inherits "^2.0.1" + process-nextick-args "^2.0.0" + readable-stream "^2.3.5" + +color-support@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" + integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== + +combined-stream@^1.0.6, combined-stream@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.7.tgz#2d1d24317afb8abe95d6d2c0b07b57813539d828" + integrity sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w== + dependencies: + delayed-stream "~1.0.0" + +commander@2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" + integrity sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q= + dependencies: + graceful-readlink ">= 1.0.0" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +convert-source-map@^1.1.1: + version "1.6.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20" + integrity sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A== + dependencies: + safe-buffer "~5.1.1" + +core-util-is@1.0.2, core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= + dependencies: + assert-plus "^1.0.0" + +dateformat@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-2.2.0.tgz#4065e2013cf9fb916ddfd82efb506ad4c6769062" + integrity sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI= + +debug@2.6.8: + version "2.6.8" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" + integrity sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw= + dependencies: + ms "2.0.0" + +deep-assign@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/deep-assign/-/deep-assign-1.0.0.tgz#b092743be8427dc621ea0067cdec7e70dd19f37b" + integrity sha1-sJJ0O+hCfcYh6gBnzex+cN0Z83s= + dependencies: + is-obj "^1.0.0" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + +diff@3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9" + integrity sha1-yc45Okt8vQsFinJck98pkCeGj/k= + +duplexer2@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.0.2.tgz#c614dcf67e2fb14995a91711e5a617e8a60a31db" + integrity sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds= + dependencies: + readable-stream "~1.1.9" + +duplexer@^0.1.1, duplexer@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" + integrity sha1-rOb/gIwc5mtX0ev5eXessCM0z8E= + +duplexify@^3.2.0: + version "3.7.1" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" + integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== + dependencies: + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +end-of-stream@^1.0.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" + integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q== + dependencies: + once "^1.4.0" + +escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +event-stream@3.3.4: + version "3.3.4" + resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" + integrity sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE= + dependencies: + duplexer "~0.1.1" + from "~0" + map-stream "~0.1.0" + pause-stream "0.0.11" + split "0.3" + stream-combiner "~0.0.4" + through "~2.3.1" + +event-stream@^3.3.1, event-stream@~3.3.4: + version "3.3.5" + resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.5.tgz#e5dd8989543630d94c6cf4d657120341fa31636b" + integrity sha512-vyibDcu5JL20Me1fP734QBH/kenBGLZap2n0+XXM7mvuUPzJ20Ydqj1aKcIeMdri1p+PU+4yAKugjN8KCVst+g== + dependencies: + duplexer "^0.1.1" + from "^0.1.7" + map-stream "0.0.7" + pause-stream "^0.0.11" + split "^1.0.1" + stream-combiner "^0.2.2" + through "^2.3.8" + +expand-brackets@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + integrity sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s= + dependencies: + is-posix-bracket "^0.1.0" + +expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + integrity sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc= + dependencies: + fill-range "^2.1.0" + +extend-shallow@^1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-1.1.4.tgz#19d6bf94dfc09d76ba711f39b872d21ff4dd9071" + integrity sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE= + dependencies: + kind-of "^1.1.0" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + dependencies: + is-extendable "^0.1.0" + +extend@^3.0.0, extend@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + integrity sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE= + dependencies: + is-extglob "^1.0.0" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= + +fancy-log@^1.1.0: + version "1.3.3" + resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.3.tgz#dbc19154f558690150a23953a0adbd035be45fc7" + integrity sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw== + dependencies: + ansi-gray "^0.1.1" + color-support "^1.1.3" + parse-node-version "^1.0.0" + time-stamp "^1.0.0" + +fast-deep-equal@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" + integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= + +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= + +fd-slicer@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" + integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4= + dependencies: + pend "~1.2.0" + +filename-regex@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" + integrity sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY= + +fill-range@^2.1.0: + version "2.2.4" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" + integrity sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q== + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^3.0.0" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + +first-chunk-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz#59bfb50cd905f60d7c394cd3d9acaab4e6ad934e" + integrity sha1-Wb+1DNkF9g18OUzT2ayqtOatk04= + +for-in@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= + +for-own@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" + integrity sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4= + dependencies: + for-in "^1.0.1" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= + +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +from@^0.1.7, from@~0: + version "0.1.7" + resolved "https://registry.yarnpkg.com/from/-/from-0.1.7.tgz#83c60afc58b9c56997007ed1a768b3ab303a44fe" + integrity sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4= + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fstream@^1.0.2: + version "1.0.11" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" + integrity sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE= + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= + dependencies: + assert-plus "^1.0.0" + +glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + integrity sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q= + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + +glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + integrity sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg= + dependencies: + is-glob "^2.0.0" + +glob-parent@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob-stream@^5.3.2: + version "5.3.5" + resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-5.3.5.tgz#a55665a9a8ccdc41915a87c701e32d4e016fad22" + integrity sha1-pVZlqajM3EGRWofHAeMtTgFvrSI= + dependencies: + extend "^3.0.0" + glob "^5.0.3" + glob-parent "^3.0.0" + micromatch "^2.3.7" + ordered-read-streams "^0.3.0" + through2 "^0.6.0" + to-absolute-glob "^0.1.1" + unique-stream "^2.0.2" + +glob@7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" + integrity sha1-gFIR3wT6rxxjo2ADBs31reULLsg= + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.2" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^5.0.3: + version "5.0.15" + resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" + integrity sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E= + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.1.1, glob@^7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" + integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glogg@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/glogg/-/glogg-1.0.2.tgz#2d7dd702beda22eb3bffadf880696da6d846313f" + integrity sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA== + dependencies: + sparkles "^1.0.0" + +graceful-fs@^4.0.0, graceful-fs@^4.1.2: + version "4.1.15" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" + integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== + +"graceful-readlink@>= 1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU= + +growl@1.9.2: + version "1.9.2" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f" + integrity sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8= + +gulp-chmod@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/gulp-chmod/-/gulp-chmod-2.0.0.tgz#00c390b928a0799b251accf631aa09e01cc6299c" + integrity sha1-AMOQuSigeZslGsz2MaoJ4BzGKZw= + dependencies: + deep-assign "^1.0.0" + stat-mode "^0.2.0" + through2 "^2.0.0" + +gulp-filter@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/gulp-filter/-/gulp-filter-5.1.0.tgz#a05e11affb07cf7dcf41a7de1cb7b63ac3783e73" + integrity sha1-oF4Rr/sHz33PQafeHLe2OsN4PnM= + dependencies: + multimatch "^2.0.0" + plugin-error "^0.1.2" + streamfilter "^1.0.5" + +gulp-gunzip@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/gulp-gunzip/-/gulp-gunzip-0.0.3.tgz#7b6e07b0f58fd3d42515c48ead5a63df0572f62f" + integrity sha1-e24HsPWP09QlFcSOrVpj3wVy9i8= + dependencies: + through2 "~0.6.5" + vinyl "~0.4.6" + +gulp-remote-src@^0.4.2: + version "0.4.4" + resolved "https://registry.yarnpkg.com/gulp-remote-src/-/gulp-remote-src-0.4.4.tgz#4a4d18fac0ffedde94a7855953de90db00a1d1b1" + integrity sha512-mo7lGgZmNXyTbcUzfjSnUVkx1pnqqiwv/pPaIrYdTO77hq0WNTxXLAzQdoYOnyJ0mfVLNmNl9AGqWLiAzTPMMA== + dependencies: + event-stream "3.3.4" + node.extend "~1.1.2" + request "^2.88.0" + through2 "~2.0.3" + vinyl "~2.0.1" + +gulp-sourcemaps@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/gulp-sourcemaps/-/gulp-sourcemaps-1.6.0.tgz#b86ff349d801ceb56e1d9e7dc7bbcb4b7dee600c" + integrity sha1-uG/zSdgBzrVuHZ59x7vLS33uYAw= + dependencies: + convert-source-map "^1.1.1" + graceful-fs "^4.1.2" + strip-bom "^2.0.0" + through2 "^2.0.0" + vinyl "^1.0.0" + +gulp-symdest@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/gulp-symdest/-/gulp-symdest-1.1.1.tgz#b0a6df3d43a0537165946ab8e38c1b7080a66fac" + integrity sha512-UHd3MokfIN7SrFdsbV5uZTwzBpL0ZSTu7iq98fuDqBGZ0dlHxgbQBJwfd6qjCW83snkQ3Hz9IY4sMRMz2iTq7w== + dependencies: + event-stream "3.3.4" + mkdirp "^0.5.1" + queue "^3.1.0" + vinyl-fs "^2.4.3" + +gulp-untar@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/gulp-untar/-/gulp-untar-0.0.6.tgz#d6bdefde7e9a8e054c9f162385a0782c4be74000" + integrity sha1-1r3v3n6ajgVMnxYjhaB4LEvnQAA= + dependencies: + event-stream "~3.3.4" + gulp-util "~3.0.8" + streamifier "~0.1.1" + tar "^2.2.1" + through2 "~2.0.3" + +gulp-util@~3.0.8: + version "3.0.8" + resolved "https://registry.yarnpkg.com/gulp-util/-/gulp-util-3.0.8.tgz#0054e1e744502e27c04c187c3ecc505dd54bbb4f" + integrity sha1-AFTh50RQLifATBh8PsxQXdVLu08= + dependencies: + array-differ "^1.0.0" + array-uniq "^1.0.2" + beeper "^1.0.0" + chalk "^1.0.0" + dateformat "^2.0.0" + fancy-log "^1.1.0" + gulplog "^1.0.0" + has-gulplog "^0.1.0" + lodash._reescape "^3.0.0" + lodash._reevaluate "^3.0.0" + lodash._reinterpolate "^3.0.0" + lodash.template "^3.0.0" + minimist "^1.1.0" + multipipe "^0.1.2" + object-assign "^3.0.0" + replace-ext "0.0.1" + through2 "^2.0.0" + vinyl "^0.5.0" + +gulp-vinyl-zip@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/gulp-vinyl-zip/-/gulp-vinyl-zip-1.4.0.tgz#56382f2ccb57231bb0478c78737ccd572973bee1" + integrity sha1-VjgvLMtXIxuwR4x4c3zNVylzvuE= + dependencies: + event-stream "^3.3.1" + queue "^3.0.10" + through2 "^0.6.3" + vinyl "^0.4.6" + vinyl-fs "^2.0.0" + yauzl "^2.2.1" + yazl "^2.2.1" + +gulplog@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/gulplog/-/gulplog-1.0.0.tgz#e28c4d45d05ecbbed818363ce8f9c5926229ffe5" + integrity sha1-4oxNRdBey77YGDY86PnFkmIp/+U= + dependencies: + glogg "^1.0.0" + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= + +har-validator@~5.1.0: + version "5.1.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" + integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== + dependencies: + ajv "^6.5.5" + har-schema "^2.0.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= + dependencies: + ansi-regex "^2.0.0" + +has-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" + integrity sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo= + +has-gulplog@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/has-gulplog/-/has-gulplog-0.1.0.tgz#6414c82913697da51590397dafb12f22967811ce" + integrity sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4= + dependencies: + sparkles "^1.0.0" + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +he@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" + integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0= + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +is-dotfile@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" + integrity sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE= + +is-equal-shallow@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + integrity sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ= + dependencies: + is-primitive "^2.0.0" + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= + +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA= + +is-extglob@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-glob@^2.0.0, is-glob@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + integrity sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM= + dependencies: + is-extglob "^1.0.0" + +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= + dependencies: + is-extglob "^2.1.0" + +is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + integrity sha1-Afy7s5NGOlSPL0ZszhbezknbkI8= + dependencies: + kind-of "^3.0.2" + +is-number@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" + integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ== + +is-obj@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= + +is-posix-bracket@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + integrity sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q= + +is-primitive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + integrity sha1-IHurkWOEmcB7Kt8kCkGochADRXU= + +is-stream@^1.0.1, is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= + +is-valid-glob@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/is-valid-glob/-/is-valid-glob-0.3.0.tgz#d4b55c69f51886f9b65c70d6c2622d37e29f48fe" + integrity sha1-1LVcafUYhvm2XHDWwmItN+KfSP4= + +is@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/is/-/is-3.3.0.tgz#61cff6dd3c4193db94a3d62582072b44e5645d79" + integrity sha512-nW24QBoPcFGGHJGUwnfpI7Yc5CdqWNdsyHQszVE/z2pKHXzh7FZ5GWhJqSyaQ9wMkQnsTx+kAI8bHlCX4tKdbg== + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= + +isarray@1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= + dependencies: + isarray "1.0.0" + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= + +json3@3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" + integrity sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE= + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +kind-of@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-1.1.0.tgz#140a3d2d41a36d2efcfa9377b62c24f8495a5c44" + integrity sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ= + +kind-of@^3.0.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= + dependencies: + is-buffer "^1.1.5" + +kind-of@^6.0.0: + version "6.0.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== + +lazystream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4" + integrity sha1-9plf4PggOS9hOWvolGJAe7dxaOQ= + dependencies: + readable-stream "^2.0.5" + +lodash._baseassign@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" + integrity sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4= + dependencies: + lodash._basecopy "^3.0.0" + lodash.keys "^3.0.0" + +lodash._basecopy@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" + integrity sha1-jaDmqHbPNEwK2KVIghEd08XHyjY= + +lodash._basecreate@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz#1bc661614daa7fc311b7d03bf16806a0213cf821" + integrity sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE= + +lodash._basetostring@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz#d1861d877f824a52f669832dcaf3ee15566a07d5" + integrity sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U= + +lodash._basevalues@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz#5b775762802bde3d3297503e26300820fdf661b7" + integrity sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc= + +lodash._getnative@^3.0.0: + version "3.9.1" + resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" + integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U= + +lodash._isiterateecall@^3.0.0: + version "3.0.9" + resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" + integrity sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw= + +lodash._reescape@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._reescape/-/lodash._reescape-3.0.0.tgz#2b1d6f5dfe07c8a355753e5f27fac7f1cde1616a" + integrity sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo= + +lodash._reevaluate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz#58bc74c40664953ae0b124d806996daca431e2ed" + integrity sha1-WLx0xAZklTrgsSTYBpltrKQx4u0= + +lodash._reinterpolate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" + integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= + +lodash._root@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" + integrity sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI= + +lodash.create@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lodash.create/-/lodash.create-3.1.1.tgz#d7f2849f0dbda7e04682bb8cd72ab022461debe7" + integrity sha1-1/KEnw29p+BGgruM1yqwIkYd6+c= + dependencies: + lodash._baseassign "^3.0.0" + lodash._basecreate "^3.0.0" + lodash._isiterateecall "^3.0.0" + +lodash.escape@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-3.2.0.tgz#995ee0dc18c1b48cc92effae71a10aab5b487698" + integrity sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg= + dependencies: + lodash._root "^3.0.0" + +lodash.isarguments@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo= + +lodash.isarray@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" + integrity sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U= + +lodash.isequal@^4.0.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= + +lodash.keys@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" + integrity sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo= + dependencies: + lodash._getnative "^3.0.0" + lodash.isarguments "^3.0.0" + lodash.isarray "^3.0.0" + +lodash.restparam@^3.0.0: + version "3.6.1" + resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" + integrity sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU= + +lodash.template@^3.0.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-3.6.2.tgz#f8cdecc6169a255be9098ae8b0c53d378931d14f" + integrity sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8= + dependencies: + lodash._basecopy "^3.0.0" + lodash._basetostring "^3.0.0" + lodash._basevalues "^3.0.0" + lodash._isiterateecall "^3.0.0" + lodash._reinterpolate "^3.0.0" + lodash.escape "^3.0.0" + lodash.keys "^3.0.0" + lodash.restparam "^3.0.0" + lodash.templatesettings "^3.0.0" + +lodash.templatesettings@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz#fb307844753b66b9f1afa54e262c745307dba8e5" + integrity sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU= + dependencies: + lodash._reinterpolate "^3.0.0" + lodash.escape "^3.0.0" + +map-stream@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.0.7.tgz#8a1f07896d82b10926bd3744a2420009f88974a8" + integrity sha1-ih8HiW2CsQkmvTdEokIACfiJdKg= + +map-stream@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194" + integrity sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ= + +math-random@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.4.tgz#5dd6943c938548267016d4e34f057583080c514c" + integrity sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A== + +merge-stream@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1" + integrity sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE= + dependencies: + readable-stream "^2.0.1" + +micromatch@^2.3.7: + version "2.3.11" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + integrity sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU= + dependencies: + arr-diff "^2.0.0" + array-unique "^0.2.1" + braces "^1.8.2" + expand-brackets "^0.1.4" + extglob "^0.3.1" + filename-regex "^2.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.1" + kind-of "^3.0.2" + normalize-path "^2.0.1" + object.omit "^2.0.0" + parse-glob "^3.0.4" + regex-cache "^0.4.2" + +mime-db@~1.38.0: + version "1.38.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.38.0.tgz#1a2aab16da9eb167b49c6e4df2d9c68d63d8e2ad" + integrity sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg== + +mime-types@^2.1.12, mime-types@~2.1.19: + version "2.1.22" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.22.tgz#fe6b355a190926ab7698c9a0556a11199b2199bd" + integrity sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog== + dependencies: + mime-db "~1.38.0" + +"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= + +minimist@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= + +mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= + dependencies: + minimist "0.0.8" + +mocha@^3.2.0: + version "3.5.3" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-3.5.3.tgz#1e0480fe36d2da5858d1eb6acc38418b26eaa20d" + integrity sha512-/6na001MJWEtYxHOV1WLfsmR4YIynkUEhBwzsb+fk2qmQ3iqsi258l/Q2MWHJMImAcNpZ8DEdYAK72NHoIQ9Eg== + dependencies: + browser-stdout "1.3.0" + commander "2.9.0" + debug "2.6.8" + diff "3.2.0" + escape-string-regexp "1.0.5" + glob "7.1.1" + growl "1.9.2" + he "1.1.1" + json3 "3.3.2" + lodash.create "3.1.1" + mkdirp "0.5.1" + supports-color "3.1.2" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +multimatch@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-2.1.0.tgz#9c7906a22fb4c02919e2f5f75161b4cdbd4b2a2b" + integrity sha1-nHkGoi+0wCkZ4vX3UWG0zb1LKis= + dependencies: + array-differ "^1.0.0" + array-union "^1.0.1" + arrify "^1.0.0" + minimatch "^3.0.0" + +multipipe@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-0.1.2.tgz#2a8f2ddf70eed564dff2d57f1e1a137d9f05078b" + integrity sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s= + dependencies: + duplexer2 "0.0.2" + +node.extend@~1.1.2: + version "1.1.8" + resolved "https://registry.yarnpkg.com/node.extend/-/node.extend-1.1.8.tgz#0aab3e63789f4e6d68b42bc00073ad1881243cf0" + integrity sha512-L/dvEBwyg3UowwqOUTyDsGBU6kjBQOpOhshio9V3i3BMPv5YUb9+mWNN8MK0IbWqT0AqaTSONZf0aTuMMahWgA== + dependencies: + has "^1.0.3" + is "^3.2.1" + +normalize-path@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= + dependencies: + remove-trailing-separator "^1.0.1" + +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== + +object-assign@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2" + integrity sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I= + +object-assign@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +object.omit@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + integrity sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo= + dependencies: + for-own "^0.1.4" + is-extendable "^0.1.1" + +once@^1.3.0, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +ordered-read-streams@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-0.3.0.tgz#7137e69b3298bb342247a1bbee3881c80e2fd78b" + integrity sha1-cTfmmzKYuzQiR6G77jiByA4v14s= + dependencies: + is-stream "^1.0.1" + readable-stream "^2.0.1" + +parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + integrity sha1-ssN2z7EfNVE7rdFz7wu246OIORw= + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + +parse-node-version@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parse-node-version/-/parse-node-version-1.0.1.tgz#e2b5dbede00e7fa9bc363607f53327e8b073189b" + integrity sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA== + +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +pause-stream@0.0.11, pause-stream@^0.0.11: + version "0.0.11" + resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445" + integrity sha1-/lo0sMvOErWqaitAPuLnO2AvFEU= + dependencies: + through "~2.3" + +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= + +plugin-error@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/plugin-error/-/plugin-error-0.1.2.tgz#3b9bb3335ccf00f425e07437e19276967da47ace" + integrity sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4= + dependencies: + ansi-cyan "^0.1.1" + ansi-red "^0.1.1" + arr-diff "^1.0.1" + arr-union "^2.0.1" + extend-shallow "^1.1.2" + +preserve@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks= + +process-nextick-args@^2.0.0, process-nextick-args@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== + +psl@^1.1.24: + version "1.1.31" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.31.tgz#e9aa86d0101b5b105cbe93ac6b784cd547276184" + integrity sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw== + +punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +qs@~6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== + +querystringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.0.tgz#7ded8dfbf7879dcc60d0a644ac6754b283ad17ef" + integrity sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg== + +queue@^3.0.10, queue@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/queue/-/queue-3.1.0.tgz#6c49d01f009e2256788789f2bffac6b8b9990585" + integrity sha1-bEnQHwCeIlZ4h4nyv/rGuLmZBYU= + dependencies: + inherits "~2.0.0" + +randomatic@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed" + integrity sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw== + dependencies: + is-number "^4.0.0" + kind-of "^6.0.0" + math-random "^1.0.1" + +"readable-stream@>=1.0.33-1 <1.1.0-0": + version "1.0.34" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + integrity sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw= + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.3.5, readable-stream@~2.3.6: + version "2.3.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@~1.1.9: + version "1.1.14" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +regex-cache@^0.4.2: + version "0.4.4" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.4.tgz#75bdc58a2a1496cec48a12835bc54c8d562336dd" + integrity sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ== + dependencies: + is-equal-shallow "^0.1.3" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= + +repeat-element@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" + integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== + +repeat-string@^1.5.2: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + +replace-ext@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924" + integrity sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ= + +replace-ext@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb" + integrity sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs= + +request@^2.79.0, request@^2.88.0: + version "2.88.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" + integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.0" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.4.3" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= + +rimraf@2: + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== + dependencies: + glob "^7.1.3" + +safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +semver@^5.3.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" + integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== + +source-map-support@^0.4.11: + version "0.4.18" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" + integrity sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA== + dependencies: + source-map "^0.5.6" + +source-map@^0.5.6: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +sparkles@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.1.tgz#008db65edce6c50eec0c5e228e1945061dd0437c" + integrity sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw== + +split@0.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/split/-/split-0.3.3.tgz#cd0eea5e63a211dfff7eb0f091c4133e2d0dd28f" + integrity sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8= + dependencies: + through "2" + +split@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" + integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg== + dependencies: + through "2" + +sshpk@^1.7.0: + version "1.16.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" + integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + +stat-mode@^0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/stat-mode/-/stat-mode-0.2.2.tgz#e6c80b623123d7d80cf132ce538f346289072502" + integrity sha1-5sgLYjEj19gM8TLOU480YokHJQI= + +stream-combiner@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.2.2.tgz#aec8cbac177b56b6f4fa479ced8c1912cee52858" + integrity sha1-rsjLrBd7Vrb0+kec7YwZEs7lKFg= + dependencies: + duplexer "~0.1.1" + through "~2.3.4" + +stream-combiner@~0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.0.4.tgz#4d5e433c185261dde623ca3f44c586bcf5c4ad14" + integrity sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ= + dependencies: + duplexer "~0.1.1" + +stream-shift@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" + integrity sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI= + +streamfilter@^1.0.5: + version "1.0.7" + resolved "https://registry.yarnpkg.com/streamfilter/-/streamfilter-1.0.7.tgz#ae3e64522aa5a35c061fd17f67620c7653c643c9" + integrity sha512-Gk6KZM+yNA1JpW0KzlZIhjo3EaBJDkYfXtYSbOwNIQ7Zd6006E6+sCFlW1NDvFG/vnXhKmw6TJJgiEQg/8lXfQ== + dependencies: + readable-stream "^2.0.2" + +streamifier@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/streamifier/-/streamifier-0.1.1.tgz#97e98d8fa4d105d62a2691d1dc07e820db8dfc4f" + integrity sha1-l+mNj6TRBdYqJpHR3AfoINuN/E8= + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-bom-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-bom-stream/-/strip-bom-stream-1.0.0.tgz#e7144398577d51a6bed0fa1994fa05f43fd988ee" + integrity sha1-5xRDmFd9Uaa+0PoZlPoF9D/ZiO4= + dependencies: + first-chunk-stream "^1.0.0" + strip-bom "^2.0.0" + +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= + dependencies: + is-utf8 "^0.2.0" + +supports-color@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.1.2.tgz#72a262894d9d408b956ca05ff37b2ed8a6e2a2d5" + integrity sha1-cqJiiU2dQIuVbKBf83su2KbiotU= + dependencies: + has-flag "^1.0.0" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= + +tar@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + integrity sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE= + dependencies: + block-stream "*" + fstream "^1.0.2" + inherits "2" + +through2-filter@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-2.0.0.tgz#60bc55a0dacb76085db1f9dae99ab43f83d622ec" + integrity sha1-YLxVoNrLdghdsfna6Zq0P4PWIuw= + dependencies: + through2 "~2.0.0" + xtend "~4.0.0" + +through2-filter@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-3.0.0.tgz#700e786df2367c2c88cd8aa5be4cf9c1e7831254" + integrity sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA== + dependencies: + through2 "~2.0.0" + xtend "~4.0.0" + +through2@^0.6.0, through2@^0.6.3, through2@~0.6.5: + version "0.6.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48" + integrity sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg= + dependencies: + readable-stream ">=1.0.33-1 <1.1.0-0" + xtend ">=4.0.0 <4.1.0-0" + +through2@^2.0.0, through2@^2.0.3, through2@~2.0.0, through2@~2.0.3: + version "2.0.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + +through@2, through@^2.3.8, through@~2.3, through@~2.3.1, through@~2.3.4: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + +time-stamp@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3" + integrity sha1-dkpaEa9QVhkhsTPztE5hhofg9cM= + +to-absolute-glob@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/to-absolute-glob/-/to-absolute-glob-0.1.1.tgz#1cdfa472a9ef50c239ee66999b662ca0eb39937f" + integrity sha1-HN+kcqnvUMI57maZm2YsoOs5k38= + dependencies: + extend-shallow "^2.0.1" + +tough-cookie@~2.4.3: + version "2.4.3" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" + integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ== + dependencies: + psl "^1.1.24" + punycode "^1.4.1" + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= + +unique-stream@^2.0.2: + version "2.3.1" + resolved "https://registry.yarnpkg.com/unique-stream/-/unique-stream-2.3.1.tgz#c65d110e9a4adf9a6c5948b28053d9a8d04cbeac" + integrity sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A== + dependencies: + json-stable-stringify-without-jsonify "^1.0.1" + through2-filter "^3.0.0" + +uri-js@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + dependencies: + punycode "^2.1.0" + +url-parse@^1.1.9: + version "1.4.4" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.4.tgz#cac1556e95faa0303691fec5cf9d5a1bc34648f8" + integrity sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg== + dependencies: + querystringify "^2.0.0" + requires-port "^1.0.0" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +uuid@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" + integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== + +vali-date@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/vali-date/-/vali-date-1.0.0.tgz#1b904a59609fb328ef078138420934f6b86709a6" + integrity sha1-G5BKWWCfsyjvB4E4Qgk09rhnCaY= + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +vinyl-fs@^2.0.0, vinyl-fs@^2.4.3: + version "2.4.4" + resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-2.4.4.tgz#be6ff3270cb55dfd7d3063640de81f25d7532239" + integrity sha1-vm/zJwy1Xf19MGNkDegfJddTIjk= + dependencies: + duplexify "^3.2.0" + glob-stream "^5.3.2" + graceful-fs "^4.0.0" + gulp-sourcemaps "1.6.0" + is-valid-glob "^0.3.0" + lazystream "^1.0.0" + lodash.isequal "^4.0.0" + merge-stream "^1.0.0" + mkdirp "^0.5.0" + object-assign "^4.0.0" + readable-stream "^2.0.4" + strip-bom "^2.0.0" + strip-bom-stream "^1.0.0" + through2 "^2.0.0" + through2-filter "^2.0.0" + vali-date "^1.0.0" + vinyl "^1.0.0" + +vinyl-source-stream@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vinyl-source-stream/-/vinyl-source-stream-1.1.2.tgz#62b53a135610a896e98ca96bee3a87f008a8e780" + integrity sha1-YrU6E1YQqJbpjKlr7jqH8Aio54A= + dependencies: + through2 "^2.0.3" + vinyl "^0.4.3" + +vinyl@^0.4.3, vinyl@^0.4.6, vinyl@~0.4.6: + version "0.4.6" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.4.6.tgz#2f356c87a550a255461f36bbeb2a5ba8bf784847" + integrity sha1-LzVsh6VQolVGHza76ypbqL94SEc= + dependencies: + clone "^0.2.0" + clone-stats "^0.0.1" + +vinyl@^0.5.0: + version "0.5.3" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.5.3.tgz#b0455b38fc5e0cf30d4325132e461970c2091cde" + integrity sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4= + dependencies: + clone "^1.0.0" + clone-stats "^0.0.1" + replace-ext "0.0.1" + +vinyl@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-1.2.0.tgz#5c88036cf565e5df05558bfc911f8656df218884" + integrity sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ= + dependencies: + clone "^1.0.0" + clone-stats "^0.0.1" + replace-ext "0.0.1" + +vinyl@~2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.0.2.tgz#0a3713d8d4e9221c58f10ca16c0116c9e25eda7c" + integrity sha1-CjcT2NTpIhxY8QyhbAEWyeJe2nw= + dependencies: + clone "^1.0.0" + clone-buffer "^1.0.0" + clone-stats "^1.0.0" + cloneable-readable "^1.0.0" + is-stream "^1.1.0" + remove-trailing-separator "^1.0.1" + replace-ext "^1.0.0" + +vscode@1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/vscode/-/vscode-1.1.5.tgz#10eb104001840c3dd0813815fd4a05f8fc882d14" + integrity sha1-EOsQQAGEDD3QgTgV/UoF+PyILRQ= + dependencies: + glob "^7.1.1" + gulp-chmod "^2.0.0" + gulp-filter "^5.0.0" + gulp-gunzip "0.0.3" + gulp-remote-src "^0.4.2" + gulp-symdest "^1.1.0" + gulp-untar "^0.0.6" + gulp-vinyl-zip "^1.4.0" + mocha "^3.2.0" + request "^2.79.0" + semver "^5.3.0" + source-map-support "^0.4.11" + url-parse "^1.1.9" + vinyl-source-stream "^1.1.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +"xtend@>=4.0.0 <4.1.0-0", xtend@~4.0.0, xtend@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= + +yauzl@^2.2.1: + version "2.10.0" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" + integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk= + dependencies: + buffer-crc32 "~0.2.3" + fd-slicer "~1.1.0" + +yazl@^2.2.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/yazl/-/yazl-2.5.1.tgz#a3d65d3dd659a5b0937850e8609f22fffa2b5c35" + integrity sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw== + dependencies: + buffer-crc32 "~0.2.3" diff --git a/extensions/xml/package.json b/extensions/xml/package.json index 985266edf..d76a632b1 100644 --- a/extensions/xml/package.json +++ b/extensions/xml/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "*" }, "contributes": { "languages": [{ @@ -22,6 +23,8 @@ ".dita", ".ditamap", ".dtd", + ".ent", + ".mod", ".dtml", ".fsproj", ".fxml", diff --git a/extensions/xml/xml.language-configuration.json b/extensions/xml/xml.language-configuration.json index faaa59c1c..702b6dc6e 100644 --- a/extensions/xml/xml.language-configuration.json +++ b/extensions/xml/xml.language-configuration.json @@ -1,31 +1,34 @@ { "comments": { - "lineComment": "", - "blockComment": [""] + "blockComment": [ "" ] }, "brackets": [ - ["<", ">"] + [""], + ["<", ">"], + ["{", "}"], + ["(", ")"] ], "autoClosingPairs": [ - ["<", ">"], - ["'", "'"], - ["\"", "\""] + { "open": "{", "close": "}"}, + { "open": "[", "close": "]"}, + { "open": "(", "close": ")" }, + { "open": "'", "close": "'" }, + { "open": "\"", "close": "\"" }, + { "open": "", "notIn": [ "comment", "string" ]}, + { "open": "", "close": "", "notIn": [ "comment", "string" ]} ], "surroundingPairs": [ - ["<", ">"], - ["'", "'"], - ["\"", "\""] - ] - - // enhancedBrackets: [{ - // tokenType: 'tag.tag-$1.xml', - // openTrigger: '>', - // open: /<(\w[\w\d]*)([^\/>]*(?!\/)>)[^<>]*$/i, - // closeComplete: '', - // closeTrigger: '>', - // close: /<\/(\w[\w\d]*)\s*>$/i - // }], - - // autoClosingPairs: [['\'', '\''], ['"', '"'] ] - + { "open": "'", "close": "'" }, + { "open": "\"", "close": "\"" }, + { "open": "{", "close": "}"}, + { "open": "[", "close": "]"}, + { "open": "(", "close": ")" }, + { "open": "<", "close": ">" } + ], + "folding": { + "markers": { + "start": "^\\s*", + "end": "^\\s*" + } + } } diff --git a/extensions/yaml/.gitignore b/extensions/yaml/.gitignore deleted file mode 100644 index 3c3629e64..000000000 --- a/extensions/yaml/.gitignore +++ /dev/null @@ -1 +0,0 @@ -node_modules diff --git a/extensions/yaml/package.json b/extensions/yaml/package.json index 79e2eecc3..5b12e0fbc 100644 --- a/extensions/yaml/package.json +++ b/extensions/yaml/package.json @@ -4,6 +4,7 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", + "license": "MIT", "engines": { "vscode": "*" }, diff --git a/extensions/yarn.lock b/extensions/yarn.lock index 149346bbb..8e552194c 100644 --- a/extensions/yarn.lock +++ b/extensions/yarn.lock @@ -2,7 +2,7 @@ # yarn lockfile v1 -typescript@3.4.5: - version "3.4.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.5.tgz#2d2618d10bb566572b8d7aad5180d84257d70a99" - integrity sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw== +typescript@3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.2.tgz#a09e1dc69bc9551cadf17dba10ee42cf55e5d56c" + integrity sha512-7KxJovlYhTX5RaRbUdkAXN1KUZ8PwWlTzQdHV6xNqvuFOs7+WBo10TQUqT19Q/Jz2hk5v9TQDIhyLhhJY4p5AA== diff --git a/gulpfile.js b/gulpfile.js index 1d13cff60..8a5eff502 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -40,4 +40,4 @@ process.on('unhandledRejection', (reason, p) => { // Load all the gulpfiles only if running tasks other than the editor tasks const build = path.join(__dirname, 'build'); require('glob').sync('gulpfile.*.js', { cwd: build }) - .forEach(f => require(`./build/${f}`)); + .forEach(f => require(`./build/${f}`)); \ No newline at end of file diff --git a/package.json b/package.json index ad900ec6e..e24f6bfec 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,11 @@ { "name": "code-oss-dev", - "version": "1.34.0", - "distro": "b9084061f5b1bb19d61328c0574b022c68269fc4", + "version": "1.37.0", + "distro": "11ab6b1c5be090591adc26a81f72a16908697165", "author": { "name": "Microsoft Corporation" }, + "license": "MIT", "main": "./out/main", "private": true, "scripts": { @@ -16,48 +17,49 @@ "watch-client": "gulp watch-client --max_old_space_size=4095", "monaco-editor-test": "mocha --only-monaco-editor", "precommit": "node build/gulpfile.hygiene.js", - "gulp": "gulp --max_old_space_size=4095", + "gulp": "gulp --max_old_space_size=8192", "7z": "7z", "update-grammars": "node build/npm/update-all-grammars.js", "update-localization-extension": "node build/npm/update-localization-extension.js", "smoketest": "cd test/smoke && node test/index.js", "download-builtin-extensions": "node build/lib/builtInExtensions.js", "monaco-compile-check": "tsc -p src/tsconfig.monaco.json --noEmit", - "strict-initialization-watch": "tsc --watch -p src/tsconfig.json --noEmit --strictPropertyInitialization" + "strict-initialization-watch": "tsc --watch -p src/tsconfig.json --noEmit --strictPropertyInitialization", + "update-distro": "node build/npm/update-distro.js" }, "dependencies": { "applicationinsights": "1.0.8", - "gc-signals": "^0.0.2", - "getmac": "1.4.1", "graceful-fs": "4.1.11", "http-proxy-agent": "^2.1.0", "https-proxy-agent": "^2.2.1", - "iconv-lite": "0.4.23", + "iconv-lite": "0.5.0", "jschardet": "1.6.0", - "keytar": "4.2.1", + "keytar": "^4.11.0", "minimist": "1.2.0", "native-is-elevated": "^0.2.1", - "native-keymap": "1.2.5", + "native-keymap": "2.0.0", "native-watchdog": "1.0.0", - "node-pty": "0.8.1", - "semver": "^5.5.0", - "spdlog": "0.8.1", - "sudo-prompt": "8.2.0", + "node-pty": "0.9.0-beta19", + "nsfw": "1.2.5", + "onigasm-umd": "^2.2.2", + "semver-umd": "^5.5.3", + "spdlog": "^0.9.0", + "sudo-prompt": "9.0.0", "v8-inspect-profiler": "^0.0.20", - "vscode-chokidar": "1.6.5", - "vscode-debugprotocol": "1.34.0", - "vscode-nsfw": "1.1.1", + "vscode-chokidar": "2.1.7", "vscode-proxy-agent": "0.4.0", - "vscode-ripgrep": "^1.2.5", - "vscode-sqlite3": "4.0.7", - "vscode-textmate": "^4.0.1", - "vscode-xterm": "3.13.0-beta3", - "yauzl": "^2.9.1", + "vscode-ripgrep": "^1.5.5", + "vscode-sqlite3": "4.0.8", + "vscode-textmate": "^4.2.2", + "xterm": "3.15.0-beta89", + "xterm-addon-search": "0.2.0-beta3", + "xterm-addon-web-links": "0.1.0-beta10", + "yauzl": "^2.9.2", "yazl": "^2.4.3" }, "devDependencies": { "7zip": "0.0.6", - "@types/keytar": "^4.0.1", + "@types/keytar": "^4.4.0", "@types/minimist": "^1.2.0", "@types/mocha": "2.2.39", "@types/node": "^10.12.12", @@ -68,21 +70,20 @@ "ansi-colors": "^3.2.3", "asar": "^0.14.0", "chromium-pickle-js": "^0.2.0", - "clean-css": "3.4.6", "copy-webpack-plugin": "^4.5.2", "coveralls": "^2.11.11", "cson-parser": "^1.3.3", "debounce": "^1.0.0", "documentdb": "^1.5.1", "electron-mksnapshot": "~2.0.0", - "eslint": "^3.4.0", + "eslint": "^4.18.2", "event-stream": "3.3.4", "express": "^4.13.1", "fancy-log": "^1.3.3", "fast-plist": "0.1.2", "glob": "^5.0.13", "gulp": "^4.0.0", - "gulp-atom-electron": "^1.20.0", + "gulp-atom-electron": "^1.21.1", "gulp-azure-storage": "^0.10.0", "gulp-buffer": "0.0.2", "gulp-concat": "^2.6.1", @@ -93,7 +94,7 @@ "gulp-gunzip": "^1.0.0", "gulp-json-editor": "^2.5.0", "gulp-plumber": "^1.2.0", - "gulp-remote-src": "^0.4.4", + "gulp-remote-retry-src": "^0.6.0", "gulp-rename": "^1.2.0", "gulp-replace": "^0.5.4", "gulp-shell": "^0.6.5", @@ -102,10 +103,15 @@ "gulp-uglify": "^3.0.0", "gulp-untar": "^0.0.7", "gulp-vinyl-zip": "^2.1.2", + "http-server": "^0.11.1", "husky": "^0.13.1", - "innosetup-compiler": "^5.5.60", + "innosetup": "5.6.1", "is": "^3.1.0", - "istanbul": "^0.3.17", + "istanbul-lib-coverage": "^2.0.5", + "istanbul-lib-instrument": "^3.3.0", + "istanbul-lib-report": "^2.0.8", + "istanbul-lib-source-maps": "^3.0.6", + "istanbul-reports": "^2.2.6", "jsdom-no-contextify": "^3.1.0", "lazy.js": "^0.4.2", "merge-options": "^1.0.1", @@ -114,26 +120,26 @@ "mkdirp": "^0.5.0", "mocha": "^2.2.5", "mocha-junit-reporter": "^1.17.0", + "opn": "^5.4.0", "optimist": "0.3.5", "p-all": "^1.0.0", "pump": "^1.0.1", "queue": "3.0.6", "rcedit": "^1.1.0", - "remap-istanbul": "^0.13.0", "rimraf": "^2.2.8", "sinon": "^1.17.2", "source-map": "^0.4.4", "ts-loader": "^4.4.2", - "tslint": "^5.11.0", - "typescript": "3.4.5", + "tslint": "^5.16.0", + "typescript": "3.5.2", "typescript-formatter": "7.1.0", - "typescript-tslint-plugin": "^0.0.7", "uglify-es": "^3.0.18", "underscore": "^1.8.2", "vinyl": "^2.0.0", "vinyl-fs": "^3.0.0", "vsce": "1.48.0", - "vscode-nls-dev": "3.2.5", + "vscode-debugprotocol": "1.35.0", + "vscode-nls-dev": "^3.3.1", "webpack": "^4.16.5", "webpack-cli": "^3.1.0", "webpack-stream": "^5.1.1" @@ -148,8 +154,8 @@ "optionalDependencies": { "vscode-windows-ca-certs": "0.1.0", "vscode-windows-registry": "1.0.1", - "windows-foreground-love": "0.1.0", - "windows-mutex": "0.2.1", - "windows-process-tree": "0.2.3" + "windows-foreground-love": "0.2.0", + "windows-mutex": "0.3.0", + "windows-process-tree": "0.2.4" } -} \ No newline at end of file +} diff --git a/remote/.yarnrc b/remote/.yarnrc new file mode 100644 index 000000000..b28191e6b --- /dev/null +++ b/remote/.yarnrc @@ -0,0 +1,3 @@ +disturl "http://nodejs.org/dist" +target "10.11.0" +runtime "node" diff --git a/remote/package.json b/remote/package.json new file mode 100644 index 000000000..34ffee1a4 --- /dev/null +++ b/remote/package.json @@ -0,0 +1,33 @@ +{ + "name": "vscode-reh", + "version": "0.0.0", + "dependencies": { + "applicationinsights": "1.0.8", + "getmac": "1.4.1", + "graceful-fs": "4.1.11", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.1", + "iconv-lite": "0.5.0", + "jschardet": "1.6.0", + "minimist": "1.2.0", + "native-watchdog": "1.0.0", + "node-pty": "0.9.0-beta19", + "nsfw": "1.2.5", + "onigasm-umd": "^2.2.2", + "semver-umd": "^5.5.3", + "spdlog": "^0.9.0", + "vscode-chokidar": "2.1.7", + "vscode-proxy-agent": "0.4.0", + "vscode-ripgrep": "^1.5.5", + "vscode-textmate": "^4.2.2", + "xterm": "3.15.0-beta89", + "xterm-addon-search": "0.2.0-beta3", + "xterm-addon-web-links": "0.1.0-beta10", + "yauzl": "^2.9.2", + "yazl": "^2.4.3" + }, + "optionalDependencies": { + "vscode-windows-ca-certs": "0.1.0", + "vscode-windows-registry": "1.0.1" + } +} diff --git a/remote/web/.yarnrc b/remote/web/.yarnrc new file mode 100644 index 000000000..b28191e6b --- /dev/null +++ b/remote/web/.yarnrc @@ -0,0 +1,3 @@ +disturl "http://nodejs.org/dist" +target "10.11.0" +runtime "node" diff --git a/remote/web/package.json b/remote/web/package.json new file mode 100644 index 000000000..c7a487b6c --- /dev/null +++ b/remote/web/package.json @@ -0,0 +1,12 @@ +{ + "name": "vscode-web", + "version": "0.0.0", + "dependencies": { + "onigasm-umd": "^2.2.2", + "vscode-textmate": "^4.1.1", + "xterm": "3.15.0-beta67", + "xterm-addon-search": "0.2.0-beta2", + "xterm-addon-web-links": "0.1.0-beta10", + "semver-umd": "^5.5.3" + } + } \ No newline at end of file diff --git a/remote/web/yarn.lock b/remote/web/yarn.lock new file mode 100644 index 000000000..b624eb372 --- /dev/null +++ b/remote/web/yarn.lock @@ -0,0 +1,47 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +nan@^2.14.0: + version "2.14.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" + integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== + +onigasm-umd@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/onigasm-umd/-/onigasm-umd-2.2.2.tgz#b989d762df61f899a3052ac794a50bd93fe20257" + integrity sha512-v2eMOJu7iE444L2iJN+U6s6s5S0y7oj/N0DAkrd6wokRtTVoq/v/yaDI1lIqFrTeJbNtqNzYvguDF5yNzW3Rvw== + +oniguruma@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/oniguruma/-/oniguruma-7.2.0.tgz#c9a59c1ea7b9fe67e237a02e02139b638856f3af" + integrity sha512-bh+ZLdykY1sdIx8jBp2zpLbVFDBc3XmKH4Ceo2lijNaN1WhEqtnpqFlmtCbRuDB17nJ58RAUStVwfW8e8uEbnA== + dependencies: + nan "^2.14.0" + +semver-umd@^5.5.3: + version "5.5.3" + resolved "https://registry.yarnpkg.com/semver-umd/-/semver-umd-5.5.3.tgz#b64d7a2d4f5a717b369d56e31940a38e47e34d1e" + integrity sha512-HOnQrn2iKnVe/xlqCTzMXQdvSz3rPbD0DmQXYuQ+oK1dpptGFfPghonQrx5JHl2O7EJwDqtQnjhE7ME23q6ngw== + +vscode-textmate@^4.1.1: + version "4.2.2" + resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-4.2.2.tgz#0b4dabc69a6fba79a065cb6b615f66eac07c8f4c" + integrity sha512-1U4ih0E/KP1zNK/EbpUqyYtI7PY+Ccd2nDGTtiMR/UalLFnmaYkwoWhN1oI7B91ptBN8NdVwWuvyUnvJAulCUw== + dependencies: + oniguruma "^7.2.0" + +xterm-addon-search@0.2.0-beta2: + version "0.2.0-beta2" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.2.0-beta2.tgz#c3173f0a6f207ee9f1848849174ee5d6b6ce8262" + integrity sha512-XEcwi2TeFGk2MuIFjiI/OpVXSNO5dGQBvHH3o+9KzqG3ooVqhhDqzwxs092QGNcNCGh8hGn/PWZiczaBBnKm/g== + +xterm-addon-web-links@0.1.0-beta10: + version "0.1.0-beta10" + resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.1.0-beta10.tgz#610fa9773a2a5ccd41c1c83ba0e2dd2c9eb66a23" + integrity sha512-xfpjy0V6bB4BR44qIgZQPoCMVakxb65gMscPkHpO//QxvUxKzabV3dxOsIbeZRFkUGsWTFlvz2OoaBLoNtv5gg== + +xterm@3.15.0-beta67: + version "3.15.0-beta67" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta67.tgz#71973e174bdc08df620945eecd3f87912f1ac550" + integrity sha512-qLfo9GHVlu/IxgDI3vRGObWZM7UL4eLhMfjZhprx2aXNMpzmrOW6l3JDRsCjUWm93EoVavbULtnDhGSiTlKitQ== diff --git a/remote/yarn.lock b/remote/yarn.lock new file mode 100644 index 000000000..1c4e700f4 --- /dev/null +++ b/remote/yarn.lock @@ -0,0 +1,1185 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +agent-base@4, agent-base@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.0.tgz#9838b5c3392b962bad031e6a4c5e1024abec45ce" + integrity sha512-c+R/U5X+2zz2+UCrCFv6odQzJdoqI+YecuhnAJLa1zYaMc13zPfwMwZrr91Pd1DYNo/yPRbiM4WVf9whgwFsIg== + dependencies: + es6-promisify "^5.0.0" + +agent-base@~4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" + integrity sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg== + dependencies: + es6-promisify "^5.0.0" + +applicationinsights@1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.0.8.tgz#db6e3d983cf9f9405fe1ee5ba30ac6e1914537b5" + integrity sha512-KzOOGdphOS/lXWMFZe5440LUdFbrLpMvh2SaRxn7BmiI550KAoSb2gIhiq6kJZ9Ir3AxRRztjhzif+e5P5IXIg== + dependencies: + diagnostic-channel "0.2.0" + diagnostic-channel-publishers "0.2.1" + zone.js "0.7.6" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= + +arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= + +async-each@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" + integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== + +atob@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +binary-extensions@^1.0.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.10.0.tgz#9aeb9a6c5e88638aad171e167f5900abe24835d0" + integrity sha1-muuabF6IY4qtFx4Wf1kAq+JINdA= + +bindings@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + +braces@^2.3.1, braces@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +buffer-crc32@~0.2.3: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +component-emitter@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +debug@3.1.0, debug@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + +debug@^2.2.0, debug@^2.3.3: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +diagnostic-channel-publishers@0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/diagnostic-channel-publishers/-/diagnostic-channel-publishers-0.2.1.tgz#8e2d607a8b6d79fe880b548bc58cc6beb288c4f3" + integrity sha1-ji1geottef6IC1SLxYzGvrKIxPM= + +diagnostic-channel@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/diagnostic-channel/-/diagnostic-channel-0.2.0.tgz#cc99af9612c23fb1fff13612c72f2cbfaa8d5a17" + integrity sha1-zJmvlhLCP7H/8TYSxy8sv6qNWhc= + dependencies: + semver "^5.3.0" + +eachr@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/eachr/-/eachr-3.2.0.tgz#2c35e43ea086516f7997cf80b7aa64d55a4a4484" + integrity sha1-LDXkPqCGUW95l8+At6pk1VpKRIQ= + dependencies: + editions "^1.1.1" + typechecker "^4.3.0" + +editions@^1.1.1, editions@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.4.tgz#3662cb592347c3168eb8e498a0ff73271d67f50b" + integrity sha512-gzao+mxnYDzIysXKMQi/+M1mjy/rjestjg6OPoYTtI+3Izp23oiGZitsl9lPDPiTGXbcSIk1iJWhliSaglxnUg== + +editions@^2.1.0, editions@^2.1.2: + version "2.1.3" + resolved "https://registry.yarnpkg.com/editions/-/editions-2.1.3.tgz#727ccf3ec2c7b12dcc652c71000f16c4824d6f7d" + integrity sha512-xDZyVm0A4nLgMNWVVLJvcwMjI80ShiH/27RyLiCnW1L273TcJIA25C4pwJ33AWV01OX6UriP35Xu+lH4S7HWQw== + dependencies: + errlop "^1.1.1" + semver "^5.6.0" + +errlop@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/errlop/-/errlop-1.1.1.tgz#d9ae4c76c3e64956c5d79e6e035d6343bfd62250" + integrity sha512-WX7QjiPHhsny7/PQvrhS5VMizXXKoKCS3udaBp8gjlARdbn+XmK300eKBAAN0hGyRaTCtRpOaxK+xFVPUJ3zkw== + dependencies: + editions "^2.1.2" + +es6-promise@^4.0.3: + version "4.2.4" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29" + integrity sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ== + +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= + dependencies: + es6-promise "^4.0.3" + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extract-opts@^3.2.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/extract-opts/-/extract-opts-3.3.1.tgz#5abbedc98c0d5202e3278727f9192d7e086c6be1" + integrity sha1-WrvtyYwNUgLjJ4cn+Rktfghsa+E= + dependencies: + eachr "^3.2.0" + editions "^1.1.1" + typechecker "^4.3.0" + +fd-slicer@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" + integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4= + dependencies: + pend "~1.2.0" + +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= + dependencies: + map-cache "^0.2.2" + +fs-extra@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" + integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= + +getmac@1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/getmac/-/getmac-1.4.1.tgz#cfefcb3ee7d7a73cba5292129cb100c19afbe17a" + integrity sha512-mQp+8D+grQX0gG8EJn6VfH0PxE56ZKNsTguOMxPShAiVk9lvH8Ey36eXepG705Ac1HCsvaSrQ/6bPHZ0++F/Mg== + dependencies: + editions "^1.3.4" + extract-opts "^3.2.0" + +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +graceful-fs@4.1.11, graceful-fs@^4.1.2: + version "4.1.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + integrity sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg= + +graceful-fs@^4.1.11, graceful-fs@^4.1.6: + version "4.2.0" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.0.tgz#8d8fdc73977cb04104721cb53666c1ca64cd328b" + integrity sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg== + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +http-proxy-agent@2.1.0, http-proxy-agent@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405" + integrity sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg== + dependencies: + agent-base "4" + debug "3.1.0" + +https-proxy-agent@2.2.1, https-proxy-agent@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0" + integrity sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ== + dependencies: + agent-base "^4.1.0" + debug "^3.1.0" + +iconv-lite@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.5.0.tgz#59cdde0a2a297cc2aeb0c6445a195ee89f127550" + integrity sha512-NnEhI9hIEKHOzJ4f697DMz9IQEXr/MMJ5w64vN2/4Ai+wRnvV7SBrL0KLoRlwaKVghOc7LQ5YkPLuX146b6Ydw== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +inherits@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +ip@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" + integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== + dependencies: + kind-of "^6.0.0" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.0.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.4.tgz#cfc86ccd5dc5a52fa80489111c6920c457e2d98b" + integrity sha1-z8hszV3FpS+oBIkRHGkgxFfi2Ys= + +is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== + dependencies: + kind-of "^6.0.0" + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^2.1.0, is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= + dependencies: + is-extglob "^2.1.0" + +is-glob@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= + dependencies: + kind-of "^3.0.2" + +is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + +isarray@1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + +jschardet@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-1.6.0.tgz#c7d1a71edcff2839db2f9ec30fc5d5ebd3c1a678" + integrity sha512-xYuhvQ7I9PDJIGBWev9xm0+SMSed3ZDBAmvVjbFR1ZRLAF+vlXcQu6cRI9uAlj81rzikElRVteehwV7DuX2ZmQ== + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + optionalDependencies: + graceful-fs "^4.1.6" + +kind-of@^3.0.2: + version "3.0.4" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.0.4.tgz#7b8ecf18a4e17f8269d73b501c9f232c96887a74" + integrity sha1-e47PGKThf4Jp1ztQHJ8jLJaIenQ= + dependencies: + is-buffer "^1.0.2" + +kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== + +lodash.isinteger@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" + integrity sha1-YZwK89A/iwTDH1iChAt3sRzWg0M= + +lodash.isundefined@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz#23ef3d9535565203a66cefd5b830f848911afb48" + integrity sha1-I+89lTVWUgOmbO/VuDD4SJEa+0g= + +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= + dependencies: + object-visit "^1.0.0" + +micromatch@^3.1.10: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= + +minimist@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= + +mixin-deep@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= + dependencies: + minimist "0.0.8" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +nan@^2.0.0, nan@^2.12.1, nan@^2.13.2, nan@^2.14.0: + version "2.14.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" + integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +native-watchdog@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/native-watchdog/-/native-watchdog-1.0.0.tgz#97344e83cd6815a8c8e6c44a52e7be05832e65ca" + integrity sha512-HKQATz5KLUMPyQQ/QaalzgTXaGz2plYPBxjyalaR4ECIu/UznXY8YJD+a9SLkkcvtxnJ8/zHLY3xik06vUZ7uA== + +node-addon-api@1.6.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-1.6.2.tgz#d8aad9781a5cfc4132cc2fecdbdd982534265217" + integrity sha512-479Bjw9nTE5DdBSZZWprFryHGjUaQC31y1wHo19We/k0BZlrmhqQitWoUL0cD8+scljCbIUL+E58oRDEakdGGA== + +node-pty@0.9.0-beta19: + version "0.9.0-beta19" + resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.9.0-beta19.tgz#0fd381b2006f4665c4c2ee0509219e591842371a" + integrity sha512-MkKEvBnauGnzgXNr/oaoWQLVXm1gheIKZs4YQp8883ZiETmbEnpSvD0FU3bELcPXG5VFPRqIGsQJ4KUMBLzkPA== + dependencies: + nan "^2.13.2" + +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +nsfw@1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/nsfw/-/nsfw-1.2.5.tgz#febe581af616f7b042f89df133abe62416c4c803" + integrity sha512-m3mwZUKXiCR69PDMLfAmKmiNzy0Oe9LhFE0DYZC5cc1htNj5Hyb1sAgglXhuaDkibFy22AVvPC5cCFB3A6mYIw== + dependencies: + fs-extra "^7.0.0" + lodash.isinteger "^4.0.4" + lodash.isundefined "^3.0.1" + nan "^2.0.0" + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + dependencies: + isobject "^3.0.0" + +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + dependencies: + isobject "^3.0.1" + +onigasm-umd@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/onigasm-umd/-/onigasm-umd-2.2.2.tgz#b989d762df61f899a3052ac794a50bd93fe20257" + integrity sha512-v2eMOJu7iE444L2iJN+U6s6s5S0y7oj/N0DAkrd6wokRtTVoq/v/yaDI1lIqFrTeJbNtqNzYvguDF5yNzW3Rvw== + +oniguruma@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/oniguruma/-/oniguruma-7.2.0.tgz#c9a59c1ea7b9fe67e237a02e02139b638856f3af" + integrity sha512-bh+ZLdykY1sdIx8jBp2zpLbVFDBc3XmKH4Ceo2lijNaN1WhEqtnpqFlmtCbRuDB17nJ58RAUStVwfW8e8uEbnA== + dependencies: + nan "^2.14.0" + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= + +picomatch@^2.0.4: + version "2.0.7" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.0.7.tgz#514169d8c7cd0bdbeecc8a2609e34a7163de69f6" + integrity sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA== + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + +process-nextick-args@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + integrity sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M= + +readable-stream@^2.0.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" + integrity sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + safe-buffer "~5.1.1" + string_decoder "~1.0.3" + util-deprecate "~1.0.1" + +readdirp@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== + dependencies: + graceful-fs "^4.1.11" + micromatch "^3.1.10" + readable-stream "^2.0.2" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +repeat-element@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + integrity sha1-7wiaF40Ug7quTZPrmLT55OEdmQo= + +repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" + integrity sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg== + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +semver-umd@^5.5.3: + version "5.5.3" + resolved "https://registry.yarnpkg.com/semver-umd/-/semver-umd-5.5.3.tgz#b64d7a2d4f5a717b369d56e31940a38e47e34d1e" + integrity sha512-HOnQrn2iKnVe/xlqCTzMXQdvSz3rPbD0DmQXYuQ+oK1dpptGFfPghonQrx5JHl2O7EJwDqtQnjhE7ME23q6ngw== + +semver@^5.3.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" + integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== + +semver@^5.6.0: + version "5.7.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" + integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== + +set-value@^2.0.0, set-value@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +smart-buffer@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.0.1.tgz#07ea1ca8d4db24eb4cac86537d7d18995221ace3" + integrity sha512-RFqinRVJVcCAL9Uh1oVqE6FZkqsyLiVOYEZ20TqIOjuX7iFVJ+zsbs4RIghnw/pTs7mZvt8ZHhvm1ZUrR4fykg== + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +socks-proxy-agent@4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-4.0.1.tgz#5936bf8b707a993079c6f37db2091821bffa6473" + integrity sha512-Kezx6/VBguXOsEe5oU3lXYyKMi4+gva72TwJ7pQY5JfqUx2nMk7NXA6z/mpNqIlfQjWYVfeuNvQjexiTaTn6Nw== + dependencies: + agent-base "~4.2.0" + socks "~2.2.0" + +socks@~2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.2.1.tgz#68ad678b3642fbc5d99c64c165bc561eab0215f9" + integrity sha512-0GabKw7n9mI46vcNrVfs0o6XzWzjVa3h6GaSo2UPxtWAROXUWavfJWh1M4PR5tnE0dcnQXZIDFP4yrAysLze/w== + dependencies: + ip "^1.1.5" + smart-buffer "^4.0.1" + +source-map-resolve@^0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" + integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== + dependencies: + atob "^2.1.1" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= + +source-map@^0.5.6: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +spdlog@^0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/spdlog/-/spdlog-0.9.0.tgz#c85dd9d0b9cd385f6f3f5b92dc9d2e1691092b5c" + integrity sha512-AeLWPCYjGi4w5DfpXFKb9pCdgMe4gFBMroGfgwXiNfzwmcNYGoFQkIuD1MChZBR1Iwrx0nGhsTSHFslt/qfTAQ== + dependencies: + bindings "^1.5.0" + mkdirp "^0.5.1" + nan "^2.14.0" + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +string_decoder@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" + integrity sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ== + dependencies: + safe-buffer "~5.1.0" + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +typechecker@^4.3.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/typechecker/-/typechecker-4.7.0.tgz#5249f427358f45b7250c4924fd4d01ed9ba435e9" + integrity sha512-4LHc1KMNJ6NDGO+dSM/yNfZQRtp8NN7psYrPHUblD62Dvkwsp3VShsbM78kOgpcmMkRTgvwdKOTjctS+uMllgQ== + dependencies: + editions "^2.1.0" + +union-value@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^2.0.1" + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +upath@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.2.tgz#3db658600edaeeccbe6db5e684d67ee8c2acd068" + integrity sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q== + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +vscode-anymatch@3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/vscode-anymatch/-/vscode-anymatch-3.0.3.tgz#5a79101e6df7e659a1f070367bc42f190eb4ae76" + integrity sha512-qQgfbzJJ5nNShh4jjC3BBekY4d8emcxHFgnqcXwsB/PUKvJPCg7AZYXM7hqS7EDnKrX9tsIFwFMihZ7yut92Qg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +vscode-chokidar@2.1.7: + version "2.1.7" + resolved "https://registry.yarnpkg.com/vscode-chokidar/-/vscode-chokidar-2.1.7.tgz#c5b31eb87402f4779bb4170915245bdcb6f7854b" + integrity sha512-uSNEQetPjAlgIAHmcF9E6M+KCw0f842rsEnJ64aamUAV6TO7gkXNCvLSzb4MuLsPU7ZQyCa++DrLQFjvciK5dg== + dependencies: + async-each "^1.0.1" + braces "^2.3.2" + glob-parent "^3.1.0" + inherits "^2.0.3" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + normalize-path "^3.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.2.1" + upath "^1.1.1" + vscode-anymatch "3.0.3" + optionalDependencies: + vscode-fsevents "1.2.12" + +vscode-fsevents@1.2.12: + version "1.2.12" + resolved "https://registry.yarnpkg.com/vscode-fsevents/-/vscode-fsevents-1.2.12.tgz#01a71a01f90ee95ca822c34427aba437a17c03a7" + integrity sha512-bH/jRdDpSesGpqiVLjp6gHLSKUOh7oNvppzZ17JIrdbRYCcDmV7dIWR5gQc27DFy0RD9JDT+t+ixMid94MkM1A== + dependencies: + nan "^2.14.0" + +vscode-proxy-agent@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/vscode-proxy-agent/-/vscode-proxy-agent-0.4.0.tgz#574833e65405c6333f350f1b9fef9909deccb6b5" + integrity sha512-L+WKjDOXRPxpq31Uj1Wr3++jaNNmhykn8JnGoYcwepbTnUwJKCbyyXRgb/hlBx0LXsF+k3BsnXt+r+5Q8rm97g== + dependencies: + debug "3.1.0" + http-proxy-agent "2.1.0" + https-proxy-agent "2.2.1" + socks-proxy-agent "4.0.1" + +vscode-ripgrep@^1.5.5: + version "1.5.5" + resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.5.tgz#24c0e9cb356cf889c98e15ecb58f9cf654a1d961" + integrity sha512-OrPrAmcun4+uZAuNcQvE6CCPskh+5AsjANod/Q3zRcJcGNxgoOSGlQN9RPtatkUNmkN8Nn8mZBnS1jMylu/dKg== + +vscode-textmate@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-4.2.2.tgz#0b4dabc69a6fba79a065cb6b615f66eac07c8f4c" + integrity sha512-1U4ih0E/KP1zNK/EbpUqyYtI7PY+Ccd2nDGTtiMR/UalLFnmaYkwoWhN1oI7B91ptBN8NdVwWuvyUnvJAulCUw== + dependencies: + oniguruma "^7.2.0" + +vscode-windows-ca-certs@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/vscode-windows-ca-certs/-/vscode-windows-ca-certs-0.1.0.tgz#d58eeb40b536130918cfde2b01e6dc7e5c1bd757" + integrity sha512-ZfZbfJIE09Q0dwGqmqTj7kuAq4g6lul9WPJvo0DkKjln8/FL+dY3wUKIKbYwWQp4x56SBTLBq3tJkD72xQ9Gqw== + dependencies: + node-addon-api "1.6.2" + +vscode-windows-registry@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/vscode-windows-registry/-/vscode-windows-registry-1.0.1.tgz#bc9f765563eb6dc1c9ad9a41f9eaacc84dfadc7c" + integrity sha512-q0aKXi9Py1OBdmXIJJFeJBzpPJMMUxMJNBU9FysWIXEwJyMQGEVevKzM2J3Qz/cHSc5LVqibmoUWzZ7g+97qRg== + dependencies: + nan "^2.12.1" + +xterm-addon-search@0.2.0-beta3: + version "0.2.0-beta3" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.2.0-beta3.tgz#710ce14658e269c5a4791f5a9e2f520883a2e62b" + integrity sha512-KzVdkEtGbKJe9ER2TmrI7XjF/wUq1lir9U63vPJi0t2ymQvIECl1V63f9QtOp1vvpdhbZiXBxO+vGTj+y0tRow== + +xterm-addon-web-links@0.1.0-beta10: + version "0.1.0-beta10" + resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.1.0-beta10.tgz#610fa9773a2a5ccd41c1c83ba0e2dd2c9eb66a23" + integrity sha512-xfpjy0V6bB4BR44qIgZQPoCMVakxb65gMscPkHpO//QxvUxKzabV3dxOsIbeZRFkUGsWTFlvz2OoaBLoNtv5gg== + +xterm@3.15.0-beta89: + version "3.15.0-beta89" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta89.tgz#255962e2595deefb42b8c0043001256526163a3f" + integrity sha512-rNaoUamacPRg+ejbKDGRDNqR3SZ3Uf/pUW0mO+FF25/lIgdLq8x7RgZVBgFweCZ/dijPjxoyMcgfNDTH9h8LOg== + +yauzl@^2.9.2: + version "2.10.0" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" + integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk= + dependencies: + buffer-crc32 "~0.2.3" + fd-slicer "~1.1.0" + +yazl@^2.4.3: + version "2.4.3" + resolved "https://registry.yarnpkg.com/yazl/-/yazl-2.4.3.tgz#ec26e5cc87d5601b9df8432dbdd3cd2e5173a071" + integrity sha1-7CblzIfVYBud+EMtvdPNLlFzoHE= + dependencies: + buffer-crc32 "~0.2.3" + +zone.js@0.7.6: + version "0.7.6" + resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.7.6.tgz#fbbc39d3e0261d0986f1ba06306eb3aeb0d22009" + integrity sha1-+7w50+AmHQmG8boGMG6zrrDSIAk= diff --git a/resources/completions/bash/code b/resources/completions/bash/code index e377c5d24..f40963db0 100644 --- a/resources/completions/bash/code +++ b/resources/completions/bash/code @@ -50,7 +50,7 @@ _code() --uninstall-extension --enable-proposed-api --verbose --log -s --status -p --performance --prof-startup --disable-extensions --disable-extension --inspect-extensions - --inspect-brk-extensions --disable-gpu --upload-logs + --inspect-brk-extensions --disable-gpu --max-memory=' -- "$cur") ) [[ $COMPREPLY == *= ]] && compopt -o nospace return diff --git a/resources/completions/zsh/_code b/resources/completions/zsh/_code index 9579cffb2..265c199f6 100644 --- a/resources/completions/zsh/_code +++ b/resources/completions/zsh/_code @@ -14,8 +14,10 @@ arguments=( '--user-data-dir[specify the directory that user data is kept in]:directory:_directories' '(- *)'{-v,--version}'[print version]' '(- *)'{-h,--help}'[print usage]' + '(- *)'{--telemetry}'[Shows all telemetry events which VS code collects.]' '--extensions-dir[set the root path for extensions]:root path:_directories' '--list-extensions[list the installed extensions]' + '--category[filters instaled extension list by category, when using --list-extension]' '--show-versions[show versions of installed extensions, when using --list-extension]' '--install-extension[install an extension]:id or path:_files -g "*.vsix(-.)"' '--uninstall-extension[uninstall an extension]:id or path:_files -g "*.vsix(-.)"' @@ -30,7 +32,6 @@ arguments=( '--inspect-extensions[allow debugging and profiling of extensions]' '--inspect-brk-extensions[allow debugging and profiling of extensions with the extension host being paused after start]' '--disable-gpu[disable GPU hardware acceleration]' - '--upload-logs[upload logs from current session to a secure endpoint]:confirm:(iConfirmLogsUpload)' '--max-memory=[max memory size for a window (in Mbytes)]:size (Mbytes)' '*:file or directory:_files' ) diff --git a/resources/linux/rpm/dependencies.json b/resources/linux/rpm/dependencies.json index d0b64c4fa..34f127e1a 100644 --- a/resources/linux/rpm/dependencies.json +++ b/resources/linux/rpm/dependencies.json @@ -63,83 +63,5 @@ "libxcb.so.1()(64bit)", "libxkbfile.so.1()(64bit)", "libsecret-1.so.0()(64bit)" - ], - "i386": [ - "ld-linux.so.2", - "ld-linux.so.2(GLIBC_2.1)", - "libX11-xcb.so.1", - "libX11.so.6", - "libXcomposite.so.1", - "libXcursor.so.1", - "libXdamage.so.1", - "libXext.so.6", - "libXfixes.so.3", - "libXi.so.6", - "libXrandr.so.2", - "libXrender.so.1", - "libXss.so.1", - "libXtst.so.6", - "libasound.so.2", - "libatk-1.0.so.0", - "libc.so.6", - "libc.so.6(GLIBC_2.0)", - "libc.so.6(GLIBC_2.1)", - "libc.so.6(GLIBC_2.1.3)", - "libc.so.6(GLIBC_2.11)", - "libc.so.6(GLIBC_2.2)", - "libc.so.6(GLIBC_2.2.3)", - "libc.so.6(GLIBC_2.3)", - "libc.so.6(GLIBC_2.3.2)", - "libc.so.6(GLIBC_2.3.4)", - "libc.so.6(GLIBC_2.4)", - "libc.so.6(GLIBC_2.6)", - "libc.so.6(GLIBC_2.7)", - "libcairo.so.2", - "libcups.so.2", - "libdbus-1.so.3", - "libdl.so.2", - "libdl.so.2(GLIBC_2.0)", - "libdl.so.2(GLIBC_2.1)", - "libexpat.so.1", - "libfontconfig.so.1", - "libfreetype.so.6", - "libgcc_s.so.1", - "libgcc_s.so.1(GCC_4.0.0)", - "libgcc_s.so.1(GLIBC_2.0)", - "libgdk-x11-2.0.so.0", - "libgdk_pixbuf-2.0.so.0", - "libgio-2.0.so.0", - "libglib-2.0.so.0", - "libgmodule-2.0.so.0", - "libgobject-2.0.so.0", - "libgtk-3.so.0", - "libm.so.6", - "libm.so.6(GLIBC_2.0)", - "libm.so.6(GLIBC_2.1)", - "libnspr4.so", - "libnss3.so", - "libnssutil3.so", - "libpango-1.0.so.0", - "libpangocairo-1.0.so.0", - "libpthread.so.0", - "libpthread.so.0(GLIBC_2.0)", - "libpthread.so.0(GLIBC_2.1)", - "libpthread.so.0(GLIBC_2.2)", - "libpthread.so.0(GLIBC_2.2.3)", - "libpthread.so.0(GLIBC_2.3.2)", - "libpthread.so.0(GLIBC_2.3.3)", - "librt.so.1", - "librt.so.1(GLIBC_2.2)", - "libsmime3.so", - "libstdc++.so.6", - "libstdc++.so.6(GLIBCXX_3.4)", - "libstdc++.so.6(GLIBCXX_3.4.10)", - "libstdc++.so.6(GLIBCXX_3.4.11)", - "libstdc++.so.6(GLIBCXX_3.4.14)", - "libstdc++.so.6(GLIBCXX_3.4.15)", - "libstdc++.so.6(GLIBCXX_3.4.9)", - "libxcb.so.1", - "libxkbfile.so.1", - "libsecret-1.so.0" ] } \ No newline at end of file diff --git a/resources/linux/snap/snapcraft.yaml b/resources/linux/snap/snapcraft.yaml index 0a78d41e8..28b3e59ad 100644 --- a/resources/linux/snap/snapcraft.yaml +++ b/resources/linux/snap/snapcraft.yaml @@ -51,6 +51,7 @@ apps: @@NAME@@: command: electron-launch $SNAP/usr/share/@@NAME@@/bin/@@NAME@@ desktop: usr/share/applications/@@NAME@@.desktop + common-id: @@NAME@@.desktop environment: DISABLE_WAYLAND: 1 GSETTINGS_SCHEMA_DIR: $SNAP/usr/share/glib-2.0/schemas diff --git a/resources/win32/bin/code.sh b/resources/win32/bin/code.sh index 82f808a86..4bc4677e1 100644 --- a/resources/win32/bin/code.sh +++ b/resources/win32/bin/code.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh # # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. See License.txt in the project root for license information. @@ -6,44 +6,44 @@ COMMIT="@@COMMIT@@" APP_NAME="@@APPNAME@@" QUALITY="@@QUALITY@@" NAME="@@NAME@@" +DATAFOLDER="@@DATAFOLDER@@" VSCODE_PATH="$(dirname "$(dirname "$(realpath "$0")")")" ELECTRON="$VSCODE_PATH/$NAME.exe" if grep -qi Microsoft /proc/version; then # in a wsl shell - fallback() { + if [ "$WSL_DISTRO_NAME" ]; then + # $WSL_DISTRO_NAME is available since WSL builds 18362, also for WSL2 + WSL_BUILD=18362 + else + WSL_BUILD=$(uname -r | sed -E 's/^.+-([0-9]+)-Microsoft/\1/') + if [ -z "$WSL_BUILD" ]; then + WSL_BUILD=0 + fi + fi + + if [ $WSL_BUILD -ge 17063 ]; then + # $WSL_DISTRO_NAME is available since WSL builds 18362, also for WSL2 + # WSLPATH is available since WSL build 17046 + # WSLENV is available since WSL build 17063 + export WSLENV=ELECTRON_RUN_AS_NODE/w:$WSLENV + CLI=$(wslpath -m "$VSCODE_PATH/resources/app/out/cli.js") + + # use the Remote WSL extension if installed + WSL_EXT_ID="ms-vscode-remote.remote-wsl" + WSL_EXT_WLOC=$(ELECTRON_RUN_AS_NODE=1 "$ELECTRON" "$CLI" --locate-extension $WSL_EXT_ID) + if [ -n "$WSL_EXT_WLOC" ]; then + # replace \r\n with \n in WSL_EXT_WLOC + WSL_CODE=$(wslpath -u "${WSL_EXT_WLOC%%[[:cntrl:]]}")/scripts/wslCode.sh + "$WSL_CODE" "$COMMIT" "$QUALITY" "$ELECTRON" "$APP_NAME" "$DATAFOLDER" "$@" + exit $? + fi + else # If running under older WSL, don't pass cli.js to Electron as # environment vars cannot be transferred from WSL to Windows # See: https://github.com/Microsoft/BashOnWindows/issues/1363 # https://github.com/Microsoft/BashOnWindows/issues/1494 "$ELECTRON" "$@" exit $? - } - WSL_BUILD=$(uname -r | sed -E 's/^.+-([0-9]+)-Microsoft/\1/') - # wslpath is not available prior to WSL build 17046 - # See: https://docs.microsoft.com/en-us/windows/wsl/release-notes#build-17046 - if [ -x /bin/wslpath ]; then - WIN_CODE_CMD=$(wslpath -w "$(dirname "$(realpath "$0")")/$APP_NAME.cmd") - # make sure the cwd is in the windows fs, otherwise there will be a warning from cmd - pushd "$(dirname "$0")" > /dev/null - WSL_EXT_ID="ms-vscode.remote-wsl" - WSL_EXT_WLOC=$(cmd.exe /c "$WIN_CODE_CMD" --locate-extension $WSL_EXT_ID) - popd > /dev/null - if ! [ -z "$WSL_EXT_WLOC" ]; then - # replace \r\n with \n in WSL_EXT_WLOC, get linux path for - WSL_CODE=$(wslpath -u "${WSL_EXT_WLOC%%[[:cntrl:]]}")/scripts/wslCode.sh - "$WSL_CODE" $COMMIT $QUALITY "$WIN_CODE_CMD" "$APP_NAME" "$@" - exit $? - elif [ $WSL_BUILD -ge 17063 ] 2> /dev/null; then - # Since WSL build 17063, we just need to set WSLENV so that - # ELECTRON_RUN_AS_NODE is visible to the win32 process - # See: https://docs.microsoft.com/en-us/windows/wsl/release-notes#build-17063 - export WSLENV=ELECTRON_RUN_AS_NODE/w:$WSLENV - CLI=$(wslpath -m "$VSCODE_PATH/resources/app/out/cli.js") - else # $WSL_BUILD ∈ [17046, 17063) OR $WSL_BUILD is indeterminate - fallback "$@" - fi - else - fallback "$@" fi elif [ -x "$(command -v cygpath)" ]; then CLI=$(cygpath -m "$VSCODE_PATH/resources/app/out/cli.js") @@ -51,4 +51,4 @@ else CLI="$VSCODE_PATH/resources/app/out/cli.js" fi ELECTRON_RUN_AS_NODE=1 "$ELECTRON" "$CLI" "$@" -exit $? \ No newline at end of file +exit $? diff --git a/scripts/code-cli.bat b/scripts/code-cli.bat index 927e3e00d..6fbf5edd6 100644 --- a/scripts/code-cli.bat +++ b/scripts/code-cli.bat @@ -17,7 +17,7 @@ set CODE=".build\electron\%NAMESHORT%" node build\lib\electron.js if %errorlevel% neq 0 node .\node_modules\gulp\bin\gulp.js electron -:: Manage build-in extensions +:: Manage built-in extensions if "%1"=="--builtin" goto builtin :: Sync built-in extensions diff --git a/scripts/code.sh b/scripts/code.sh index 8227916f9..542efab52 100755 --- a/scripts/code.sh +++ b/scripts/code.sh @@ -58,15 +58,21 @@ function code() { function code-wsl() { # in a wsl shell - local WIN_CODE_CLI_CMD=$(wslpath -w "$ROOT/scripts/code-cli.bat") - if ! [ -z "$WIN_CODE_CLI_CMD" ]; then - local WSL_EXT_ID="ms-vscode.remote-wsl" - local WSL_EXT_WLOC=$(cmd.exe /c "$WIN_CODE_CLI_CMD" --locate-extension $WSL_EXT_ID) - if ! [ -z "$WSL_EXT_WLOC" ]; then + ELECTRON="$ROOT/.build/electron/Code - OSS.exe" + if [ -f "$ELECTRON" ]; then + local CWD=$(pwd) + cd $ROOT + export WSLENV=ELECTRON_RUN_AS_NODE/w:$WSLENV + local WSL_EXT_ID="ms-vscode-remote.remote-wsl" + local WSL_EXT_WLOC=$(ELECTRON_RUN_AS_NODE=1 "$ROOT/.build/electron/Code - OSS.exe" "out/cli.js" --locate-extension $WSL_EXT_ID) + cd $CWD + if [ -n "$WSL_EXT_WLOC" ]; then # replace \r\n with \n in WSL_EXT_WLOC local WSL_CODE=$(wslpath -u "${WSL_EXT_WLOC%%[[:cntrl:]]}")/scripts/wslCode-dev.sh $WSL_CODE "$ROOT" "$@" exit $? + else + echo "Remote WSL not installed, trying to run VSCode in WSL." fi fi } @@ -74,4 +80,4 @@ function code-wsl() if ! [ -z ${IN_WSL+x} ]; then code-wsl "$@" fi -code "$@" \ No newline at end of file +code "$@" diff --git a/scripts/env.ps1 b/scripts/env.ps1 deleted file mode 100644 index 72e094d0a..000000000 --- a/scripts/env.ps1 +++ /dev/null @@ -1,3 +0,0 @@ -$env:npm_config_disturl="https://atom.io/download/electron" -$env:npm_config_target=(node -p "require('./build/lib/electron').getElectronVersion();") -$env:npm_config_runtime="electron" diff --git a/scripts/env.sh b/scripts/env.sh deleted file mode 100755 index 8f641759b..000000000 --- a/scripts/env.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -export npm_config_disturl=https://atom.io/download/electron -export npm_config_target=$(node -p "require('./build/lib/electron').getElectronVersion();") -export npm_config_runtime=electron -export npm_config_cache="$HOME/.npm-electron" -mkdir -p "$npm_config_cache" diff --git a/scripts/test-integration.bat b/scripts/test-integration.bat index d6ef0295e..20567bc77 100644 --- a/scripts/test-integration.bat +++ b/scripts/test-integration.bat @@ -10,22 +10,26 @@ call .\scripts\test.bat --runGlob **\*.integrationTest.js %* if %errorlevel% neq 0 exit /b %errorlevel% :: Tests in the extension host -call .\scripts\code.bat %~dp0\..\extensions\vscode-api-tests\testWorkspace --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\singlefolder-tests --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% +call .\scripts\code.bat %~dp0\..\extensions\vscode-api-tests\testWorkspace --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\singlefolder-tests --disable-extensions --disable-inspect --user-data-dir=%VSCODEUSERDATADIR% if %errorlevel% neq 0 exit /b %errorlevel% -call .\scripts\code.bat %~dp0\..\extensions\vscode-api-tests\testworkspace.code-workspace --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\workspace-tests --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% +call .\scripts\code.bat %~dp0\..\extensions\vscode-api-tests\testworkspace.code-workspace --extensionDevelopmentPath=%~dp0\..\extensions\vscode-api-tests --extensionTestsPath=%~dp0\..\extensions\vscode-api-tests\out\workspace-tests --disable-extensions --disable-inspect --user-data-dir=%VSCODEUSERDATADIR% if %errorlevel% neq 0 exit /b %errorlevel% -call .\scripts\code.bat %~dp0\..\extensions\vscode-colorize-tests\test --extensionDevelopmentPath=%~dp0\..\extensions\vscode-colorize-tests --extensionTestsPath=%~dp0\..\extensions\vscode-colorize-tests\out --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% +call .\scripts\code.bat %~dp0\..\extensions\vscode-colorize-tests\test --extensionDevelopmentPath=%~dp0\..\extensions\vscode-colorize-tests --extensionTestsPath=%~dp0\..\extensions\vscode-colorize-tests\out --disable-extensions --disable-inspect --user-data-dir=%VSCODEUSERDATADIR% if %errorlevel% neq 0 exit /b %errorlevel% -call .\scripts\code.bat $%~dp0\..\extensions\emmet\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\emmet --extensionTestsPath=%~dp0\..\extensions\emmet\out\test --disable-extensions --user-data-dir=%VSCODEUSERDATADIR% . +call .\scripts\code.bat $%~dp0\..\extensions\emmet\test-fixtures --extensionDevelopmentPath=%~dp0\..\extensions\emmet --extensionTestsPath=%~dp0\..\extensions\emmet\out\test --disable-extensions --disable-inspect --user-data-dir=%VSCODEUSERDATADIR% . if %errorlevel% neq 0 exit /b %errorlevel% :: Tests in commonJS (HTML, CSS, JSON language server tests...) call .\scripts\node-electron.bat .\node_modules\mocha\bin\_mocha .\extensions\*\server\out\test\**\*.test.js if %errorlevel% neq 0 exit /b %errorlevel% +if exist ".\resources\server\test\test-remote-integration.bat" ( + call .\resources\server\test\test-remote-integration.bat +) + rmdir /s /q %VSCODEUSERDATADIR% popd diff --git a/scripts/test-integration.sh b/scripts/test-integration.sh index d95026b94..45595a5f0 100755 --- a/scripts/test-integration.sh +++ b/scripts/test-integration.sh @@ -16,15 +16,19 @@ cd $ROOT ./scripts/test.sh --runGlob **/*.integrationTest.js "$@" # Tests in the extension host -./scripts/code.sh $ROOT/extensions/vscode-api-tests/testWorkspace --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/singlefolder-tests --disable-extensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started -./scripts/code.sh $ROOT/extensions/vscode-api-tests/testworkspace.code-workspace --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/workspace-tests --disable-extensions --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 --disable-extensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started -./scripts/code.sh $ROOT/extensions/markdown-language-features/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/markdown-language-features --extensionTestsPath=$ROOT/extensions/markdown-language-features/out/test --disable-extensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started +./scripts/code.sh $ROOT/extensions/vscode-api-tests/testWorkspace --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/singlefolder-tests --disable-extensions --skip-getting-started --disable-inspect --user-data-dir=$VSCODEUSERDATADIR +./scripts/code.sh $ROOT/extensions/vscode-api-tests/testworkspace.code-workspace --extensionDevelopmentPath=$ROOT/extensions/vscode-api-tests --extensionTestsPath=$ROOT/extensions/vscode-api-tests/out/workspace-tests --disable-extensions --skip-getting-started --disable-inspect --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 --disable-extensions --skip-getting-started --disable-inspect --user-data-dir=$VSCODEUSERDATADIR +./scripts/code.sh $ROOT/extensions/markdown-language-features/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/markdown-language-features --extensionTestsPath=$ROOT/extensions/markdown-language-features/out/test --disable-extensions --skip-getting-started --disable-inspect --user-data-dir=$VSCODEUSERDATADIR mkdir -p $ROOT/extensions/emmet/test-fixtures -./scripts/code.sh $ROOT/extensions/emmet/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test --disable-extensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started +./scripts/code.sh $ROOT/extensions/emmet/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test --disable-extensions --skip-getting-started --disable-inspect --user-data-dir=$VSCODEUSERDATADIR rm -rf $ROOT/extensions/emmet/test-fixtures +if [ -f ./resources/server/test/test-remote-integration.sh ]; then + ./resources/server/test/test-remote-integration.sh +fi + # Tests in commonJS cd $ROOT/extensions/css-language-features/server && $ROOT/scripts/node-electron.sh test/index.js cd $ROOT/extensions/html-language-features/server && $ROOT/scripts/node-electron.sh test/index.js diff --git a/src/buildfile.js b/src/buildfile.js index 889763f49..0c77f1ae5 100644 --- a/src/buildfile.js +++ b/src/buildfile.js @@ -11,8 +11,16 @@ exports.base = [{ dest: 'vs/base/worker/workerMain.js' }]; +exports.serviceWorker = [{ + name: 'vs/workbench/contrib/resources/browser/resourceServiceWorker', + // include: ['vs/editor/common/services/editorSimpleWorker'], + prepend: ['vs/loader.js'], + append: ['vs/workbench/contrib/resources/browser/resourceServiceWorkerMain'], + dest: 'vs/workbench/contrib/resources/browser/resourceServiceWorkerMain.js' +}]; + exports.workbench = require('./vs/workbench/buildfile').collectModules(['vs/workbench/workbench.main']); -exports.workbenchNodeless = require('./vs/workbench/buildfile').collectModules(['vs/workbench/workbench.nodeless.main']); +exports.workbenchWeb = require('./vs/workbench/buildfile').collectModules(['vs/workbench/workbench.web.api']); exports.code = require('./vs/code/buildfile').collectModules(); diff --git a/src/main.js b/src/main.js index 186be5a80..6902f1d65 100644 --- a/src/main.js +++ b/src/main.js @@ -51,9 +51,11 @@ userDefinedLocale.then(locale => { } }); -// Configure command line switches +// Cached data const nodeCachedDataDir = getNodeCachedDir(); -configureCommandlineSwitches(args, nodeCachedDataDir); + +// Configure command line switches +configureCommandlineSwitches(args); // Load our code once ready app.once('ready', function () { @@ -134,31 +136,25 @@ function onReady() { * @typedef {import('minimist').ParsedArgs} ParsedArgs * * @param {ParsedArgs} cliArgs - * @param {{ jsFlags: () => string }} nodeCachedDataDir */ -function configureCommandlineSwitches(cliArgs, nodeCachedDataDir) { +function configureCommandlineSwitches(cliArgs) { // Force pre-Chrome-60 color profile handling (for https://github.com/Microsoft/vscode/issues/51791) app.commandLine.appendSwitch('disable-color-correct-rendering'); // Support JS Flags - const jsFlags = resolveJSFlags(cliArgs, nodeCachedDataDir.jsFlags()); + const jsFlags = getJSFlags(cliArgs); if (jsFlags) { app.commandLine.appendSwitch('--js-flags', jsFlags); } - - // Disable smooth scrolling for Webviews - if (cliArgs['disable-smooth-scrolling']) { - app.commandLine.appendSwitch('disable-smooth-scrolling'); - } } /** * @param {ParsedArgs} cliArgs - * @param {string[]} jsFlags * @returns {string} */ -function resolveJSFlags(cliArgs, ...jsFlags) { +function getJSFlags(cliArgs) { + const jsFlags = []; // Add any existing JS flags we already got from the command line if (cliArgs['js-flags']) { @@ -205,7 +201,7 @@ function parseCLIArgs() { function setCurrentWorkingDirectory() { try { if (process.platform === 'win32') { - process.env['VSCODE_CWD'] = process.cwd(); // remember as environment letiable + process.env['VSCODE_CWD'] = process.cwd(); // remember as environment variable process.chdir(path.dirname(app.getPath('exe'))); // always set application folder as cwd } else if (process.env['VSCODE_CWD']) { process.chdir(process.env['VSCODE_CWD']); @@ -253,7 +249,7 @@ function registerListeners() { } /** - * @returns {{ jsFlags: () => string; ensureExists: () => Promise, _compute: () => string; }} + * @returns {{ ensureExists: () => Promise }} */ function getNodeCachedDir() { return new class { @@ -262,11 +258,6 @@ function getNodeCachedDir() { this.value = this._compute(); } - jsFlags() { - // return this.value ? '--nolazy' : undefined; - return undefined; - } - ensureExists() { return bootstrap.mkdirp(this.value).then(() => this.value, () => { /*ignore*/ }); } @@ -347,4 +338,4 @@ function getUserDefinedLocale() { return undefined; }); } -//#endregion \ No newline at end of file +//#endregion diff --git a/src/tsconfig.base.json b/src/tsconfig.base.json index 627491de5..cfd4b390a 100644 --- a/src/tsconfig.base.json +++ b/src/tsconfig.base.json @@ -3,7 +3,6 @@ "module": "amd", "moduleResolution": "node", "noImplicitAny": true, - "suppressImplicitAnyIndexErrors": true, "target": "es5", "experimentalDecorators": true, "noImplicitReturns": true, diff --git a/src/tsconfig.json b/src/tsconfig.json index 25a1f449c..7fbb44c3e 100644 --- a/src/tsconfig.json +++ b/src/tsconfig.json @@ -9,7 +9,8 @@ "lib": [ "dom", "es5", - "es2015.iterable" + "es2015.iterable", + "webworker" ] }, "include": [ @@ -19,4 +20,4 @@ "exclude": [ "./typings/require-monaco.d.ts" ] -} \ No newline at end of file +} diff --git a/src/tsconfig.monaco.json b/src/tsconfig.monaco.json index afcbcaff3..329835037 100644 --- a/src/tsconfig.monaco.json +++ b/src/tsconfig.monaco.json @@ -10,7 +10,7 @@ "preserveConstEnums": true, "target": "es5", "sourceMap": false, - "declaration": true, + "declaration": true }, "include": [ "typings/require.d.ts", diff --git a/src/typings/chokidar.d.ts b/src/typings/chokidar.d.ts index 411080c2c..7f78ded23 100644 --- a/src/typings/chokidar.d.ts +++ b/src/typings/chokidar.d.ts @@ -5,84 +5,196 @@ declare module 'vscode-chokidar' { + // TypeScript Version: 3.0 + + import * as fs from "fs"; + import { EventEmitter } from "events"; + /** - * takes paths to be watched recursively and options + * The object's keys are all the directories (using absolute paths unless the `cwd` option was + * used), and the values are arrays of the names of the items contained in each directory. */ - export function watch(paths: string | string[], options: IOptions): FSWatcher; + export interface WatchedPaths { + [directory: string]: string[]; + } - export interface IOptions { + export class FSWatcher extends EventEmitter implements fs.FSWatcher { + + readonly options?: WatchOptions; /** - * (regexp or function) files to be ignored. This function or regexp is tested against the whole path, not just filename. - * If it is a function with two arguments, it gets called twice per path - once with a single argument (the path), second time with two arguments (the path and the fs.Stats object of that path). + * Constructs a new FSWatcher instance with optional WatchOptions parameter. */ - ignored?: any; + constructor(options?: WatchOptions); + + /** + * Add files, directories, or glob patterns for tracking. Takes an array of strings or just one + * string. + */ + add(paths: string | string[]): void; + + /** + * Stop watching files, directories, or glob patterns. Takes an array of strings or just one + * string. + */ + unwatch(paths: string | string[]): void; + + /** + * Returns an object representing all the paths on the file system being watched by this + * `FSWatcher` instance. The object's keys are all the directories (using absolute paths unless + * the `cwd` option was used), and the values are arrays of the names of the items contained in + * each directory. + */ + getWatched(): WatchedPaths; + + /** + * Removes all listeners from watched files. + */ + close(): void; + + on(event: 'add' | 'addDir' | 'change', listener: (path: string, stats?: fs.Stats) => void): this; + + on(event: 'all', listener: (eventName: 'add' | 'addDir' | 'change' | 'unlink' | 'unlinkDir', path: string, stats?: fs.Stats) => void): this; + + /** + * Error occured + */ + on(event: 'error', listener: (error: Error) => void): this; + + /** + * Exposes the native Node `fs.FSWatcher events` + */ + on(event: 'raw', listener: (eventName: string, path: string, details: any) => void): this; + + /** + * Fires when the initial scan is complete + */ + on(event: 'ready', listener: () => void): this; + + on(event: 'unlink' | 'unlinkDir', listener: (path: string) => void): this; + + on(event: string, listener: (...args: any[]) => void): this; + } + export interface WatchOptions { /** - * (default: false). Indicates whether the process should continue to run as long as files are being watched. + * Indicates whether the process should continue to run as long as files are being watched. If + * set to `false` when using `fsevents` to watch, no more events will be emitted after `ready`, + * even if the process continues to run. */ persistent?: boolean; /** - * (default: false). Indicates whether to watch files that don't have read permissions. + * ([anymatch](https://github.com/es128/anymatch)-compatible definition) Defines files/paths to + * be ignored. The whole relative or absolute path is tested, not just filename. If a function + * with two arguments is provided, it gets called twice per path - once with a single argument + * (the path), second time with two arguments (the path and the + * [`fs.Stats`](http://nodejs.org/api/fs.html#fs_class_fs_stats) object of that path). */ - ignorePermissionErrors?: boolean; + ignored?: any; /** - * (default: false). Indicates whether chokidar should ignore the initial add events or not. + * If set to `false` then `add`/`addDir` events are also emitted for matching paths while + * instantiating the watching as chokidar discovers these file paths (before the `ready` event). */ ignoreInitial?: boolean; /** - * (default: 100). Interval of file system polling. + * When `false`, only the symlinks themselves will be watched for changes instead of following + * the link references and bubbling events through the link's path. */ - interval?: number; + followSymlinks?: boolean; /** - * (default: 300). Interval of file system polling for binary files (see extensions in src/is-binary). + * The base directory from which watch `paths` are to be derived. Paths emitted with events will + * be relative to this. */ - binaryInterval?: number; + cwd?: string; + + /** + * If set to true then the strings passed to .watch() and .add() are treated as literal path + * names, even if they look like globs. Default: false. + */ + disableGlobbing?: boolean; /** - * (default: false on Windows, true on Linux and OS X). Whether to use fs.watchFile (backed by polling), or fs.watch. If polling leads to high CPU utilization, consider setting this to false. + * Whether to use fs.watchFile (backed by polling), or fs.watch. If polling leads to high CPU + * utilization, consider setting this to `false`. It is typically necessary to **set this to + * `true` to successfully watch files over a network**, and it may be necessary to successfully + * watch files in other non-standard situations. Setting to `true` explicitly on OS X overrides + * the `useFsEvents` default. */ usePolling?: boolean; /** - * (default: true on OS X). Whether to use the fsevents watching interface if available. When set to true explicitly and fsevents is available this supercedes the usePolling setting. When set to false on OS X, usePolling: true becomes the default. + * Whether to use the `fsevents` watching interface if available. When set to `true` explicitly + * and `fsevents` is available this supercedes the `usePolling` setting. When set to `false` on + * OS X, `usePolling: true` becomes the default. */ useFsEvents?: boolean; /** - * (default: true). When false, only the symlinks themselves will be watched for changes instead of following the link references and bubbling events through the link's path. + * If relying upon the [`fs.Stats`](http://nodejs.org/api/fs.html#fs_class_fs_stats) object that + * may get passed with `add`, `addDir`, and `change` events, set this to `true` to ensure it is + * provided even in cases where it wasn't already available from the underlying watch events. */ - followSymlinks?: boolean; + alwaysStat?: boolean; /** - * (default: false). If set to true then the strings passed to .watch() and .add() are treated as literal path names, even if they look like globs. + * If set, limits how many levels of subdirectories will be traversed. */ - disableGlobbing?: boolean; - } + depth?: number; + + /** + * Interval of file system polling. + */ + interval?: number; - export interface FSWatcher { + /** + * Interval of file system polling for binary files. ([see list of binary extensions](https://gi + * thub.com/sindresorhus/binary-extensions/blob/master/binary-extensions.json)) + */ + binaryInterval?: number; - add(fileDirOrGlob: string): void; - add(filesDirsOrGlobs: Array): void; + /** + * Indicates whether to watch files that don't have read permissions if possible. If watching + * fails due to `EPERM` or `EACCES` with this set to `true`, the errors will be suppressed + * silently. + */ + ignorePermissionErrors?: boolean; - unwatch(fileDirOrGlob: string): void; - unwatch(filesDirsOrGlobs: Array): void; + /** + * `true` if `useFsEvents` and `usePolling` are `false`). Automatically filters out artifacts + * that occur when using editors that use "atomic writes" instead of writing directly to the + * source file. If a file is re-added within 100 ms of being deleted, Chokidar emits a `change` + * event rather than `unlink` then `add`. If the default of 100 ms does not work well for you, + * you can override it by setting `atomic` to a custom value, in milliseconds. + */ + atomic?: boolean | number; /** - * Listen for an FS event. Available events: add, addDir, change, unlink, unlinkDir, error. Additionally all is available which gets emitted for every non-error event. + * can be set to an object in order to adjust timing params: */ - on(event: string, clb: (type: string, path: string) => void): void; - on(event: string, clb: (error: Error) => void): void; + awaitWriteFinish?: AwaitWriteFinishOptions | boolean; + } + export interface AwaitWriteFinishOptions { /** - * Removes all listeners from watched files. + * Amount of time in milliseconds for a file size to remain constant before emitting its event. */ - close(): void; + stabilityThreshold?: number; - options: IOptions; + /** + * File size polling interval. + */ + pollInterval?: number; } + + /** + * produces an instance of `FSWatcher`. + */ + export function watch( + paths: string | string[], + options?: WatchOptions + ): FSWatcher; } \ No newline at end of file diff --git a/src/typings/electron.d.ts b/src/typings/electron.d.ts index 20e58bcd7..5be0ac0e3 100644 --- a/src/typings/electron.d.ts +++ b/src/typings/electron.d.ts @@ -1,4 +1,4 @@ -// Type definitions for Electron 3.1.8 +// Type definitions for Electron 4.2.7 // Project: http://electronjs.org/ // Definitions by: The Electron Team // Definitions: https://github.com/electron/electron-typescript-definitions @@ -86,7 +86,7 @@ declare namespace Electron { webviewTag: WebviewTag; } - interface AllElectron extends MainInterface, RendererInterface {} + interface AllElectron extends MainInterface, RendererInterface { } const app: App; const autoUpdater: AutoUpdater; @@ -119,7 +119,7 @@ declare namespace Electron { interface App extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/app + // Docs: http://electronjs.org/docs/api/app /** * Emitted when Chrome's accessibility support changes. This event fires when @@ -472,6 +472,100 @@ declare namespace Electron { 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 remote.getBuiltin() is called in the renderer process of + * webContents. Calling event.preventDefault() will prevent the module from being + * returned. Custom value can be returned by setting event.returnValue. + */ + on(event: 'remote-get-builtin', listener: (event: Event, + webContents: WebContents, + moduleName: string) => void): this; + once(event: 'remote-get-builtin', listener: (event: Event, + webContents: WebContents, + moduleName: string) => void): this; + addListener(event: 'remote-get-builtin', listener: (event: Event, + webContents: WebContents, + moduleName: string) => void): this; + removeListener(event: 'remote-get-builtin', listener: (event: Event, + webContents: WebContents, + moduleName: string) => void): this; + /** + * Emitted when remote.getCurrentWebContents() is called in the renderer process of + * webContents. Calling event.preventDefault() will prevent the object from being + * returned. Custom value can be returned by setting event.returnValue. + */ + on(event: 'remote-get-current-web-contents', listener: (event: Event, + webContents: WebContents) => void): this; + once(event: 'remote-get-current-web-contents', listener: (event: Event, + webContents: WebContents) => void): this; + addListener(event: 'remote-get-current-web-contents', listener: (event: Event, + webContents: WebContents) => void): this; + removeListener(event: 'remote-get-current-web-contents', listener: (event: Event, + webContents: WebContents) => void): this; + /** + * Emitted when remote.getCurrentWindow() is called in the renderer process of + * webContents. Calling event.preventDefault() will prevent the object from being + * returned. Custom value can be returned by setting event.returnValue. + */ + on(event: 'remote-get-current-window', listener: (event: Event, + webContents: WebContents) => void): this; + once(event: 'remote-get-current-window', listener: (event: Event, + webContents: WebContents) => void): this; + addListener(event: 'remote-get-current-window', listener: (event: Event, + webContents: WebContents) => void): this; + removeListener(event: 'remote-get-current-window', listener: (event: Event, + webContents: WebContents) => void): this; + /** + * Emitted when remote.getGlobal() is called in the renderer process of + * webContents. Calling event.preventDefault() will prevent the global from being + * returned. Custom value can be returned by setting event.returnValue. + */ + on(event: 'remote-get-global', listener: (event: Event, + webContents: WebContents, + globalName: string) => void): this; + once(event: 'remote-get-global', listener: (event: Event, + webContents: WebContents, + globalName: string) => void): this; + addListener(event: 'remote-get-global', listener: (event: Event, + webContents: WebContents, + globalName: string) => void): this; + removeListener(event: 'remote-get-global', listener: (event: Event, + webContents: WebContents, + globalName: string) => void): this; + /** + * Emitted when .getWebContents() is called in the renderer process of + * webContents. Calling event.preventDefault() will prevent the object from being + * returned. Custom value can be returned by setting event.returnValue. + */ + on(event: 'remote-get-guest-web-contents', listener: (event: Event, + webContents: WebContents, + guestWebContents: WebContents) => void): this; + once(event: 'remote-get-guest-web-contents', listener: (event: Event, + webContents: WebContents, + guestWebContents: WebContents) => void): this; + addListener(event: 'remote-get-guest-web-contents', listener: (event: Event, + webContents: WebContents, + guestWebContents: WebContents) => void): this; + removeListener(event: 'remote-get-guest-web-contents', listener: (event: Event, + webContents: WebContents, + guestWebContents: WebContents) => void): this; + /** + * Emitted when remote.require() is called in the renderer process of webContents. + * Calling event.preventDefault() will prevent the module from being returned. + * Custom value can be returned by setting event.returnValue. + */ + on(event: 'remote-require', listener: (event: Event, + webContents: WebContents, + moduleName: string) => void): this; + once(event: 'remote-require', listener: (event: Event, + webContents: WebContents, + moduleName: string) => void): this; + addListener(event: 'remote-require', listener: (event: Event, + webContents: WebContents, + moduleName: string) => void): this; + removeListener(event: 'remote-require', listener: (event: Event, + webContents: WebContents, + moduleName: string) => void): this; /** * This event will be emitted inside the primary instance of your application when * a second instance has been executed. argv is an Array of the second instance's @@ -690,6 +784,11 @@ declare namespace Electron { * is ready. */ enableMixedSandbox(): void; + /** + * Enables full sandbox mode on the app. This method can only be called before app + * is ready. + */ + enableSandbox(): void; /** * 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 @@ -709,13 +808,22 @@ declare namespace Electron { * 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; + getFileIcon(path: string, 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; + getFileIcon(path: string, options: FileIconOptions, callback: (error: Error, icon: NativeImage) => void): void; getGPUFeatureStatus(): GPUFeatureStatus; + /** + * For infoType equal to complete: Promise is fulfilled with Object containing all + * the GPU Information as in chromium's GPUInfo object. This includes the version + * and driver information that's shown on chrome://gpu page. For infoType equal to + * basic: Promise is fulfilled with Object containing fewer attributes than when + * requested with complete. Here's an example of basic response: Using basic should + * be preferred if only basic information like vendorId or driverId is needed. + */ + getGPUInfo(infoType: string): Promise; getJumpListSettings(): JumpListSettings; /** * To set the locale, you'll want to use a command line switch at app startup, @@ -754,7 +862,7 @@ declare namespace Electron { /** * 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 + * success while any other value indicates failure according to Chromium * net_error_list. */ importCertificate(options: ImportCertificateOptions, callback: (result: number) => void): void; @@ -843,9 +951,9 @@ declare namespace Electron { setAboutPanelOptions(options: AboutPanelOptionsOptions): void; /** * Manually enables Chrome's accessibility support, allowing to expose - * accessibility switch to users in application settings. - * https://www.chromium.org/developers/design-documents/accessibility for more - * details. Disabled by default. Note: Rendering accessibility tree can + * accessibility switch to users in application settings. See Chromium's + * accessibility docs for more details. Disabled by default. This API must be + * called after the ready event is emitted. Note: Rendering accessibility tree can * significantly affect the performance of your app. It should not be enabled by * default. */ @@ -929,7 +1037,12 @@ declare namespace Electron { */ show(): void; /** - * Start accessing a security scoped resource. With this method electron + * Show the about panel with the values defined in the app's .plist file or with + * the options set via app.setAboutPanelOptions(options). + */ + showAboutPanel(): void; + /** + * Start accessing a security scoped resource. With this method Electron * applications that are packaged for the Mac App Store may reach outside their * sandbox to access files chosen by the user. See Apple's documentation for a * description of how this system works. @@ -940,7 +1053,7 @@ declare namespace Electron { * userInfo into its current userInfo dictionary. */ updateCurrentActivity(type: string, userInfo: any): void; - whenReady(): Promise; + whenReady(): Promise; commandLine: CommandLine; dock: Dock; /** @@ -949,11 +1062,19 @@ declare namespace Electron { * production environments. */ isPackaged?: boolean; + /** + * A String which is the user agent string Electron will use as a global fallback. + * This is the user agent that will be used when no user agent is set at the + * webContents or session level. Useful for ensuring your entire app has the same + * user agent. Set to a custom value as early as possible in your apps + * initialization to ensure that your overridden value is used. + */ + userAgentFallback?: string; } interface AutoUpdater extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/auto-updater + // Docs: http://electronjs.org/docs/api/auto-updater /** * This event is emitted after a user calls quitAndInstall(). When this API is @@ -990,7 +1111,9 @@ declare namespace Electron { removeListener(event: 'update-available', listener: Function): this; /** * Emitted when an update has been downloaded. On Windows only releaseName is - * available. + * available. Note: It is not strictly necessary to handle this event. A + * successfully downloaded update will still be applied the next time the + * application starts. */ on(event: 'update-downloaded', listener: (event: Event, releaseNotes: string, @@ -1029,10 +1152,10 @@ declare namespace Electron { * Restarts the app and installs the update after it has been downloaded. It should * only be called after update-downloaded has been emitted. Under the hood calling * autoUpdater.quitAndInstall() will close all application windows first, and - * automatically call app.quit() after all windows have been closed. Note: If the - * application is quit without calling this API after the update-downloaded event - * has been emitted, the application will still be replaced by the updated one on - * the next run. + * automatically call app.quit() after all windows have been closed. Note: It is + * not strictly necessary to call this function to apply an update, as a + * successfully downloaded update will always be applied the next time the + * application starts. */ quitAndInstall(): void; /** @@ -1043,7 +1166,7 @@ declare namespace Electron { interface BluetoothDevice { - // Docs: http://electron.atom.io/docs/api/structures/bluetooth-device + // Docs: http://electronjs.org/docs/api/structures/bluetooth-device deviceId: string; deviceName: string; @@ -1051,11 +1174,11 @@ declare namespace Electron { class BrowserView extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/browser-view + // Docs: http://electronjs.org/docs/api/browser-view constructor(options?: BrowserViewConstructorOptions); static fromId(id: number): BrowserView; - static fromWebContents(webContents: WebContents): BrowserView | null; + static fromWebContents(webContents: WebContents): (BrowserView) | (null); static getAllViews(): BrowserView[]; /** * Force closing the view, the unload and beforeunload events won't be emitted for @@ -1076,8 +1199,19 @@ declare namespace Electron { class BrowserWindow extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/browser-window + // Docs: http://electronjs.org/docs/api/browser-window + /** + * Emitted when the window is set or unset to show always on top of other windows. + */ + on(event: 'always-on-top-changed', listener: (event: Event, + isAlwaysOnTop: boolean) => void): this; + once(event: 'always-on-top-changed', listener: (event: Event, + isAlwaysOnTop: boolean) => void): this; + addListener(event: 'always-on-top-changed', listener: (event: Event, + isAlwaysOnTop: boolean) => void): this; + removeListener(event: 'always-on-top-changed', listener: (event: Event, + isAlwaysOnTop: boolean) => void): this; /** * 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 @@ -1204,16 +1338,21 @@ declare namespace Electron { 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. + * prevent the native window's title from changing. explicitSet is false when title + * is synthesized from file url. */ on(event: 'page-title-updated', listener: (event: Event, - title: string) => void): this; + title: string, + explicitSet: boolean) => void): this; once(event: 'page-title-updated', listener: (event: Event, - title: string) => void): this; + title: string, + explicitSet: boolean) => void): this; addListener(event: 'page-title-updated', listener: (event: Event, - title: string) => void): this; + title: string, + explicitSet: boolean) => void): this; removeListener(event: 'page-title-updated', listener: (event: Event, - title: string) => void): this; + title: string, + explicitSet: boolean) => void): this; /** * Emitted when the web page has been rendered (while not being shown) and window * can be displayed without a visual flash. @@ -1223,7 +1362,7 @@ declare namespace Electron { addListener(event: 'ready-to-show', listener: Function): this; removeListener(event: 'ready-to-show', listener: Function): this; /** - * Emitted when the window is being resized. + * Emitted after the window has been resized. */ on(event: 'resize', listener: Function): this; once(event: 'resize', listener: Function): this; @@ -1318,6 +1457,58 @@ declare namespace Electron { once(event: 'unresponsive', listener: Function): this; addListener(event: 'unresponsive', listener: Function): this; removeListener(event: 'unresponsive', listener: Function): this; + /** + * Emitted before the window is moved. Calling event.preventDefault() will prevent + * the window from being moved. Note that this is only emitted when the window is + * being resized manually. Resizing the window with setBounds/setSize will not emit + * this event. + */ + on(event: 'will-move', listener: (event: Event, + /** + * ` Location the window is being moved to. + */ + newBounds: Rectangle) => void): this; + once(event: 'will-move', listener: (event: Event, + /** + * ` Location the window is being moved to. + */ + newBounds: Rectangle) => void): this; + addListener(event: 'will-move', listener: (event: Event, + /** + * ` Location the window is being moved to. + */ + newBounds: Rectangle) => void): this; + removeListener(event: 'will-move', listener: (event: Event, + /** + * ` Location the window is being moved to. + */ + newBounds: Rectangle) => void): this; + /** + * Emitted before the window is resized. Calling event.preventDefault() will + * prevent the window from being resized. Note that this is only emitted when the + * window is being resized manually. Resizing the window with setBounds/setSize + * will not emit this event. + */ + on(event: 'will-resize', listener: (event: Event, + /** + * ` Size the window is being resized to. + */ + newBounds: Rectangle) => void): this; + once(event: 'will-resize', listener: (event: Event, + /** + * ` Size the window is being resized to. + */ + newBounds: Rectangle) => void): this; + addListener(event: 'will-resize', listener: (event: Event, + /** + * ` Size the window is being resized to. + */ + newBounds: Rectangle) => void): this; + removeListener(event: 'will-resize', listener: (event: Event, + /** + * ` Size the window is being resized to. + */ + newBounds: Rectangle) => void): this; constructor(options?: BrowserWindowConstructorOptions); /** * Adds DevTools extension located at path, and returns extension's name. The @@ -1335,7 +1526,7 @@ declare namespace Electron { * This API cannot be called before the ready event of the app module is emitted. */ static addExtension(path: string): void; - static fromBrowserView(browserView: BrowserView): BrowserWindow | null; + static fromBrowserView(browserView: BrowserView): (BrowserWindow) | (null); static fromId(id: number): BrowserWindow; static fromWebContents(webContents: WebContents): BrowserWindow; static getAllWindows(): BrowserWindow[]; @@ -1349,7 +1540,7 @@ declare namespace Electron { * emitted. */ static getExtensions(): Extensions; - static getFocusedWindow(): BrowserWindow | null; + static getFocusedWindow(): (BrowserWindow) | (null); /** * Remove a DevTools extension by name. Note: This API cannot be called before the * ready event of the app module is emitted. @@ -1411,7 +1602,7 @@ declare namespace Electron { * Note: The BrowserView API is currently experimental and may change or be removed * in future Electron releases. */ - getBrowserView(): BrowserView | null; + getBrowserView(): (BrowserView) | (null); getChildWindows(): BrowserWindow[]; getContentBounds(): Rectangle; getContentSize(): number[]; @@ -1422,6 +1613,13 @@ declare namespace Electron { * (unsigned long) on Linux. */ getNativeWindowHandle(): Buffer; + /** + * Note: whatever the current state of the window : maximized, minimized or in + * fullscreen, this function always returns the position and size of the window in + * normal state. In normal state, getBounds and getNormalBounds returns the same + * Rectangle. + */ + getNormalBounds(): Rectangle; getOpacity(): number; getParentWindow(): BrowserWindow; getPosition(): number[]; @@ -1473,6 +1671,7 @@ declare namespace Electron { * On Linux always returns true. */ isMovable(): boolean; + isNormal(): boolean; isResizable(): boolean; isSimpleFullScreen(): boolean; isVisible(): boolean; @@ -1485,7 +1684,7 @@ declare namespace Electron { * Same as webContents.loadFile, filePath should be a path to an HTML file relative * to the root of your application. See the webContents docs for more information. */ - loadFile(filePath: string): void; + loadFile(filePath: string, options?: LoadFileOptions): void; /** * 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 @@ -1579,7 +1778,12 @@ declare namespace Electron { */ setAutoHideMenuBar(hide: boolean): void; /** - * Resizes and moves the window to the supplied bounds + * Sets the background color of the window. See Setting backgroundColor. + */ + setBackgroundColor(backgroundColor: string): void; + /** + * Resizes and moves the window to the supplied bounds. Any properties that are not + * supplied will default to their current values. */ setBounds(bounds: Rectangle, animate?: boolean): void; setBrowserView(browserView: BrowserView): void; @@ -1655,7 +1859,7 @@ declare namespace Electron { * Sets the menu as the window's menu bar, setting it to null will remove the menu * bar. */ - setMenu(menu: Menu | null): void; + 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. @@ -1682,7 +1886,7 @@ declare namespace Electron { * 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 | null, description: string): void; + setOverlayIcon(overlay: (NativeImage) | (null), description: string): void; /** * Sets parent as current window's parent window, passing null will turn current * window into a top-level window. @@ -1754,7 +1958,8 @@ declare namespace Electron { /** * 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}. + * entire window by specifying an empty region: { x: 0, y: 0, width: 0, height: 0 + * }. */ setThumbnailClip(region: Rectangle): void; /** @@ -1782,7 +1987,12 @@ declare namespace Electron { * Sets whether the window should be visible on all workspaces. Note: This API does * nothing on Windows. */ - setVisibleOnAllWorkspaces(visible: boolean): void; + setVisibleOnAllWorkspaces(visible: boolean, options?: VisibleOnAllWorkspacesOptions): void; + /** + * Sets whether the window traffic light buttons should be visible. This cannot be + * called when titleBarStyle is set to customButtonsOnHover. + */ + setWindowButtonVisibility(visible: boolean): void; /** * Shows and gives focus to the window. */ @@ -1818,7 +2028,7 @@ declare namespace Electron { class BrowserWindowProxy extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/browser-window-proxy + // Docs: http://electronjs.org/docs/api/browser-window-proxy /** * Removes focus from the child window. @@ -1851,7 +2061,7 @@ declare namespace Electron { interface Certificate { - // Docs: http://electron.atom.io/docs/api/structures/certificate + // Docs: http://electronjs.org/docs/api/structures/certificate /** * PEM encoded data @@ -1897,37 +2107,37 @@ declare namespace Electron { interface CertificatePrincipal { - // Docs: http://electron.atom.io/docs/api/structures/certificate-principal + // Docs: http://electronjs.org/docs/api/structures/certificate-principal /** - * Common Name + * Common Name. */ commonName: string; /** - * Country or region + * Country or region. */ country: string; /** - * Locality + * Locality. */ locality: string; /** - * Organization names + * Organization names. */ organizations: string[]; /** - * Organization Unit names + * Organization Unit names. */ organizationUnits: string[]; /** - * State or province + * State or province. */ state: string; } class ClientRequest extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/client-request + // Docs: http://electronjs.org/docs/api/client-request /** * Emitted when the request is aborted. The abort event will not be fired if the @@ -2045,7 +2255,7 @@ declare namespace Electron { * 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; + end(chunk?: (string) | (Buffer), encoding?: string, callback?: Function): void; /** * Continues any deferred redirection request when the redirection mode is manual. */ @@ -2078,13 +2288,13 @@ declare namespace Electron { * 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; + write(chunk: (string) | (Buffer), encoding?: string, callback?: Function): void; chunkedEncoding: boolean; } interface Clipboard extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/clipboard + // Docs: http://electronjs.org/docs/api/clipboard availableFormats(type?: string): string[]; /** @@ -2144,7 +2354,7 @@ declare namespace Electron { interface ContentTracing extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/content-tracing + // Docs: http://electronjs.org/docs/api/content-tracing /** * Get the current monitoring traced data. Child processes typically cache trace @@ -2181,7 +2391,7 @@ declare namespace Electron { * request. The callback will be called once all child processes have acknowledged * the startRecording request. */ - startRecording(options: TraceCategoriesAndOptions | TraceConfig, callback: Function): void; + startRecording(options: (TraceCategoriesAndOptions) | (TraceConfig), callback: Function): void; /** * Stop monitoring on all processes. Once all child processes have acknowledged the * stopMonitoring request the callback is called. @@ -2203,10 +2413,11 @@ declare namespace Electron { interface Cookie { - // Docs: http://electron.atom.io/docs/api/structures/cookie + // Docs: http://electronjs.org/docs/api/structures/cookie /** - * The domain of the cookie. + * The domain of the cookie; this will be normalized with a preceding dot so that + * it's also valid for subdomains. */ domain?: string; /** @@ -2215,7 +2426,8 @@ declare namespace Electron { */ expirationDate?: number; /** - * Whether the cookie is a host-only cookie. + * Whether the cookie is a host-only cookie; this will only be true if no domain + * was passed. */ hostOnly?: boolean; /** @@ -2247,7 +2459,7 @@ declare namespace Electron { class Cookies extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/cookies + // Docs: http://electronjs.org/docs/api/cookies /** * Emitted when a cookie is changed because it was added, edited, removed, or @@ -2328,7 +2540,7 @@ declare namespace Electron { interface CPUUsage { - // Docs: http://electron.atom.io/docs/api/structures/cpu-usage + // Docs: http://electronjs.org/docs/api/structures/cpu-usage /** * The number of average idle cpu wakeups per second since the last call to @@ -2343,7 +2555,7 @@ declare namespace Electron { interface CrashReport { - // Docs: http://electron.atom.io/docs/api/structures/crash-report + // Docs: http://electronjs.org/docs/api/structures/crash-report date: Date; id: string; @@ -2351,7 +2563,7 @@ declare namespace Electron { interface CrashReporter extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/crash-reporter + // Docs: http://electronjs.org/docs/api/crash-reporter /** * Set an extra parameter to be sent with the crash report. The values specified @@ -2362,8 +2574,10 @@ declare namespace Electron { */ addExtraParameter(key: string, value: string): void; /** - * 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. + * Returns the date and ID of the last crash report. Only crash reports that have + * been uploaded will be returned; even if a crash report is present on disk it + * will not be returned until it is uploaded. In the case that there are no + * uploaded reports, null is returned. */ getLastCrashReport(): CrashReport; /** @@ -2419,7 +2633,7 @@ declare namespace Electron { class Debugger extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/debugger + // Docs: http://electronjs.org/docs/api/debugger /** * Emitted when debugging session is terminated. This happens either when @@ -2505,7 +2719,7 @@ declare namespace Electron { interface DesktopCapturer extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/desktop-capturer + // Docs: http://electronjs.org/docs/api/desktop-capturer /** * Starts gathering information about all available desktop media sources, and @@ -2518,7 +2732,7 @@ declare namespace Electron { interface DesktopCapturerSource { - // Docs: http://electron.atom.io/docs/api/structures/desktop-capturer-source + // Docs: http://electronjs.org/docs/api/structures/desktop-capturer-source /** * A unique identifier that will correspond to the id of the matching returned by @@ -2534,8 +2748,8 @@ declare namespace Electron { */ 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. + * 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; /** @@ -2549,7 +2763,7 @@ declare namespace Electron { interface Dialog extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/dialog + // Docs: http://electronjs.org/docs/api/dialog /** * On macOS, this displays a modal dialog that shows a message and certificate @@ -2610,7 +2824,7 @@ declare namespace Electron { * 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[], bookmarks: string[]) => void): string[]; + showOpenDialog(browserWindow: BrowserWindow, options: OpenDialogOptions, callback?: (filePaths: string[], bookmarks: string[]) => void): (string[]) | (undefined); /** * 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 @@ -2623,7 +2837,7 @@ declare namespace Electron { * 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[], bookmarks: string[]) => void): string[]; + showOpenDialog(options: OpenDialogOptions, callback?: (filePaths: string[], bookmarks: string[]) => void): (string[]) | (undefined); /** * 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 @@ -2631,7 +2845,7 @@ declare namespace Electron { * the API call will be asynchronous and the result will be passed via * callback(filename). */ - showSaveDialog(browserWindow: BrowserWindow, options: SaveDialogOptions, callback?: (filename: string, bookmark: string) => void): string; + showSaveDialog(browserWindow: BrowserWindow, options: SaveDialogOptions, callback?: (filename: string, bookmark: string) => void): (string) | (undefined); /** * 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 @@ -2639,12 +2853,12 @@ declare namespace Electron { * the API call will be asynchronous and the result will be passed via * callback(filename). */ - showSaveDialog(options: SaveDialogOptions, callback?: (filename: string, bookmark: string) => void): string; + showSaveDialog(options: SaveDialogOptions, callback?: (filename: string, bookmark: string) => void): (string) | (undefined); } interface Display { - // Docs: http://electron.atom.io/docs/api/structures/display + // Docs: http://electronjs.org/docs/api/structures/display bounds: Rectangle; /** @@ -2670,7 +2884,7 @@ declare namespace Electron { class DownloadItem extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/download-item + // Docs: http://electronjs.org/docs/api/download-item /** * Emitted when the download is in a terminal state. This includes a completed @@ -2773,7 +2987,7 @@ declare namespace Electron { interface FileFilter { - // Docs: http://electron.atom.io/docs/api/structures/file-filter + // Docs: http://electronjs.org/docs/api/structures/file-filter extensions: string[]; name: string; @@ -2781,7 +2995,7 @@ declare namespace Electron { interface GlobalShortcut extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/global-shortcut + // Docs: http://electronjs.org/docs/api/global-shortcut /** * When the accelerator is already taken by other applications, this call will @@ -2811,65 +3025,65 @@ declare namespace Electron { interface GPUFeatureStatus { - // Docs: http://electron.atom.io/docs/api/structures/gpu-feature-status + // Docs: http://electronjs.org/docs/api/structures/gpu-feature-status /** - * Canvas + * Canvas. */ '2d_canvas': string; /** - * Flash + * Flash. */ flash_3d: string; /** - * Flash Stage3D + * Flash Stage3D. */ flash_stage3d: string; /** - * Flash Stage3D Baseline profile + * Flash Stage3D Baseline profile. */ flash_stage3d_baseline: string; /** - * Compositing + * Compositing. */ gpu_compositing: string; /** - * Multiple Raster Threads + * Multiple Raster Threads. */ multiple_raster_threads: string; /** - * Native GpuMemoryBuffers + * Native GpuMemoryBuffers. */ native_gpu_memory_buffers: string; /** - * Rasterization + * Rasterization. */ rasterization: string; /** - * Video Decode + * Video Decode. */ video_decode: string; /** - * Video Encode + * Video Encode. */ video_encode: string; /** - * VPx Video Decode + * VPx Video Decode. */ vpx_decode: string; /** - * WebGL + * WebGL. */ webgl: string; /** - * WebGL2 + * WebGL2. */ webgl2: string; } interface InAppPurchase extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/in-app-purchase + // Docs: http://electronjs.org/docs/api/in-app-purchase /** * Emitted when one or more transactions have been updated. @@ -2917,7 +3131,7 @@ declare namespace Electron { class IncomingMessage extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/incoming-message + // Docs: http://electronjs.org/docs/api/incoming-message /** * Emitted when a request has been canceled during an ongoing HTTP transaction. @@ -2978,7 +3192,7 @@ declare namespace Electron { interface IOCounters { - // Docs: http://electron.atom.io/docs/api/structures/io-counters + // Docs: http://electronjs.org/docs/api/structures/io-counters /** * Then number of I/O other operations. @@ -3008,7 +3222,7 @@ declare namespace Electron { interface IpcMain extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/ipc-main + // Docs: http://electronjs.org/docs/api/ipc-main /** * Listens to channel, when a new message arrives listener would be called with @@ -3033,7 +3247,7 @@ declare namespace Electron { interface IpcRenderer extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/ipc-renderer + // Docs: http://electronjs.org/docs/api/ipc-renderer /** * Listens to channel, when a new message arrives listener would be called with @@ -3083,7 +3297,7 @@ declare namespace Electron { interface JumpListCategory { - // Docs: http://electron.atom.io/docs/api/structures/jump-list-category + // Docs: http://electronjs.org/docs/api/structures/jump-list-category /** * Array of objects if type is tasks or custom, otherwise it should be omitted. @@ -3101,7 +3315,7 @@ declare namespace Electron { interface JumpListItem { - // Docs: http://electron.atom.io/docs/api/structures/jump-list-item + // Docs: http://electronjs.org/docs/api/structures/jump-list-item /** * The command line arguments when program is executed. Should only be set if type @@ -3146,38 +3360,9 @@ declare namespace Electron { 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 + // Docs: http://electronjs.org/docs/api/structures/memory-usage-details count: number; liveSize: number; @@ -3186,7 +3371,7 @@ declare namespace Electron { class Menu { - // Docs: http://electron.atom.io/docs/api/menu + // Docs: http://electronjs.org/docs/api/menu /** * Emitted when a popup is closed either manually or with menu.closePopup(). @@ -3213,7 +3398,7 @@ declare namespace Electron { * 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 | null; + static getApplicationMenu(): (Menu) | (null); /** * Sends the action to the first responder of application. This is used for * emulating default macOS menu behaviors. Usually you would use the role property @@ -3227,7 +3412,7 @@ declare namespace Electron { * 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 | null): void; + static setApplicationMenu(menu: (Menu) | (null)): void; /** * Appends the menuItem to the menu. */ @@ -3244,13 +3429,13 @@ declare namespace Electron { /** * Pops up this menu as a context menu in the BrowserWindow. */ - popup(options: PopupOptions): void; + popup(options?: PopupOptions): void; items: MenuItem[]; } class MenuItem { - // Docs: http://electron.atom.io/docs/api/menu-item + // Docs: http://electronjs.org/docs/api/menu-item constructor(options: MenuItemConstructorOptions); checked: boolean; @@ -3262,21 +3447,21 @@ declare namespace Electron { interface MimeTypedBuffer { - // Docs: http://electron.atom.io/docs/api/structures/mime-typed-buffer + // Docs: http://electronjs.org/docs/api/structures/mime-typed-buffer /** - * The actual Buffer content + * The actual Buffer content. */ data: Buffer; /** - * The mimeType of the Buffer that you are sending + * The mimeType of the Buffer that you are sending. */ mimeType: string; } class NativeImage { - // Docs: http://electron.atom.io/docs/api/native-image + // Docs: http://electronjs.org/docs/api/native-image /** * Creates an empty NativeImage instance. @@ -3294,7 +3479,14 @@ declare namespace Electron { * Creates a new NativeImage instance from the NSImage that maps to the given image * name. See NSImageName for a list of possible values. The hslShift is applied to * the image with the following rules This means that [-1, 0, 1] will make the - * image completely white and [-1, 1, 0] will make the image completely black. + * image completely white and [-1, 1, 0] will make the image completely black. In + * some cases, the NSImageName doesn't match its string representation; one example + * of this is NSFolderImageName, whose string representation would actually be + * NSFolder. Therefore, you'll need to determine the correct string representation + * for your image before passing it in. This can be done with the following: echo + * -e '#import \nint main() { NSLog(@"%@", SYSTEM_IMAGE_NAME); }' | + * clang -otest -x objective-c -framework Cocoa - && ./test where SYSTEM_IMAGE_NAME + * should be replaced with any value from this list. */ static createFromNamedImage(imageName: string, hslShift: number[]): NativeImage; /** @@ -3343,7 +3535,7 @@ declare namespace Electron { interface Net extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/net + // Docs: http://electronjs.org/docs/api/net /** * Creates a ClientRequest instance using the provided options which are directly @@ -3351,12 +3543,12 @@ declare namespace Electron { * to issue both secure and insecure HTTP requests according to the specified * protocol scheme in the options object. */ - request(options: any | string): ClientRequest; + request(options: (any) | (string)): ClientRequest; } interface NetLog extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/net-log + // Docs: http://electronjs.org/docs/api/net-log /** * Starts recording network events to path. @@ -3379,7 +3571,7 @@ declare namespace Electron { class Notification extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/notification + // Docs: http://electronjs.org/docs/api/notification on(event: 'action', listener: (event: Event, /** @@ -3469,7 +3661,7 @@ declare namespace Electron { interface NotificationAction { - // Docs: http://electron.atom.io/docs/api/structures/notification-action + // Docs: http://electronjs.org/docs/api/structures/notification-action /** * The label for the given action. @@ -3483,7 +3675,7 @@ declare namespace Electron { interface Point { - // Docs: http://electron.atom.io/docs/api/structures/point + // Docs: http://electronjs.org/docs/api/structures/point x: number; y: number; @@ -3491,7 +3683,7 @@ declare namespace Electron { interface PowerMonitor extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/power-monitor + // Docs: http://electronjs.org/docs/api/power-monitor /** * Emitted when the system is about to lock the screen. @@ -3545,11 +3737,22 @@ declare namespace Electron { once(event: 'unlock-screen', listener: Function): this; addListener(event: 'unlock-screen', listener: Function): this; removeListener(event: 'unlock-screen', listener: Function): this; + /** + * Calculate the system idle state. idleThreshold is the amount of time (in + * seconds) before considered idle. callback will be called synchronously on some + * systems and with an idleState argument that describes the system's state. locked + * is available on supported systems only. + */ + querySystemIdleState(idleThreshold: number, callback: (idleState: 'active' | 'idle' | 'locked' | 'unknown') => void): void; + /** + * Calculate system idle time in seconds. + */ + querySystemIdleTime(callback: (idleTime: number) => void): void; } interface PowerSaveBlocker extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/power-save-blocker + // Docs: http://electronjs.org/docs/api/power-save-blocker isStarted(id: number): boolean; /** @@ -3571,7 +3774,7 @@ declare namespace Electron { interface PrinterInfo { - // Docs: http://electron.atom.io/docs/api/structures/printer-info + // Docs: http://electronjs.org/docs/api/structures/printer-info description: string; isDefault: boolean; @@ -3581,16 +3784,12 @@ declare namespace Electron { interface ProcessMetric { - // Docs: http://electron.atom.io/docs/api/structures/process-metric + // Docs: http://electronjs.org/docs/api/structures/process-metric /** * CPU usage of the process. */ cpu: CPUUsage; - /** - * Memory information for the process. - */ - memory: MemoryInfo; /** * Process id of the process. */ @@ -3603,7 +3802,7 @@ declare namespace Electron { interface Product { - // Docs: http://electron.atom.io/docs/api/structures/product + // Docs: http://electronjs.org/docs/api/structures/product /** * The total size of the content, in bytes. @@ -3642,7 +3841,7 @@ declare namespace Electron { interface Protocol extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/protocol + // Docs: http://electronjs.org/docs/api/protocol /** * Intercepts scheme protocol and uses handler as the protocol's new handler which @@ -3663,7 +3862,7 @@ declare namespace Electron { * Same as protocol.registerStreamProtocol, except that it replaces an existing * protocol handler. */ - interceptStreamProtocol(scheme: string, handler: (request: InterceptStreamProtocolRequest, callback: (stream?: ReadableStream | StreamProtocolResponse) => void) => void, completion?: (error: Error) => void): void; + interceptStreamProtocol(scheme: string, handler: (request: InterceptStreamProtocolRequest, callback: (stream?: (NodeJS.ReadableStream) | (StreamProtocolResponse)) => 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. @@ -3680,15 +3879,15 @@ declare namespace Electron { * 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; + 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 + * 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 @@ -3732,7 +3931,7 @@ declare namespace Electron { * that implements the readable stream API (emits data/end/error events). For * example, here's how a file could be returned: */ - registerStreamProtocol(scheme: string, handler: (request: RegisterStreamProtocolRequest, callback: (stream?: ReadableStream | StreamProtocolResponse) => void) => void, completion?: (error: Error) => void): void; + registerStreamProtocol(scheme: string, handler: (request: RegisterStreamProtocolRequest, callback: (stream?: (NodeJS.ReadableStream) | (StreamProtocolResponse)) => void) => void, completion?: (error: Error) => void): 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 @@ -3752,29 +3951,29 @@ declare namespace Electron { interface Rectangle { - // Docs: http://electron.atom.io/docs/api/structures/rectangle + // Docs: http://electronjs.org/docs/api/structures/rectangle /** - * The height of the rectangle (must be an integer) + * The height of the rectangle (must be an integer). */ height: number; /** - * The width of the rectangle (must be an integer) + * The width of the rectangle (must be an integer). */ width: number; /** - * The x coordinate of the origin of the rectangle (must be an integer) + * 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) + * The y coordinate of the origin of the rectangle (must be an integer). */ y: number; } interface Referrer { - // Docs: http://electron.atom.io/docs/api/structures/referrer + // Docs: http://electronjs.org/docs/api/structures/referrer /** * Can be default, unsafe-url, no-referrer-when-downgrade, no-referrer, origin, @@ -3790,7 +3989,7 @@ declare namespace Electron { interface Remote extends MainInterface { - // Docs: http://electron.atom.io/docs/api/remote + // Docs: http://electronjs.org/docs/api/remote getCurrentWebContents(): WebContents; /** @@ -3813,7 +4012,7 @@ declare namespace Electron { interface RemoveClientCertificate { - // Docs: http://electron.atom.io/docs/api/structures/remove-client-certificate + // Docs: http://electronjs.org/docs/api/structures/remove-client-certificate /** * Origin of the server whose associated client certificate must be removed from @@ -3828,7 +4027,7 @@ declare namespace Electron { interface RemovePassword { - // Docs: http://electron.atom.io/docs/api/structures/remove-password + // Docs: http://electronjs.org/docs/api/structures/remove-password /** * When provided, the authentication info related to the origin will only be @@ -3860,7 +4059,7 @@ declare namespace Electron { interface Screen extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/screen + // Docs: http://electronjs.org/docs/api/screen /** * Emitted when newDisplay has been added. @@ -3911,7 +4110,7 @@ declare namespace Electron { * relative to the display nearest to window. If window is null, scaling will be * performed to the display nearest to rect. */ - dipToScreenRect(window: BrowserWindow | null, rect: Rectangle): Rectangle; + dipToScreenRect(window: (BrowserWindow) | (null), rect: Rectangle): Rectangle; getAllDisplays(): Display[]; /** * The current absolute position of the mouse pointer. @@ -3930,44 +4129,44 @@ declare namespace Electron { * relative to the display nearest to window. If window is null, scaling will be * performed to the display nearest to rect. */ - screenToDipRect(window: BrowserWindow | null, rect: Rectangle): Rectangle; + screenToDipRect(window: (BrowserWindow) | (null), rect: Rectangle): Rectangle; } interface ScrubberItem { - // Docs: http://electron.atom.io/docs/api/structures/scrubber-item + // Docs: http://electronjs.org/docs/api/structures/scrubber-item /** - * The image to appear in this item + * The image to appear in this item. */ icon?: NativeImage; /** - * The text to appear in this item + * The text to appear in this item. */ label?: string; } interface SegmentedControlSegment { - // Docs: http://electron.atom.io/docs/api/structures/segmented-control-segment + // Docs: http://electronjs.org/docs/api/structures/segmented-control-segment /** - * Whether this segment is selectable. Default: true + * Whether this segment is selectable. Default: true. */ enabled?: boolean; /** - * The image to appear in this segment + * The image to appear in this segment. */ icon?: NativeImage; /** - * The text to appear in this segment + * The text to appear in this segment. */ label?: string; } class Session extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/session + // Docs: http://electronjs.org/docs/api/session /** * If partition starts with persist:, the page will use a persistent session @@ -4007,7 +4206,7 @@ declare namespace Electron { /** * Clears the session’s HTTP authentication cache. */ - clearAuthCache(options: RemovePassword | RemoveClientCertificate, callback?: Function): void; + clearAuthCache(options: (RemovePassword) | (RemoveClientCertificate), callback?: Function): void; /** * Clears the session’s HTTP cache. */ @@ -4066,12 +4265,18 @@ declare namespace Electron { * Downloads under the respective app folder. */ setDownloadPath(path: string): void; + /** + * Sets the handler which can be used to respond to permission checks for the + * session. Returning true will allow the permission and false will reject it. To + * clear the handler, call setPermissionCheckHandler(null). + */ + setPermissionCheckHandler(handler: ((webContents: WebContents, permission: string, requestingOrigin: string, details: PermissionCheckHandlerDetails) => boolean) | (null)): 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. To clear the handler, call setPermissionRequestHandler(null). */ - setPermissionRequestHandler(handler: (webContents: WebContents, permission: string, callback: (permissionGranted: boolean) => void, details: PermissionRequestHandlerDetails) => void | null): void; + setPermissionRequestHandler(handler: ((webContents: WebContents, permission: string, callback: (permissionGranted: boolean) => void, details: PermissionRequestHandlerDetails) => void) | (null)): void; /** * Adds scripts that will be executed on ALL web contents that are associated with * this session just before normal preload scripts run. @@ -4100,7 +4305,7 @@ declare namespace Electron { interface Shell { - // Docs: http://electron.atom.io/docs/api/shell + // Docs: http://electronjs.org/docs/api/shell /** * Play the beep sound. @@ -4140,7 +4345,7 @@ declare namespace Electron { interface ShortcutDetails { - // Docs: http://electron.atom.io/docs/api/structures/shortcut-details + // Docs: http://electronjs.org/docs/api/structures/shortcut-details /** * The Application User Model ID. Default is empty. @@ -4176,7 +4381,7 @@ declare namespace Electron { interface Size { - // Docs: http://electron.atom.io/docs/api/structures/size + // Docs: http://electronjs.org/docs/api/structures/size height: number; width: number; @@ -4184,25 +4389,25 @@ declare namespace Electron { interface StreamProtocolResponse { - // Docs: http://electron.atom.io/docs/api/structures/stream-protocol-response + // Docs: http://electronjs.org/docs/api/structures/stream-protocol-response /** - * A Node.js readable stream representing the response body + * A Node.js readable stream representing the response body. */ - data: ReadableStream; + data: NodeJS.ReadableStream; /** - * An object containing the response headers + * An object containing the response headers. */ headers: Headers; /** - * The HTTP response code + * The HTTP response code. */ statusCode: number; } interface SystemPreferences extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/system-preferences + // Docs: http://electronjs.org/docs/api/system-preferences on(event: 'accent-color-changed', listener: (event: Event, /** @@ -4252,8 +4457,41 @@ declare namespace Electron { * used, `false` otherwise. */ invertedColorScheme: boolean) => void): this; + /** + * Important: In order to properly leverage this API, you must set the + * NSMicrophoneUsageDescription and NSCameraUsageDescription strings in your app's + * Info.plist file. The values for these keys will be used to populate the + * permission dialogs so that the user will be properly informed as to the purpose + * of the permission request. See Electron Application Distribution for more + * information about how to set these in the context of Electron. This user consent + * was not required until macOS 10.14 Mojave, so this method will always return + * true if your system is running 10.13 High Sierra or lower. + */ + askForMediaAccess(mediaType: 'microphone' | 'camera'): Promise; getAccentColor(): string; + /** + * Gets the macOS appearance setting that you have declared you want for your + * application, maps to NSApplication.appearance. You can use the + * setAppLevelAppearance API to set this value. + */ + getAppLevelAppearance(): ('dark' | 'light' | 'unknown'); 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; + /** + * Gets the macOS appearance setting that is currently applied to your application, + * maps to NSApplication.effectiveAppearance Please note that until Electron is + * built targeting the 10.14 SDK, your application's effectiveAppearance will + * default to 'light' and won't inherit the OS preference. In the interim in order + * for your application to inherit the OS preference you must set the + * NSRequiresAquaSystemAppearance key in your apps Info.plist to false. If you are + * using electron-packager or electron-forge just set the enableDarwinDarkMode + * packager option to true. See the Electron Packager API for more details. + */ + getEffectiveAppearance(): ('dark' | 'light' | 'unknown'); + /** + * This user consent was not required until macOS 10.14 Mojave, so this method will + * always return granted if your system is running 10.13 High Sierra or lower. + */ + getMediaAccessStatus(mediaType: string): ('not-determined' | 'granted' | 'denied' | 'restricted' | 'unknown'); /** * Some popular key and types are: */ @@ -4266,6 +4504,7 @@ declare namespace Electron { isDarkMode(): boolean; isInvertedColorScheme(): boolean; isSwipeTrackingFromScrollEventsEnabled(): boolean; + isTrustedAccessibilityClient(prompt: boolean): boolean; /** * Posts event as native notifications of macOS. The userInfo is an Object that * contains the user information dictionary sent along with the notification. @@ -4290,6 +4529,11 @@ declare namespace Electron { * global value of a key previously set with setUserDefault. */ removeUserDefault(key: string): void; + /** + * Sets the appearance setting for your application, this should override the + * system default and override the value of getEffectiveAppearance. + */ + setAppLevelAppearance(appearance: 'dark' | 'light'): void; /** * Set the value of key in NSUserDefaults. Note that type should match actual type * of value. An exception is thrown if they don't. Some popular key and types are: @@ -4333,7 +4577,7 @@ declare namespace Electron { interface Task { - // Docs: http://electron.atom.io/docs/api/structures/task + // Docs: http://electronjs.org/docs/api/structures/task /** * The command line arguments when program is executed. @@ -4368,7 +4612,7 @@ declare namespace Electron { interface ThumbarButton { - // Docs: http://electron.atom.io/docs/api/structures/thumbar-button + // Docs: http://electronjs.org/docs/api/structures/thumbar-button click: Function; /** @@ -4388,7 +4632,7 @@ declare namespace Electron { class TouchBarButton extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/touch-bar-button + // Docs: http://electronjs.org/docs/api/touch-bar-button constructor(options: TouchBarButtonConstructorOptions); backgroundColor: string; @@ -4398,7 +4642,7 @@ declare namespace Electron { class TouchBarColorPicker extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/touch-bar-color-picker + // Docs: http://electronjs.org/docs/api/touch-bar-color-picker constructor(options: TouchBarColorPickerConstructorOptions); availableColors: string[]; @@ -4407,14 +4651,14 @@ declare namespace Electron { class TouchBarGroup extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/touch-bar-group + // Docs: http://electronjs.org/docs/api/touch-bar-group constructor(options: TouchBarGroupConstructorOptions); } class TouchBarLabel extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/touch-bar-label + // Docs: http://electronjs.org/docs/api/touch-bar-label constructor(options: TouchBarLabelConstructorOptions); label: string; @@ -4423,7 +4667,7 @@ declare namespace Electron { class TouchBarPopover extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/touch-bar-popover + // Docs: http://electronjs.org/docs/api/touch-bar-popover constructor(options: TouchBarPopoverConstructorOptions); icon: NativeImage; @@ -4432,7 +4676,7 @@ declare namespace Electron { class TouchBarScrubber extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/touch-bar-scrubber + // Docs: http://electronjs.org/docs/api/touch-bar-scrubber constructor(options: TouchBarScrubberConstructorOptions); continuous: boolean; @@ -4445,7 +4689,7 @@ declare namespace Electron { class TouchBarSegmentedControl extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/touch-bar-segmented-control + // Docs: http://electronjs.org/docs/api/touch-bar-segmented-control constructor(options: TouchBarSegmentedControlConstructorOptions); segments: SegmentedControlSegment[]; @@ -4455,7 +4699,7 @@ declare namespace Electron { class TouchBarSlider extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/touch-bar-slider + // Docs: http://electronjs.org/docs/api/touch-bar-slider constructor(options: TouchBarSliderConstructorOptions); label: string; @@ -4466,14 +4710,14 @@ declare namespace Electron { class TouchBarSpacer extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/touch-bar-spacer + // Docs: http://electronjs.org/docs/api/touch-bar-spacer constructor(options: TouchBarSpacerConstructorOptions); } class TouchBar extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/touch-bar + // Docs: http://electronjs.org/docs/api/touch-bar constructor(options: TouchBarConstructorOptions); escapeItem: (TouchBarButton | TouchBarColorPicker | TouchBarGroup | TouchBarLabel | TouchBarPopover | TouchBarScrubber | TouchBarSegmentedControl | TouchBarSlider | TouchBarSpacer | null); @@ -4490,7 +4734,7 @@ declare namespace Electron { interface TraceCategoriesAndOptions { - // Docs: http://electron.atom.io/docs/api/structures/trace-categories-and-options + // Docs: http://electronjs.org/docs/api/structures/trace-categories-and-options /** * – is a filter to control what category groups should be traced. A filter can @@ -4517,7 +4761,7 @@ declare namespace Electron { interface TraceConfig { - // Docs: http://electron.atom.io/docs/api/structures/trace-config + // Docs: http://electronjs.org/docs/api/structures/trace-config excluded_categories?: string[]; included_categories?: string[]; @@ -4526,7 +4770,7 @@ declare namespace Electron { interface Transaction { - // Docs: http://electron.atom.io/docs/api/structures/transaction + // Docs: http://electronjs.org/docs/api/structures/transaction /** * The error code if an error occurred while processing the transaction. @@ -4558,7 +4802,7 @@ declare namespace Electron { class Tray extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/tray + // Docs: http://electronjs.org/docs/api/tray /** * Emitted when the tray balloon is clicked. @@ -4810,7 +5054,7 @@ declare namespace Electron { * The bounds of tray icon. */ bounds: Rectangle) => void): this; - constructor(image: NativeImage | string); + constructor(image: (NativeImage) | (string)); /** * Destroys the tray icon immediately. */ @@ -4834,7 +5078,7 @@ declare namespace Electron { /** * Sets the context menu for this icon. */ - setContextMenu(menu: Menu | null): void; + setContextMenu(menu: (Menu) | (null)): 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 @@ -4850,11 +5094,11 @@ declare namespace Electron { /** * Sets the image associated with this tray icon. */ - setImage(image: NativeImage | string): void; + setImage(image: (NativeImage) | (string)): void; /** * Sets the image associated with this tray icon when pressed on macOS. */ - setPressedImage(image: NativeImage | string): void; + setPressedImage(image: (NativeImage) | (string)): void; /** * Sets the title displayed aside of the tray icon in the status bar (Support ANSI * colors). @@ -4868,7 +5112,7 @@ declare namespace Electron { interface UploadBlob { - // Docs: http://electron.atom.io/docs/api/structures/upload-blob + // Docs: http://electronjs.org/docs/api/structures/upload-blob /** * UUID of blob data to upload. @@ -4882,7 +5126,7 @@ declare namespace Electron { interface UploadData { - // Docs: http://electron.atom.io/docs/api/structures/upload-data + // Docs: http://electronjs.org/docs/api/structures/upload-data /** * UUID of blob data. Use method to retrieve the data. @@ -4900,7 +5144,7 @@ declare namespace Electron { interface UploadFile { - // Docs: http://electron.atom.io/docs/api/structures/upload-file + // Docs: http://electronjs.org/docs/api/structures/upload-file /** * Path of file to be uploaded. @@ -4926,7 +5170,7 @@ declare namespace Electron { interface UploadRawData { - // Docs: http://electron.atom.io/docs/api/structures/upload-raw-data + // Docs: http://electronjs.org/docs/api/structures/upload-raw-data /** * Data to be uploaded. @@ -4940,7 +5184,7 @@ declare namespace Electron { class WebContents extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/web-contents + // Docs: http://electronjs.org/docs/api/web-contents static fromId(id: number): WebContents; static getAllWebContents(): WebContents[]; @@ -5164,22 +5408,22 @@ declare namespace Electron { */ on(event: 'did-attach-webview', listener: (event: Event, /** - * The guest web contents that is used by the ``. + * The guest web contents that is used by the ` */ webContents: WebContents) => void): this; once(event: 'did-attach-webview', listener: (event: Event, /** - * The guest web contents that is used by the ``. + * The guest web contents that is used by the ` */ webContents: WebContents) => void): this; addListener(event: 'did-attach-webview', listener: (event: Event, /** - * The guest web contents that is used by the ``. + * The guest web contents that is used by the ` */ webContents: WebContents) => void): this; removeListener(event: 'did-attach-webview', listener: (event: Event, /** - * The guest web contents that is used by the ``. + * The guest web contents that is used by the ` */ webContents: WebContents) => void): this; /** @@ -5190,22 +5434,22 @@ declare namespace Electron { /** * Theme color is in format of '#rrggbb'. It is `null` when no theme color is set. */ - color: string | null) => void): this; + color: (string) | (null)) => void): this; once(event: 'did-change-theme-color', listener: (event: Event, /** * Theme color is in format of '#rrggbb'. It is `null` when no theme color is set. */ - color: string | null) => void): this; + color: (string) | (null)) => void): this; addListener(event: 'did-change-theme-color', listener: (event: Event, /** * Theme color is in format of '#rrggbb'. It is `null` when no theme color is set. */ - color: string | null) => void): this; + color: (string) | (null)) => void): this; removeListener(event: 'did-change-theme-color', listener: (event: Event, /** * Theme color is in format of '#rrggbb'. It is `null` when no theme color is set. */ - color: string | null) => void): this; + color: (string) | (null)) => void): 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 @@ -5394,6 +5638,35 @@ declare namespace Electron { isMainFrame: boolean, frameProcessId: number, frameRoutingId: number) => void): this; + /** + * Emitted after a server side redirect occurs during navigation. For example a + * 302 redirect. This event can not be prevented, if you want to prevent redirects + * you should checkout out the will-redirect event above. + */ + on(event: 'did-redirect-navigation', listener: (event: Event, + url: string, + isInPlace: boolean, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + once(event: 'did-redirect-navigation', listener: (event: Event, + url: string, + isInPlace: boolean, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + addListener(event: 'did-redirect-navigation', listener: (event: Event, + url: string, + isInPlace: boolean, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + removeListener(event: 'did-redirect-navigation', listener: (event: Event, + url: string, + isInPlace: boolean, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; /** * Corresponds to the points in time when the spinner of the tab started spinning. */ @@ -5405,22 +5678,26 @@ declare namespace Electron { * Emitted when any frame (including main) starts navigating. isInplace will be * true for in-page navigations. */ - on(event: 'did-start-navigation', listener: (url: string, + on(event: 'did-start-navigation', listener: (event: Event, + url: string, isInPlace: boolean, isMainFrame: boolean, frameProcessId: number, frameRoutingId: number) => void): this; - once(event: 'did-start-navigation', listener: (url: string, + once(event: 'did-start-navigation', listener: (event: Event, + url: string, isInPlace: boolean, isMainFrame: boolean, frameProcessId: number, frameRoutingId: number) => void): this; - addListener(event: 'did-start-navigation', listener: (url: string, + addListener(event: 'did-start-navigation', listener: (event: Event, + url: string, isInPlace: boolean, isMainFrame: boolean, frameProcessId: number, frameRoutingId: number) => void): this; - removeListener(event: 'did-start-navigation', listener: (url: string, + removeListener(event: 'did-start-navigation', listener: (event: Event, + url: string, isInPlace: boolean, isMainFrame: boolean, frameProcessId: number, @@ -5605,6 +5882,22 @@ declare namespace Electron { * Array of URLs. */ favicons: string[]) => void): this; + /** + * Fired when page title is set during navigation. explicitSet is false when title + * is synthesized from file url. + */ + on(event: 'page-title-updated', listener: (event: Event, + title: string, + explicitSet: boolean) => void): this; + once(event: 'page-title-updated', listener: (event: Event, + title: string, + explicitSet: boolean) => void): this; + addListener(event: 'page-title-updated', listener: (event: Event, + title: string, + explicitSet: boolean) => void): this; + removeListener(event: 'page-title-updated', listener: (event: Event, + title: string, + explicitSet: boolean) => void): this; /** * Emitted when a new frame is generated. Only the dirty area is passed in the * buffer. @@ -5648,6 +5941,76 @@ declare namespace Electron { removeListener(event: 'plugin-crashed', listener: (event: Event, name: string, version: string) => void): this; + /** + * Emitted when remote.getBuiltin() is called in the renderer process. Calling + * event.preventDefault() will prevent the module from being returned. Custom value + * can be returned by setting event.returnValue. + */ + on(event: 'remote-get-builtin', listener: (event: Event, + moduleName: string) => void): this; + once(event: 'remote-get-builtin', listener: (event: Event, + moduleName: string) => void): this; + addListener(event: 'remote-get-builtin', listener: (event: Event, + moduleName: string) => void): this; + removeListener(event: 'remote-get-builtin', listener: (event: Event, + moduleName: string) => void): this; + /** + * Emitted when remote.getCurrentWebContents() is called in the renderer process. + * Calling event.preventDefault() will prevent the object from being returned. + * Custom value can be returned by setting event.returnValue. + */ + on(event: 'remote-get-current-web-contents', listener: (event: Event) => void): this; + once(event: 'remote-get-current-web-contents', listener: (event: Event) => void): this; + addListener(event: 'remote-get-current-web-contents', listener: (event: Event) => void): this; + removeListener(event: 'remote-get-current-web-contents', listener: (event: Event) => void): this; + /** + * Emitted when remote.getCurrentWindow() is called in the renderer process. + * Calling event.preventDefault() will prevent the object from being returned. + * Custom value can be returned by setting event.returnValue. + */ + on(event: 'remote-get-current-window', listener: (event: Event) => void): this; + once(event: 'remote-get-current-window', listener: (event: Event) => void): this; + addListener(event: 'remote-get-current-window', listener: (event: Event) => void): this; + removeListener(event: 'remote-get-current-window', listener: (event: Event) => void): this; + /** + * Emitted when remote.getGlobal() is called in the renderer process. Calling + * event.preventDefault() will prevent the global from being returned. Custom value + * can be returned by setting event.returnValue. + */ + on(event: 'remote-get-global', listener: (event: Event, + globalName: string) => void): this; + once(event: 'remote-get-global', listener: (event: Event, + globalName: string) => void): this; + addListener(event: 'remote-get-global', listener: (event: Event, + globalName: string) => void): this; + removeListener(event: 'remote-get-global', listener: (event: Event, + globalName: string) => void): this; + /** + * Emitted when .getWebContents() is called in the renderer process. + * Calling event.preventDefault() will prevent the object from being returned. + * Custom value can be returned by setting event.returnValue. + */ + on(event: 'remote-get-guest-web-contents', listener: (event: Event, + guestWebContents: WebContents) => void): this; + once(event: 'remote-get-guest-web-contents', listener: (event: Event, + guestWebContents: WebContents) => void): this; + addListener(event: 'remote-get-guest-web-contents', listener: (event: Event, + guestWebContents: WebContents) => void): this; + removeListener(event: 'remote-get-guest-web-contents', listener: (event: Event, + guestWebContents: WebContents) => void): this; + /** + * Emitted when remote.require() is called in the renderer process. Calling + * event.preventDefault() will prevent the module from being returned. Custom value + * can be returned by setting event.returnValue. + */ + on(event: 'remote-require', listener: (event: Event, + moduleName: string) => void): this; + once(event: 'remote-require', listener: (event: Event, + moduleName: string) => void): this; + addListener(event: 'remote-require', listener: (event: Event, + moduleName: string) => void): this; + removeListener(event: 'remote-require', listener: (event: Event, + moduleName: string) => void): this; /** * Emitted when the unresponsive web page becomes responsive again. */ @@ -5727,8 +6090,7 @@ declare namespace Electron { */ webPreferences: any, /** - * The other `` parameters such as the `src` URL. This object can be - * modified to adjust the parameters of the guest page. + * The other ` */ params: any) => void): this; once(event: 'will-attach-webview', listener: (event: Event, @@ -5738,8 +6100,7 @@ declare namespace Electron { */ webPreferences: any, /** - * The other `` parameters such as the `src` URL. This object can be - * modified to adjust the parameters of the guest page. + * The other ` */ params: any) => void): this; addListener(event: 'will-attach-webview', listener: (event: Event, @@ -5749,8 +6110,7 @@ declare namespace Electron { */ webPreferences: any, /** - * The other `` parameters such as the `src` URL. This object can be - * modified to adjust the parameters of the guest page. + * The other ` */ params: any) => void): this; removeListener(event: 'will-attach-webview', listener: (event: Event, @@ -5760,8 +6120,7 @@ declare namespace Electron { */ webPreferences: any, /** - * The other `` parameters such as the `src` URL. This object can be - * modified to adjust the parameters of the guest page. + * The other ` */ params: any) => void): this; /** @@ -5790,6 +6149,36 @@ declare namespace Electron { 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; + /** + * Emitted as a server side redirect occurs during navigation. For example a 302 + * redirect. This event will be emitted after did-start-navigation and always + * before the did-redirect-navigation event for the same navigation. Calling + * event.preventDefault() will prevent the navigation (not just the redirect). + */ + on(event: 'will-redirect', listener: (event: Event, + url: string, + isInPlace: boolean, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + once(event: 'will-redirect', listener: (event: Event, + url: string, + isInPlace: boolean, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + addListener(event: 'will-redirect', listener: (event: Event, + url: string, + isInPlace: boolean, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; + removeListener(event: 'will-redirect', listener: (event: Event, + url: string, + isInPlace: boolean, + isMainFrame: boolean, + frameProcessId: number, + frameRoutingId: number) => void): this; /** * Adds the specified path to DevTools workspace. Must be used after DevTools * creation: @@ -5895,6 +6284,7 @@ declare namespace Electron { getPrinters(): PrinterInfo[]; getProcessId(): number; getTitle(): string; + getType(): ('backgroundPage' | 'window' | 'browserView' | 'remote' | 'webview' | 'offscreen'); getURL(): string; getUserAgent(): string; getWebRTCIPHandlingPolicy(): string; @@ -5953,6 +6343,7 @@ declare namespace Electron { invalidate(): void; isAudioMuted(): boolean; isCrashed(): boolean; + isCurrentlyAudible(): boolean; isDestroyed(): boolean; isDevToolsFocused(): boolean; isDevToolsOpened(): boolean; @@ -5967,7 +6358,7 @@ declare namespace Electron { * relative to the root of your application. For instance an app structure like * this: Would require code like this */ - loadFile(filePath: string): void; + loadFile(filePath: string, options?: LoadFileOptions): void; /** * 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 @@ -5992,8 +6383,8 @@ declare namespace Electron { * 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. + * 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, callback?: (success: boolean) => void): void; /** @@ -6054,6 +6445,11 @@ declare namespace Electron { * Mute the audio on the current web page. */ setAudioMuted(muted: boolean): void; + /** + * Controls whether or not this WebContents will throttle animations and timers + * when the page becomes backgrounded. This also affects the Page Visibility API. + */ + setBackgroundThrottling(allowed: boolean): void; /** * Uses the devToolsWebContents as the target WebContents to show devtools. The * devToolsWebContents must not have done any navigation, and it should not be used @@ -6131,6 +6527,10 @@ declare namespace Electron { * If offscreen rendering is enabled and painting, stop painting. */ stopPainting(): void; + /** + * Takes a V8 heap snapshot and saves it to filePath. + */ + takeHeapSnapshot(filePath: string): Promise; /** * Toggles the developer tools. */ @@ -6158,7 +6558,7 @@ declare namespace Electron { interface WebFrame extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/web-frame + // Docs: http://electronjs.org/docs/api/web-frame /** * Attempts to free memory that is no longer being used (like images from a @@ -6176,7 +6576,7 @@ declare namespace Electron { */ executeJavaScript(code: string, userGesture?: boolean, callback?: (result: any) => void): Promise; /** - * Work like executeJavaScript but evaluates scripts in isolated context. + * Work like executeJavaScript but evaluates scripts in an isolated context. */ executeJavaScriptInIsolatedWorld(worldId: number, scripts: WebSource[], userGesture?: boolean, callback?: (result: any) => void): void; findFrameByName(name: string): WebFrame; @@ -6279,7 +6679,7 @@ declare namespace Electron { class WebRequest extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/web-request + // Docs: http://electronjs.org/docs/api/web-request /** * The listener will be called with listener(details) when a server initiated @@ -6373,7 +6773,7 @@ declare namespace Electron { interface WebSource { - // Docs: http://electron.atom.io/docs/api/structures/web-source + // Docs: http://electronjs.org/docs/api/structures/web-source code: string; /** @@ -6385,7 +6785,7 @@ declare namespace Electron { interface WebviewTag extends HTMLElement { - // Docs: http://electron.atom.io/docs/api/webview-tag + // Docs: http://electronjs.org/docs/api/webview-tag /** * Fired when a load has committed. This includes navigation within the current @@ -6509,11 +6909,6 @@ declare namespace Electron { */ 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. */ @@ -6597,6 +6992,10 @@ declare namespace Electron { * Executes editing command delete in page. */ delete(): void; + /** + * Initiates a download of the resource at url without navigating. + */ + downloadURL(url: 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 @@ -6611,7 +7010,21 @@ declare namespace Electron { getTitle(): string; getURL(): string; getUserAgent(): string; + /** + * It depends on the remote module, it is therefore not available when this module + * is disabled. + */ getWebContents(): WebContents; + /** + * 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 guest page go back. */ @@ -6646,9 +7059,11 @@ declare namespace Electron { inspectServiceWorker(): void; isAudioMuted(): boolean; isCrashed(): boolean; + isCurrentlyAudible(): boolean; isDevToolsFocused(): boolean; isDevToolsOpened(): boolean; isLoading(): boolean; + isLoadingMainFrame(): boolean; isWaitingForResponse(): boolean; /** * Loads the url in the webview, the url must contain the protocol prefix, e.g. the @@ -6716,10 +7131,18 @@ declare namespace Electron { * Set guest page muted. */ setAudioMuted(muted: boolean): void; + /** + * Sets the maximum and minimum layout-based (i.e. non-visual) zoom level. + */ + setLayoutZoomLevelLimits(minimumLevel: number, maximumLevel: number): void; /** * Overrides the user agent for the guest page. */ setUserAgent(userAgent: string): 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. @@ -6728,7 +7151,8 @@ declare namespace Electron { /** * 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. + * limits of 300% and 50% of original size, respectively. The formula for this is + * scale := 1.2 ^ level. */ setZoomLevel(level: number): void; /** @@ -6781,6 +7205,11 @@ declare namespace Electron { * RuntimeEnabledFeatures.json5 file. */ enableblinkfeatures?: string; + /** + * When this attribute is false the guest page in webview will not have access to + * the remote module. The remote module is avaiable by default. + */ + enableremotemodule?: string; /** * Sets the referrer URL for the guest page. */ @@ -7054,7 +7483,7 @@ declare namespace Electron { * visual effects, you can also leave it undefined so the executable's icon will be * used. */ - icon?: NativeImage | string; + icon?: (NativeImage) | (string); /** * Whether window should be shown when created. Default is true. */ @@ -7091,9 +7520,8 @@ declare namespace Electron { enableLargerThanScreen?: boolean; /** * Window's background color as a hexadecimal value, like #66CD00 or #FFF or - * #80FFFFFF (alpha is supported). Default is #FFF (white). If transparent is set - * to true, only values with transparent (#00-------) or opaque (#FF-----) alpha - * values are respected. + * #80FFFFFF (alpha is supported if transparent is set to true). Default is #FFF + * (white). */ backgroundColor?: string; /** @@ -7320,7 +7748,7 @@ declare namespace Electron { } interface CrashReporterStartOptions { - companyName?: string; + companyName: string; /** * URL that crash reports will be sent to as POST. */ @@ -7422,7 +7850,8 @@ declare namespace Electron { */ value?: string; /** - * The domain of the cookie. Empty by default if omitted. + * The domain of the cookie; this will be normalized with a preceding dot so that + * it's also valid for subdomains. Empty by default if omitted. */ domain?: string; /** @@ -7476,7 +7905,7 @@ declare namespace Electron { /** * - */ - icon?: NativeImage | string; + icon?: (NativeImage) | (string); title: string; content: string; } @@ -7518,7 +7947,7 @@ declare namespace Electron { /** * Sets the image associated with this dock icon. */ - setIcon: (image: NativeImage | string) => void; + setIcon: (image: (NativeImage) | (string)) => void; } interface EnableNetworkEmulationOptions { @@ -7716,6 +8145,7 @@ declare namespace Electron { interface InterceptHttpProtocolRequest { url: string; + headers: Headers; referrer: string; method: string; uploadData: UploadData[]; @@ -7772,11 +8202,26 @@ declare namespace Electron { isMainFrame: boolean; } + interface LoadFileOptions { + /** + * Passed to url.format(). + */ + query?: Query; + /** + * Passed to url.format(). + */ + search?: string; + /** + * Passed to url.format(). + */ + hash?: string; + } + interface LoadURLOptions { /** * An HTTP Referrer url. */ - httpReferrer?: string | Referrer; + httpReferrer?: (string) | (Referrer); /** * A user agent originating the request. */ @@ -7785,7 +8230,7 @@ declare namespace Electron { * Extra headers separated by "\n" */ extraHeaders?: string; - postData?: UploadRawData[] | UploadFile[] | UploadBlob[]; + postData?: (UploadRawData[]) | (UploadFile[]) | (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 @@ -7856,7 +8301,7 @@ declare namespace Electron { label?: string; sublabel?: string; accelerator?: Accelerator; - icon?: NativeImage | string; + icon?: (NativeImage) | (string); /** * If false, the menu item will be greyed out and unclickable. */ @@ -7879,17 +8324,36 @@ declare namespace Electron { * type: 'submenu' can be omitted. If the value is not a then it will be * automatically converted to one using Menu.buildFromTemplate. */ - submenu?: MenuItemConstructorOptions[] | Menu; + 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. + * Inserts this item before the item with the specified label. If the referenced + * item doesn't exist the item will be inserted at the end of the menu. Also + * implies that the menu item in question should be placed in the same “group” as + * the item. */ - position?: string; + before?: string[]; + /** + * Inserts this item after the item with the specified label. If the referenced + * item doesn't exist the item will be inserted at the end of the menu. + */ + after?: string[]; + /** + * Provides a means for a single context menu to declare the placement of their + * containing group before the containing group of the item with the specified + * label. + */ + beforeGroupContaining?: string[]; + /** + * Provides a means for a single context menu to declare the placement of their + * containing group after the containing group of the item with the specified + * label. + */ + afterGroupContaining?: string[]; } interface MessageBoxOptions { @@ -7935,7 +8399,7 @@ declare namespace Electron { * 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. + * the return value or callback response. */ cancelId?: number; /** @@ -7993,7 +8457,7 @@ declare namespace Electron { /** * An icon to use in the notification. */ - icon?: string | NativeImage; + icon?: (string) | (NativeImage); /** * Whether or not to add an inline reply option to the notification. */ @@ -8093,6 +8557,7 @@ declare namespace Electron { method: string; webContentsId?: number; resourceType: string; + referrer: string; timestamp: number; responseHeaders: ResponseHeaders; fromCache: boolean; @@ -8151,7 +8616,7 @@ declare namespace Electron { } interface OnHeadersReceivedResponse { - cancel: boolean; + cancel?: boolean; /** * When provided, the server is assumed to have responded with these headers. */ @@ -8242,7 +8707,11 @@ declare namespace Electron { /** * true to bring the opened application to the foreground. The default is true. */ - activate: boolean; + activate?: boolean; + /** + * The working directory. + */ + workingDirectory?: string; } interface PageFaviconUpdatedEvent extends Event { @@ -8267,8 +8736,8 @@ declare namespace Electron { */ 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; /** @@ -8298,11 +8767,42 @@ declare namespace Electron { quantity: number; } + interface PermissionCheckHandlerDetails { + /** + * The security orign of the media check. + */ + securityOrigin: string; + /** + * The type of media access being requested, can be video, audio or unknown + */ + mediaType: ('video' | 'audio' | 'unknown'); + /** + * The last URL the requesting frame loaded + */ + requestingUrl: string; + /** + * Whether the frame making the request is the main frame + */ + isMainFrame: boolean; + } + interface PermissionRequestHandlerDetails { /** * The url of the openExternal request. */ - externalURL: string; + externalURL?: string; + /** + * The types of media access being requested, elements can be video or audio + */ + mediaTypes?: Array<'video' | 'audio'>; + /** + * The last URL the requesting frame loaded + */ + requestingUrl: string; + /** + * Whether the frame making the request is the main frame + */ + isMainFrame: boolean; } interface PluginCrashedEvent extends Event { @@ -8359,7 +8859,7 @@ declare namespace Electron { * Specify page size of the generated PDF. Can be A3, A4, A5, Legal, Letter, * Tabloid or an Object containing height and width in microns. */ - pageSize?: string | Size; + pageSize?: (string) | (Size); /** * Whether to print CSS backgrounds. */ @@ -8376,23 +8876,19 @@ declare namespace Electron { interface ProcessMemoryInfo { /** - * The amount of memory currently pinned to actual physical RAM. - */ - workingSetSize: number; - /** - * The maximum amount of memory that has ever been pinned to actual physical RAM. + * and The amount of memory currently pinned to actual physical RAM in Kilobytes. */ - peakWorkingSetSize: number; + residentSet: number; /** * The amount of memory not shared by other processes, such as JS heap or HTML - * content. + * content in Kilobytes. */ - privateBytes: number; + private: number; /** * The amount of memory shared between processes, typically memory consumed by the - * Electron code itself. + * Electron code itself in Kilobytes. */ - sharedBytes: number; + shared: number; } interface ProgressBarOptions { @@ -8437,6 +8933,7 @@ declare namespace Electron { interface RegisterHttpProtocolRequest { url: string; + headers: Headers; referrer: string; method: string; uploadData: UploadData[]; @@ -8704,8 +9201,8 @@ declare namespace Electron { } interface TouchBarConstructorOptions { - items: Array; - escapeItem?: TouchBarButton | TouchBarColorPicker | TouchBarGroup | TouchBarLabel | TouchBarPopover | TouchBarScrubber | TouchBarSegmentedControl | TouchBarSlider | TouchBarSpacer | null; + items: Array<(TouchBarButton) | (TouchBarColorPicker) | (TouchBarGroup) | (TouchBarLabel) | (TouchBarPopover) | (TouchBarScrubber) | (TouchBarSegmentedControl) | (TouchBarSlider) | (TouchBarSpacer)>; + escapeItem?: (TouchBarButton) | (TouchBarColorPicker) | (TouchBarGroup) | (TouchBarLabel) | (TouchBarPopover) | (TouchBarScrubber) | (TouchBarSegmentedControl) | (TouchBarSlider) | (TouchBarSpacer) | (null); } interface TouchBarGroupConstructorOptions { @@ -8871,6 +9368,13 @@ declare namespace Electron { electron?: string; } + interface VisibleOnAllWorkspacesOptions { + /** + * Sets whether the window should be visible above fullscreen windows + */ + visibleOnFullScreen?: boolean; + } + interface WillNavigateEvent extends Event { url: string; } @@ -8964,6 +9468,9 @@ declare namespace Electron { interface Options { } + interface Query { + } + interface RequestHeaders { } @@ -9004,6 +9511,10 @@ declare namespace Electron { * currently experimental and may change or be removed in future Electron releases. */ sandbox?: boolean; + /** + * Whether to enable the module. Default is true. + */ + enableRemoteModule?: 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 @@ -9072,10 +9583,6 @@ declare namespace Electron { * Enables Chromium's experimental features. Default is false. */ // experimentalFeatures?: boolean; ### VSCODE CHANGE (https://github.com/electron/electron/blob/master/docs/tutorial/security.md) ### - /** - * Enables Chromium's experimental canvas features. Default is false. - */ - experimentalCanvasFeatures?: boolean; /** * Enables scroll bounce (rubber banding) effect on macOS. Default is false. */ @@ -9131,8 +9638,7 @@ declare namespace Electron { * 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. + * Context' entry in the combo box at the top of the Console tab. */ contextIsolation?: boolean; /** @@ -9144,11 +9650,11 @@ declare namespace Electron { 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 + * 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. + * alter the 's initial settings. */ webviewTag?: boolean; /** @@ -9230,7 +9736,7 @@ interface Document { declare namespace NodeJS { interface Process extends EventEmitter { - // Docs: http://electron.atom.io/docs/api/process + // Docs: http://electronjs.org/docs/api/process // ### BEGIN VSCODE MODIFICATION ### // /** @@ -9250,6 +9756,12 @@ declare namespace NodeJS { */ crash(): void; getCPUUsage(): Electron.CPUUsage; + /** + * Indicates the creation time of the application. The time is represented as + * number of milliseconds since epoch. It returns null if it is unable to get the + * process creation time. + */ + getCreationTime(): (number) | (null); /** * Returns an object with V8 heap statistics. Note that all statistics are reported * in Kilobytes. @@ -9258,7 +9770,12 @@ declare namespace NodeJS { getIOCounters(): Electron.IOCounters; /** * Returns an object giving memory usage statistics about the current process. Note - * that all statistics are reported in Kilobytes. + * that all statistics are reported in Kilobytes. This api should be called after + * app ready. Chromium does not provide residentSet value for macOS. This is + * because macOS performs in-memory compression of pages that haven't been recently + * used. As a result the resident set size value is not what one would expect. + * private memory is more representative of the actual pre-compression memory usage + * of the process on macOS. */ getProcessMemoryInfo(): Electron.ProcessMemoryInfo; /** @@ -9275,6 +9792,10 @@ declare namespace NodeJS { * whichever is lower for the current process. */ setFdLimit(maxDescriptors: number): void; + /** + * Takes a V8 heap snapshot and saves it to filePath. + */ + takeHeapSnapshot(filePath: string): boolean; /** * 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. @@ -9300,6 +9821,11 @@ declare namespace NodeJS { * A String representing the path to the resources directory. */ resourcesPath?: string; + /** + * A Boolean. When the renderer process is sandboxed, this property is true, + * otherwise it is undefined. + */ + sandboxed?: boolean; /** * A Boolean that controls whether or not deprecation warnings will be thrown as * exceptions. Setting this to true will throw errors for deprecations. This @@ -9335,4 +9861,4 @@ declare namespace NodeJS { electron: string; chrome: string; } -} +} \ No newline at end of file diff --git a/src/typings/gc-signals.d.ts b/src/typings/gc-signals.d.ts deleted file mode 100644 index 15af04117..000000000 --- a/src/typings/gc-signals.d.ts +++ /dev/null @@ -1,19 +0,0 @@ -declare module 'gc-signals' { - export interface GCSignal { - } - /** - * Create a new GC signal. When being garbage collected the passed - * value is stored for later consumption. - */ - export const GCSignal: { - new(id: number): GCSignal; - }; - /** - * Consume ids of garbage collected signals. - */ - export function consumeSignals(): number[]; - export function onDidGarbageCollectSignals(callback: (ids: number[]) => any): { - dispose(): void; - }; - export function trackGarbageCollection(obj: any, id: number): number; -} \ No newline at end of file diff --git a/src/typings/getmac.d.ts b/src/typings/getmac.d.ts deleted file mode 100644 index e93b81354..000000000 --- a/src/typings/getmac.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -declare module getmac { - export function getMac(callback: (error: Error, macAddress: string) => void): void; -} - -declare module 'getmac' { - export = getmac; -} \ No newline at end of file diff --git a/src/typings/lib.array-ext.d.ts b/src/typings/lib.array-ext.d.ts index 127f64e1f..5a77b70a9 100644 --- a/src/typings/lib.array-ext.d.ts +++ b/src/typings/lib.array-ext.d.ts @@ -4,6 +4,8 @@ *--------------------------------------------------------------------------------------------*/ interface ArrayConstructor { + isArray(arg: ReadonlyArray | null | undefined): arg is ReadonlyArray; + isArray(arg: Array | null | undefined): arg is Array; isArray(arg: any): arg is Array; isArray(arg: any): arg is Array; } \ No newline at end of file diff --git a/src/typings/node-pty.d.ts b/src/typings/node-pty.d.ts index 8eeb51e3b..2e6d6cfdc 100644 --- a/src/typings/node-pty.d.ts +++ b/src/typings/node-pty.d.ts @@ -1,5 +1,6 @@ /** * Copyright (c) 2017, Daniel Imms (MIT License). + * Copyright (c) 2018, Microsoft Corporation (MIT License). */ declare module 'node-pty' { @@ -11,76 +12,132 @@ declare module 'node-pty' { * escaped properly. * @param options The options of the terminal. * @see CommandLineToArgvW https://msdn.microsoft.com/en-us/library/windows/desktop/bb776391(v=vs.85).aspx - * @see Parsing C++ Command-Line Arguments https://msdn.microsoft.com/en-us/library/17w5ykft.aspx + * @see Parsing C++ Comamnd-Line Arguments https://msdn.microsoft.com/en-us/library/17w5ykft.aspx * @see GetCommandLine https://msdn.microsoft.com/en-us/library/windows/desktop/ms683156.aspx */ - export function spawn(file: string, args: string[] | string, options: IPtyForkOptions): IPty; + export function spawn(file: string, args: string[] | string, options: IPtyForkOptions | IWindowsPtyForkOptions): IPty; export interface IPtyForkOptions { - name?: string; - cols?: number; - rows?: number; - cwd?: string; - env?: { [key: string]: string }; - uid?: number; - gid?: number; - encoding?: string; - /** - * Whether to use the experimental ConPTY system on Windows. This setting will be ignored on - * non-Windows. - */ - experimentalUseConpty?: boolean; + name?: string; + cols?: number; + rows?: number; + cwd?: string; + env?: { [key: string]: string }; + uid?: number; + gid?: number; + encoding?: string; + } + + export interface IWindowsPtyForkOptions { + name?: string; + cols?: number; + rows?: number; + cwd?: string; + env?: { [key: string]: string }; + encoding?: string; + /** + * Whether to use the experimental ConPTY system on Windows. When this is not set, ConPTY will + * be used when the Windows build number is >= 18309 (it's available in 17134 and 17692 but is + * too unstable to enable by default). + * + * This setting does nothing on non-Windows. + */ + experimentalUseConpty?: boolean; + /** + * Whether to use PSEUDOCONSOLE_INHERIT_CURSOR in conpty. + * @see https://docs.microsoft.com/en-us/windows/console/createpseudoconsole + */ + conptyInheritCursor?: boolean; } /** * An interface representing a pseudoterminal, on Windows this is emulated via the winpty library. */ export interface IPty { - /** - * The process ID of the outer process. - */ - pid: number; - - /** - * The title of the active process. - */ - process: string; - - /** - * Adds a listener to the data event, fired when data is returned from the pty. - * @param event The name of the event. - * @param listener The callback function. - */ - on(event: 'data', listener: (data: string) => void): void; - - /** - * Adds a listener to the exit event, fired when the pty exits. - * @param event The name of the event. - * @param listener The callback function, exitCode is the exit code of the process and signal is - * the signal that triggered the exit. signal is not supported on Windows. - */ - on(event: 'exit', listener: (exitCode: number, signal?: number) => void): void; - - /** - * Resizes the dimensions of the pty. - * @param columns The number of columns to use. - * @param rows The number of rows to use. - */ - resize(columns: number, rows: number): void; - - /** - * Writes data to the pty. - * @param data The data to write. - */ - write(data: string): void; - - /** - * Kills the pty. - * @param signal The signal to use, defaults to SIGHUP. If the TIOCSIG/TIOCSIGNAL ioctl is not - * supported then the process will be killed instead. This parameter is not supported on - * Windows. - * @throws Will throw when signal is used on Windows. - */ - kill(signal?: string): void; + /** + * The process ID of the outer process. + */ + readonly pid: number; + + /** + * The column size in characters. + */ + readonly cols: number; + + /** + * The row size in characters. + */ + readonly rows: number; + + /** + * The title of the active process. + */ + readonly process: string; + + /** + * Adds an event listener for when a data event fires. This happens when data is returned from + * the pty. + * @returns an `IDisposable` to stop listening. + */ + readonly onData: IEvent; + + /** + * Adds an event listener for when an exit event fires. This happens when the pty exits. + * @returns an `IDisposable` to stop listening. + */ + readonly onExit: IEvent<{ exitCode: number, signal?: number }>; + + /** + * Adds a listener to the data event, fired when data is returned from the pty. + * @param event The name of the event. + * @param listener The callback function. + * @deprecated Use IPty.onData + */ + on(event: 'data', listener: (data: string) => void): void; + + /** + * Adds a listener to the exit event, fired when the pty exits. + * @param event The name of the event. + * @param listener The callback function, exitCode is the exit code of the process and signal is + * the signal that triggered the exit. signal is not supported on Windows. + * @deprecated Use IPty.onExit + */ + on(event: 'exit', listener: (exitCode: number, signal?: number) => void): void; + + /** + * Resizes the dimensions of the pty. + * @param columns THe number of columns to use. + * @param rows The number of rows to use. + */ + resize(columns: number, rows: number): void; + + /** + * Writes data to the pty. + * @param data The data to write. + */ + write(data: string): void; + + /** + * Kills the pty. + * @param signal The signal to use, defaults to SIGHUP. This parameter is not supported on + * Windows. + * @throws Will throw when signal is used on Windows. + */ + kill(signal?: string): void; + } + + /** + * An object that can be disposed via a dispose function. + */ + export interface IDisposable { + dispose(): void; + } + + /** + * An event that can be listened to. + * @returns an `IDisposable` to stop listening. + */ + export interface IEvent { + (listener: (e: T) => any): IDisposable; } - } \ No newline at end of file +} diff --git a/src/typings/nsfw.d.ts b/src/typings/nsfw.d.ts new file mode 100644 index 000000000..f8bb423a2 --- /dev/null +++ b/src/typings/nsfw.d.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. + *--------------------------------------------------------------------------------------------*/ + +declare module 'nsfw' { + interface NsfwWatcher { + start(): any; + stop(): any; + } + + interface NsfwWatchingPromise { + then(): void; + } + + interface NsfwStartWatchingPromise { + then(fn: (watcher: NsfwWatcher) => void): NsfwWatchingPromise; + } + + interface NsfwEvent { + action: number; + directory: string; + file?: string; + newFile?: string; + newDirectory?: string; + oldFile?: string; + } + + interface NsfwFunction { + (dir: string, eventHandler: (events: NsfwEvent[]) => void, options?: any): NsfwStartWatchingPromise; + actions: { + CREATED: number; + DELETED: number; + MODIFIED: number; + RENAMED: number; + } + } + + var nsfw: NsfwFunction; + export = nsfw; +} diff --git a/src/typings/onigasm-umd.d.ts b/src/typings/onigasm-umd.d.ts new file mode 100644 index 000000000..151cecebf --- /dev/null +++ b/src/typings/onigasm-umd.d.ts @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +declare module "onigasm-umd" { + + function loadWASM(data: string | ArrayBuffer): Promise; + + class OnigString { + constructor(content: string); + readonly content: string; + readonly dispose?: () => void; + } + + class OnigScanner { + constructor(patterns: string[]); + findNextMatchSync(string: string | OnigString, startPosition: number): IOnigMatch; + } + + export interface IOnigCaptureIndex { + index: number + start: number + end: number + length: number + } + + export interface IOnigMatch { + index: number + captureIndices: IOnigCaptureIndex[] + scanner: OnigScanner + } +} \ No newline at end of file diff --git a/src/typings/require.d.ts b/src/typings/require.d.ts index ded5e2e72..618861a5b 100644 --- a/src/typings/require.d.ts +++ b/src/typings/require.d.ts @@ -17,7 +17,12 @@ declare const enum LoaderEventType { NodeEndEvaluatingScript = 32, NodeBeginNativeRequire = 33, - NodeEndNativeRequire = 34 + NodeEndNativeRequire = 34, + + CachedDataFound = 60, + CachedDataMissed = 61, + CachedDataRejected = 62, + CachedDataCreated = 63, } declare class LoaderEvent { diff --git a/src/typings/semver-umd.d.ts b/src/typings/semver-umd.d.ts new file mode 100644 index 000000000..372f000c6 --- /dev/null +++ b/src/typings/semver-umd.d.ts @@ -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. + *--------------------------------------------------------------------------------------------*/ + +declare module 'semver-umd' { + + export * from "semver"; + +} \ No newline at end of file diff --git a/src/typings/vscode-nsfw.d.ts b/src/typings/vscode-nsfw.d.ts deleted file mode 100644 index 5f70eb30f..000000000 --- a/src/typings/vscode-nsfw.d.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. - *--------------------------------------------------------------------------------------------*/ - -declare module 'vscode-nsfw' { - interface NsfwWatcher { - start(): any; - stop(): any; - } - - interface NsfwWatchingPromise { - then(): void; - } - - interface NsfwStartWatchingPromise { - then(fn: (watcher: NsfwWatcher) => void): NsfwWatchingPromise; - } - - interface NsfwEvent { - action: number; - directory: string; - file?: string; - newFile?: string; - oldFile?: string; - } - - interface NsfwFunction { - (dir: string, eventHandler: (events: NsfwEvent[]) => void, options?: any): NsfwStartWatchingPromise; - actions: { - CREATED: number; - DELETED: number; - MODIFIED: number; - RENAMED: number; - } - } - - var nsfw: NsfwFunction; - export = nsfw; -} diff --git a/src/typings/vscode-sqlite3.d.ts b/src/typings/vscode-sqlite3.d.ts index 4363d251c..9a79c4ded 100644 --- a/src/typings/vscode-sqlite3.d.ts +++ b/src/typings/vscode-sqlite3.d.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ // Type definitions for sqlite3 3.1 -// Project: https://github.com/mapbox/node-sqlite3 +// Project: http://github.com/mapbox/node-sqlite3 // Definitions by: Nick Malaguti // Sumant Manne // Behind The Math @@ -18,6 +18,9 @@ declare module 'vscode-sqlite3' { export const OPEN_READONLY: number; export const OPEN_READWRITE: number; export const OPEN_CREATE: number; + export const OPEN_SHAREDCACHE: number; + export const OPEN_PRIVATECACHE: number; + export const OPEN_URI: number; export const cached: { Database(filename: string, callback?: (this: Database, err: Error | null) => void): Database; @@ -100,6 +103,9 @@ declare module 'vscode-sqlite3' { OPEN_READONLY: number; OPEN_READWRITE: number; OPEN_CREATE: number; + OPEN_SHAREDCACHE: number; + OPEN_PRIVATECACHE: number; + OPEN_URI: number; cached: typeof cached; RunResult: RunResult; Statement: typeof Statement; diff --git a/src/typings/vscode-textmate.d.ts b/src/typings/vscode-textmate.d.ts index 224b91004..835b33008 100644 --- a/src/typings/vscode-textmate.d.ts +++ b/src/typings/vscode-textmate.d.ts @@ -30,7 +30,7 @@ declare module "vscode-textmate" { */ export interface RegistryOptions { theme?: IRawTheme; - loadGrammar(scopeName: string): Thenable | null; + loadGrammar(scopeName: string): Thenable; getInjections?(scopeName: string): string[]; getOnigLib?(): Thenable; } @@ -85,7 +85,7 @@ declare module "vscode-textmate" { * Load the grammar for `scopeName` and all referenced included grammars asynchronously. */ loadGrammar(initialScopeName: string): Thenable; - private _loadGrammar(initialScopeName, initialLanguage, embeddedLanguages, tokenTypes); + private _loadGrammar; /** * Adds a rawGrammar. */ @@ -182,7 +182,7 @@ declare module "vscode-textmate" { equals(other: StackElement): boolean; } export const INITIAL: StackElement; - export const parseRawGrammar: (content: string, filePath: string) => IRawGrammar; + export const parseRawGrammar: (content: string, filePath?: string) => IRawGrammar; export interface ILocation { readonly filename: string; readonly line: number; diff --git a/src/typings/vscode-windows-ca-certs.d.ts b/src/typings/vscode-windows-ca-certs.d.ts new file mode 100644 index 000000000..f923eb8a8 --- /dev/null +++ b/src/typings/vscode-windows-ca-certs.d.ts @@ -0,0 +1,6 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +declare module 'vscode-windows-ca-certs'; diff --git a/src/typings/vscode-xterm.d.ts b/src/typings/vscode-xterm.d.ts deleted file mode 100644 index e425a37c4..000000000 --- a/src/typings/vscode-xterm.d.ts +++ /dev/null @@ -1,817 +0,0 @@ -/** - * @license MIT - * - * This contains the type declarations for the xterm.js library. Note that - * some interfaces differ between this file and the actual implementation in - * src/, that's because this file declares the *public* API which is intended - * to be stable and consumed by external programs. - */ - -/// - -declare module 'vscode-xterm' { - /** - * A string representing text font weight. - */ - export type FontWeight = 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900'; - - /** - * A string representing a renderer type. - */ - export type RendererType = 'dom' | 'canvas'; - - /** - * An object containing start up options for the terminal. - */ - export interface ITerminalOptions { - /** - * Whether background should support non-opaque color. It must be set before - * executing open() method and can't be changed later without excuting it again. - * Warning: Enabling this option can reduce performances somewhat. - */ - allowTransparency?: boolean; - - /** - * A data uri of the sound to use for the bell (needs bellStyle = 'sound'). - */ - bellSound?: string; - - /** - * The type of the bell notification the terminal will use. - */ - bellStyle?: 'none' /*| 'visual'*/ | 'sound' /*| 'both'*/; - - /** - * When enabled the cursor will be set to the beginning of the next line - * with every new line. This equivalent to sending '\r\n' for each '\n'. - * Normally the termios settings of the underlying PTY deals with the - * translation of '\n' to '\r\n' and this setting should not be used. If you - * deal with data from a non-PTY related source, this settings might be - * useful. - */ - convertEol?: boolean; - - /** - * 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 draw bold text in bright colors. The default is true. - */ - drawBoldTextInBrightColors?: boolean; - - /** - * Whether to enable the rendering of bold text. - * - * @deprecated Use fontWeight and fontWeightBold instead. - */ - enableBold?: boolean; - - /** - * What character atlas implementation to use. The character atlas caches drawn characters, - * speeding up rendering significantly. However, it can introduce some minor rendering - * artifacts. - * - * - 'none': Don't use an atlas. - * - 'static': Generate an atlas when the terminal starts or is reconfigured. This atlas will - * only contain ASCII characters in 16 colors. - * - 'dynamic': Generate an atlas using a LRU cache as characters are requested. Limited to - * ASCII characters (for now), but supports 256 colors. For characters covered by the static - * cache, it's slightly slower in comparison, since there's more overhead involved in - * managing the cache. - * - * Currently defaults to 'static'. This option may be removed in the future. If it is, passed - * parameters will be ignored. - */ - experimentalCharAtlas?: 'none' | 'static' | 'dynamic'; - - /** - * (EXPERIMENTAL) Defines which implementation to use for buffer lines. - * - * - 'JsArray': The default/stable implementation. - * - 'TypedArray': The new experimental implementation based on TypedArrays that is expected to - * significantly boost performance and memory consumption. Use at your own risk. - * - * @deprecated This option will be removed in the future. - */ - experimentalBufferLineImpl?: 'JsArray' | 'TypedArray'; - - /** - * The font size used to render text. - */ - fontSize?: number; - - /** - * The font family used to render text. - */ - fontFamily?: string; - - /** - * The font weight used to render non-bold text. - */ - fontWeight?: FontWeight; - - /** - * The font weight used to render bold text. - */ - fontWeightBold?: FontWeight; - - /** - * The spacing in whole pixels between characters.. - */ - letterSpacing?: number; - - /** - * The line height used to render text. - */ - lineHeight?: number; - - /** - * Whether to treat option as the meta key. - */ - macOptionIsMeta?: boolean; - - /** - * Whether holding a modifier key will force normal selection behavior, - * regardless of whether the terminal is in mouse events mode. This will - * also prevent mouse events from being emitted by the terminal. For example, - * this allows you to use xterm.js' regular selection inside tmux with - * mouse mode enabled. - */ - macOptionClickForcesSelection?: boolean; - - /** - * The type of renderer to use, this allows using the fallback DOM renderer - * when canvas is too slow for the environment. The following features do - * not work when the DOM renderer is used: - * - * - Letter spacing - * - Cursor blink - */ - rendererType?: RendererType; - - /** - * Whether to select the word under the cursor on right click, this is - * standard behavior in a lot of macOS applications. - */ - rightClickSelectsWord?: boolean; - - /** - * The number of rows in the terminal. - */ - rows?: number; - - /** - * Whether screen reader support is enabled. When on this will expose - * supporting elements in the DOM to support NVDA on Windows and VoiceOver - * on macOS. - */ - screenReaderMode?: boolean; - - /** - * 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; - } - - /** - * Contains colors to theme the terminal with. - */ - export interface ITheme { - /** The default foreground color */ - foreground?: string, - /** The default background color */ - background?: string, - /** The cursor color */ - cursor?: string, - /** The accent color of the cursor (used as the foreground color for a block cursor) */ - cursorAccent?: string, - /** The selection color (can be transparent) */ - selection?: 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 - } - - /** - * An object containing options for a link matcher. - */ - export 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 whether to create an individual link, pass - * whether the link is valid to the callback. - */ - validationCallback?: (uri: string, callback: (isValid: boolean) => void) => void; - - /** - * A callback that fires when the mouse hovers over a link for a moment. - */ - tooltipCallback?: (event: MouseEvent, uri: string) => boolean | void; - - /** - * 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 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; - - /** - * A callback that fires when the mousedown and click events occur that - * determines whether a link will be activated upon click. This enables - * only activating a link when a certain modifier is held down, if not the - * mouse event will continue propagation (eg. double click to select word). - */ - willLinkActivate?: (event: MouseEvent, uri: string) => boolean; - } - - export interface IEventEmitter { - on(type: string, listener: (...args: any[]) => void): void; - off(type: string, listener: (...args: any[]) => void): void; - emit(type: string, data?: any): void; - addDisposableListener(type: string, handler: (...args: any[]) => void): IDisposable; - } - - /** - * An object that can be disposed via a dispose function. - */ - export interface IDisposable { - dispose(): void; - } - - export interface IMarker extends IDisposable { - readonly id: number; - readonly isDisposed: boolean; - readonly line: number; - } - - export interface ILocalizableStrings { - blankLine: string; - promptLabel: string; - tooMuchOutput: string; - } - - /** - * The class that represents an xterm.js terminal. - */ - export class Terminal implements IEventEmitter, IDisposable { - /** - * 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; - - /** - * (EXPERIMENTAL) Get all markers registered against the buffer. If the alt - * buffer is active this will always return []. - */ - markers: IMarker[]; - - /** - * Natural language strings that can be localized. - */ - static strings: ILocalizableStrings; - - /** - * 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' | 'selection', listener: () => void): void; - /** - * Registers an event listener. - * @param type The type of the event. - * @param listener The listener. - */ - on(type: 'data', listener: (...args: any[]) => 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' | 'selection' | 'data' | 'key' | 'keypress' | 'keydown' | 'refresh' | 'resize' | 'scroll' | 'title' | string, listener: (...args: any[]) => void): void; - - /** - * Emits an event on the terminal. - * @param type The type of event - * @param data data associated with the event. - * @deprecated This is being removed from the API with no replacement, see - * issue #1505. - */ - emit(type: string, data?: any): void; - - /** - * Adds an event listener to the Terminal, returning an IDisposable that can - * be used to conveniently remove the event listener. - * @param type The type of event. - * @param handler The event handler. - */ - addDisposableListener(type: string, handler: (...args: any[]) => void): IDisposable; - - /** - * 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. This element - * must be visible (have dimensions) when `open` is called as several DOM- - * based measurements need to be performed when this function is called. - */ - 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) => 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; - - /** - * (EXPERIMENTAL) Registers a character joiner, allowing custom sequences of - * characters to be rendered as a single unit. This is useful in particular - * for rendering ligatures and graphemes, among other things. - * - * Each registered character joiner is called with a string of text - * representing a portion of a line in the terminal that can be rendered as - * a single unit. The joiner must return a sorted array, where each entry is - * itself an array of length two, containing the start (inclusive) and end - * (exclusive) index of a substring of the input that should be rendered as - * a single unit. When multiple joiners are provided, the results of each - * are collected. If there are any overlapping substrings between them, they - * are combined into one larger unit that is drawn together. - * - * All character joiners that are registered get called every time a line is - * rendered in the terminal, so it is essential for the handler function to - * run as quickly as possible to avoid slowdowns when rendering. Similarly, - * joiners should strive to return the smallest possible substrings to - * render together, since they aren't drawn as optimally as individual - * characters. - * - * NOTE: character joiners are only used by the canvas renderer. - * - * @param handler The function that determines character joins. It is called - * with a string of text that is eligible for joining and returns an array - * where each entry is an array containing the start (inclusive) and end - * (exclusive) indexes of ranges that should be rendered as a single unit. - * @return The ID of the new joiner, this can be used to deregister - */ - registerCharacterJoiner(handler: (text: string) => [number, number][]): number; - - /** - * (EXPERIMENTAL) Deregisters the character joiner if one was registered. - * NOTE: character joiners are only used by the canvas renderer. - * @param joinerId The character joiner's ID (returned after register) - */ - deregisterCharacterJoiner(joinerId: number): void; - - /** - * (EXPERIMENTAL) Adds a marker to the normal buffer and returns it. If the - * alt buffer is active, undefined is returned. - * @param cursorYOffset The y position offset of the marker from the cursor. - */ - addMarker(cursorYOffset: number): IMarker; - - /** - * Gets whether the terminal has an active selection. - */ - 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; - - /** - * Selects text in the buffer between 2 lines. - * @param start The 0-based line index to select from (inclusive). - * @param end The 0-based line index to select to (inclusive). - */ - selectLines(start: number, end: number): void; - - /* - * Disposes of the terminal, detaching it from the DOM and removing any - * active listeners. - */ - dispose(): void; - - /** - * Destroys the terminal and detaches it from the DOM. - * - * @deprecated Use dispose() instead. - */ - 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; - - /** - * Scrolls to a line within the buffer. - * @param line The 0-based line index to scroll to. - */ - scrollToLine(line: number): void; - - /** - * Clear the entire buffer, making the prompt line the new first line. - */ - 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' | 'fontWeight' | 'fontWeightBold' | 'rendererType' | 'termName'): string; - /** - * Retrieves an option's value from the terminal. - * @param key The option key. - */ - getOption(key: 'allowTransparency' | 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'debug' | 'disableStdin' | 'enableBold' | 'macOptionIsMeta' | 'rightClickSelectsWord' | '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' | 'letterSpacing' | 'lineHeight' | 'rows' | 'tabStopWidth' | 'scrollback'): 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: 'fontWeight' | 'fontWeightBold', value: null | 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900'): void; - /** - * Sets an option on the terminal. - * @param key The option key. - * @param value The option value. - */ - setOption(key: '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: 'allowTransparency' | 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'debug' | 'disableStdin' | 'enableBold' | 'macOptionIsMeta' | 'popOnBell' | 'rightClickSelectsWord' | '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: 'fontSize' | 'letterSpacing' | 'lineHeight' | 'tabStopWidth' | 'scrollback', value: 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: 'cols' | 'rows', value: number): 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 - - /** - * Applies an addon to the Terminal prototype, making it available to all - * newly created Terminals. - * @param addon The addon to apply. - */ - static applyAddon(addon: any): void; - } -} - - -// Modifications to official .d.ts below -declare module 'vscode-xterm' { - interface TerminalCore { - debug: boolean; - - buffer: { - y: number; - ybase: number; - ydisp: number; - x: number; - lines: any[]; - - translateBufferLineToString(lineIndex: number, trimRight: boolean): string; - }; - - handler(text: string): void; - - /** - * Emit an event on the terminal. - */ - emit(type: string, data: any): void; - - charMeasure?: { height: number, width: number }; - - renderer: { - _renderLayers: any[]; - onIntersectionChange: any; - }; - } - - interface ISearchOptions { - /** - * Whether the find should be done as a regex. - */ - regex?: boolean; - /** - * Whether only whole words should match. - */ - wholeWord?: boolean; - /** - * Whether find should pay attention to case. - */ - caseSensitive?: boolean; - } - - interface Terminal { - _core: TerminalCore; - - webLinksInit(handler?: (event: MouseEvent, uri: string) => void, options?: ILinkMatcherOptions): void; - winptyCompatInit(): void; - - /** - * Find the next instance of the term, then scroll to and select it. If it - * doesn't exist, do nothing. - * @param term The search term. - * @param findOptions Regex, whole word, and case sensitive options. - * @return Whether a result was found. - */ - findNext(term: string, findOptions: ISearchOptions): boolean; - - /** - * Find the previous instance of the term, then scroll to and select it. If it - * doesn't exist, do nothing. - * @param term The search term. - * @param findOptions Regex, whole word, and case sensitive options. - * @return Whether a result was found. - */ - findPrevious(term: string, findOptions: ISearchOptions): boolean; - } -} diff --git a/src/typings/vsda.d.ts b/src/typings/vsda.d.ts new file mode 100644 index 000000000..369e98483 --- /dev/null +++ b/src/typings/vsda.d.ts @@ -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. + *--------------------------------------------------------------------------------------------*/ + +declare module 'vsda' { + export class signer { + sign(arg: any): any; + } +} diff --git a/src/typings/xterm-addon-search.d.ts b/src/typings/xterm-addon-search.d.ts new file mode 100644 index 000000000..2f3be6f82 --- /dev/null +++ b/src/typings/xterm-addon-search.d.ts @@ -0,0 +1,69 @@ +/** + * Copyright (c) 2017 The xterm.js authors. All rights reserved. + * @license MIT + */ + +// HACK: gulp-tsb doesn't play nice with importing from typings +// import { Terminal, ITerminalAddon } from 'xterm'; + +declare module 'xterm-addon-search' { + /** + * Options for a search. + */ + export interface ISearchOptions { + /** + * Whether the search term is a regex. + */ + regex?: boolean; + + /** + * Whether to search for a whole word, the result is only valid if it's + * suppounded in "non-word" characters such as `_`, `(`, `)` or space. + */ + wholeWord?: boolean; + + /** + * Whether the search is case sensitive. + */ + caseSensitive?: boolean; + + /** + * Whether to do an indcremental search, this will expand the selection if it + * still matches the term the user typed. Note that this only affects + * `findNext`, not `findPrevious`. + */ + incremental?: boolean; + } + + /** + * An xterm.js addon that provides search functionality. + */ + export class SearchAddon { + /** + * Activates the addon + * @param terminal The terminal the addon is being loaded in. + */ + public activate(terminal: any): void; + + /** + * Disposes the addon. + */ + public dispose(): void; + + /** + * Search forwards for the next result that matches the search term and + * options. + * @param term The search term. + * @param searchOptions The options for the search. + */ + public findNext(term: string, searchOptions?: ISearchOptions): boolean; + + /** + * Search backwards for the previous result that matches the search term and + * options. + * @param term The search term. + * @param searchOptions The options for the search. + */ + public findPrevious(term: string, searchOptions?: ISearchOptions): boolean; + } +} diff --git a/src/typings/xterm-addon-web-links.d.ts b/src/typings/xterm-addon-web-links.d.ts new file mode 100644 index 000000000..da348f8c8 --- /dev/null +++ b/src/typings/xterm-addon-web-links.d.ts @@ -0,0 +1,71 @@ +/** + * Copyright (c) 2017 The xterm.js authors. All rights reserved. + * @license MIT + */ + +// HACK: gulp-tsb doesn't play nice with importing from typings +// import { Terminal, ITerminalAddon } from 'xterm'; +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 whether to create an individual link, pass + * whether the link is valid to the callback. + */ + validationCallback?: (uri: string, callback: (isValid: boolean) => void) => void; + + /** + * A callback that fires when the mouse hovers over a link for a moment. + */ + tooltipCallback?: (event: MouseEvent, uri: string) => boolean | void; + + /** + * 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?: () => 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; + + /** + * A callback that fires when the mousedown and click events occur that + * determines whether a link will be activated upon click. This enables + * only activating a link when a certain modifier is held down, if not the + * mouse event will continue propagation (eg. double click to select word). + */ + willLinkActivate?: (event: MouseEvent, uri: string) => boolean; +} + +declare module 'xterm-addon-web-links' { + /** + * An xterm.js addon that enables web links. + */ + export class WebLinksAddon { + /** + * Creates a new web links addon. + * @param handler The callback when the link is called. + * @param options Options for the link matcher. + */ + constructor(handler?: (event: MouseEvent, uri: string) => void, options?: ILinkMatcherOptions); + + /** + * Activates the addon + * @param terminal The terminal the addon is being loaded in. + */ + public activate(terminal: any): void; + + /** + * Disposes the addon. + */ + public dispose(): void; + } +} diff --git a/src/typings/xterm.d.ts b/src/typings/xterm.d.ts new file mode 100644 index 000000000..663b99702 --- /dev/null +++ b/src/typings/xterm.d.ts @@ -0,0 +1,990 @@ +/** + * @license MIT + * + * This contains the type declarations for the xterm.js library. Note that + * some interfaces differ between this file and the actual implementation in + * src/, that's because this file declares the *public* API which is intended + * to be stable and consumed by external programs. + */ + +/// + +declare module 'xterm' { + /** + * A string representing text font weight. + */ + export type FontWeight = 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900'; + + /** + * A string representing log level. + */ + export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'off'; + + /** + * A string representing a renderer type. + */ + export type RendererType = 'dom' | 'canvas'; + + /** + * An object containing start up options for the terminal. + */ + export interface ITerminalOptions { + /** + * Whether background should support non-opaque color. It must be set before + * executing the `Terminal.open()` method and can't be changed later without + * executing it again. Note that enabling this can negatively impact + * performance. + */ + allowTransparency?: boolean; + + /** + * A data uri of the sound to use for the bell when `bellStyle = 'sound'`. + */ + bellSound?: string; + + /** + * The type of the bell notification the terminal will use. + */ + bellStyle?: 'none' /*| 'visual'*/ | 'sound' /*| 'both'*/; + + /** + * When enabled the cursor will be set to the beginning of the next line + * with every new line. This equivalent to sending '\r\n' for each '\n'. + * Normally the termios settings of the underlying PTY deals with the + * translation of '\n' to '\r\n' and this setting should not be used. If you + * deal with data from a non-PTY related source, this settings might be + * useful. + */ + convertEol?: boolean; + + /** + * 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 draw bold text in bright colors. The default is true. + */ + drawBoldTextInBrightColors?: boolean; + + /** + * The font size used to render text. + */ + fontSize?: number; + + /** + * The font family used to render text. + */ + fontFamily?: string; + + /** + * The font weight used to render non-bold text. + */ + fontWeight?: FontWeight; + + /** + * The font weight used to render bold text. + */ + fontWeightBold?: FontWeight; + + /** + * The spacing in whole pixels between characters.. + */ + letterSpacing?: number; + + /** + * The line height used to render text. + */ + lineHeight?: number; + + /** + * What log level to use, this will log for all levels below and including + * what is set: + * + * 1. debug + * 2. info (default) + * 3. warn + * 4. error + * 5. off + */ + logLevel?: LogLevel; + + /** + * Whether to treat option as the meta key. + */ + macOptionIsMeta?: boolean; + + /** + * Whether holding a modifier key will force normal selection behavior, + * regardless of whether the terminal is in mouse events mode. This will + * also prevent mouse events from being emitted by the terminal. For + * example, this allows you to use xterm.js' regular selection inside tmux + * with mouse mode enabled. + */ + macOptionClickForcesSelection?: boolean; + + /** + * The type of renderer to use, this allows using the fallback DOM renderer + * when canvas is too slow for the environment. The following features do + * not work when the DOM renderer is used: + * + * - Letter spacing + * - Cursor blink + */ + rendererType?: RendererType; + + /** + * Whether to select the word under the cursor on right click, this is + * standard behavior in a lot of macOS applications. + */ + rightClickSelectsWord?: boolean; + + /** + * The number of rows in the terminal. + */ + rows?: number; + + /** + * Whether screen reader support is enabled. When on this will expose + * supporting elements in the DOM to support NVDA on Windows and VoiceOver + * on macOS. + */ + screenReaderMode?: boolean; + + /** + * 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; + + /** + * Whether "Windows mode" is enabled. Because Windows backends winpty and + * conpty operate by doing line wrapping on their side, xterm.js does not + * have access to wrapped lines. When Windows mode is enabled the following + * changes will be in effect: + * + * - Reflow is disabled. + * - Lines are assumed to be wrapped if the last character of the line is + * not whitespace. + */ + windowsMode?: boolean; + + /** + * A string containing all characters that are considered word separated by the + * double click to select work logic. + */ + wordSeparator?: string; + } + + /** + * Contains colors to theme the terminal with. + */ + export interface ITheme { + /** The default foreground color */ + foreground?: string, + /** The default background color */ + background?: string, + /** The cursor color */ + cursor?: string, + /** The accent color of the cursor (fg color for a block cursor) */ + cursorAccent?: string, + /** The selection background color (can be transparent) */ + selection?: 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 + } + + /** + * An object containing options for a link matcher. + */ + export 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 whether to create an individual link, pass + * whether the link is valid to the callback. + */ + validationCallback?: (uri: string, callback: (isValid: boolean) => void) => void; + + /** + * A callback that fires when the mouse hovers over a link for a moment. + */ + tooltipCallback?: (event: MouseEvent, uri: string) => boolean | void; + + /** + * 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?: () => 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; + + /** + * A callback that fires when the mousedown and click events occur that + * determines whether a link will be activated upon click. This enables + * only activating a link when a certain modifier is held down, if not the + * mouse event will continue propagation (eg. double click to select word). + */ + willLinkActivate?: (event: MouseEvent, uri: string) => boolean; + } + + /** + * An object that can be disposed via a dispose function. + */ + export interface IDisposable { + dispose(): void; + } + + /** + * An event that can be listened to. + * @returns an `IDisposable` to stop listening. + */ + export interface IEvent { + (listener: (e: T) => any): IDisposable; + } + + /** + * Represents a specific line in the terminal that is tracked when scrollback + * is trimmed and lines are added or removed. + */ + export interface IMarker extends IDisposable { + /** + * A unique identifier for this marker. + */ + readonly id: number; + + /** + * Whether this marker is disposed. + */ + readonly isDisposed: boolean; + + /** + * The actual line index in the buffer at this point in time. + */ + readonly line: number; + } + + /** + * The set of localizable strings. + */ + export interface ILocalizableStrings { + /** + * The aria label for the underlying input textarea for the terminal. + */ + promptLabel: string; + + /** + * Announcement for when line reading is suppressed due to too many lines + * being printed to the terminal when `screenReaderMode` is enabled. + */ + tooMuchOutput: string; + } + + /** + * The class that represents an xterm.js terminal. + */ + export class Terminal implements IDisposable { + /** + * The element containing the terminal. + */ + readonly element: HTMLElement; + + /** + * The textarea that accepts input for the terminal. + */ + readonly textarea: HTMLTextAreaElement; + + /** + * The number of rows in the terminal's viewport. Use + * `ITerminalOptions.rows` to set this in the constructor and + * `Terminal.resize` for when the terminal exists. + */ + readonly rows: number; + + /** + * The number of columns in the terminal's viewport. Use + * `ITerminalOptions.cols` to set this in the constructor and + * `Terminal.resize` for when the terminal exists. + */ + readonly cols: number; + + /** + * (EXPERIMENTAL) The terminal's current buffer, this might be either the + * normal buffer or the alt buffer depending on what's running in the + * terminal. + */ + readonly buffer: IBuffer; + + /** + * (EXPERIMENTAL) Get all markers registered against the buffer. If the alt + * buffer is active this will always return []. + */ + readonly markers: ReadonlyArray; + + /** + * Natural language strings that can be localized. + */ + static strings: ILocalizableStrings; + + /** + * Creates a new `Terminal` object. + * + * @param options An object containing a set of options. + */ + constructor(options?: ITerminalOptions); + + /** + * Adds an event listener for the cursor moves. + * @returns an `IDisposable` to stop listening. + */ + onCursorMove: IEvent; + + /** + * Adds an event listener for when a data event fires. This happens for + * example when the user types or pastes into the terminal. The event value + * is whatever `string` results, in a typical setup, this should be passed + * on to the backing pty. + * @returns an `IDisposable` to stop listening. + */ + onData: IEvent; + + /** + * Adds an event listener for a key is pressed. The event value contains the + * string that will be sent in the data event as well as the DOM event that + * triggered it. + * @returns an `IDisposable` to stop listening. + */ + onKey: IEvent<{ key: string, domEvent: KeyboardEvent }>; + + /** + * Adds an event listener for when a line feed is added. + * @returns an `IDisposable` to stop listening. + */ + onLineFeed: IEvent; + + /** + * Adds an event listener for when a scroll occurs. The event value is the + * new position of the viewport. + * @returns an `IDisposable` to stop listening. + */ + onScroll: IEvent; + + /** + * Adds an event listener for when a selection change occurs. + * @returns an `IDisposable` to stop listening. + */ + onSelectionChange: IEvent; + + /** + * Adds an event listener for when rows are rendered. The event value + * contains the start row and end rows of the rendered area (ranges from `0` + * to `Terminal.rows - 1`). + * @returns an `IDisposable` to stop listening. + */ + onRender: IEvent<{ start: number, end: number }>; + + /** + * Adds an event listener for when the terminal is resized. The event value + * contains the new size. + * @returns an `IDisposable` to stop listening. + */ + onResize: IEvent<{ cols: number, rows: number }>; + + /** + * Adds an event listener for when an OSC 0 or OSC 2 title change occurs. + * The event value is the new title. + * @returns an `IDisposable` to stop listening. + */ + onTitleChange: IEvent; + + /** + * Unfocus the terminal. + */ + blur(): void; + + /** + * Focus the terminal. + */ + focus(): void; + + /** + * Resizes the terminal. It's best practice to debounce calls to resize, + * this will help ensure that the pty can respond to the resize event + * before another one occurs. + * @param x The number of columns to resize to. + * @param y The number of rows to resize to. + */ + resize(columns: number, rows: number): void; + + /** + * Opens the terminal within an element. + * @param parent The element to create the terminal within. This element + * must be visible (have dimensions) when `open` is called as several DOM- + * based measurements need to be performed when this function is called. + */ + 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 + * propagation 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) Adds a handler for CSI escape sequences. + * @param flag The flag should be one-character string, which specifies the + * final character (e.g "m" for SGR) of the CSI sequence. + * @param callback The function to handle the escape sequence. The callback + * is called with the numerical params, as well as the special characters + * (e.g. "$" for DECSCPP). If the sequence has subparams the array will + * contain subarrays with their numercial values. + * Return true if the sequence was handled; false if + * we should try a previous handler (set by addCsiHandler or setCsiHandler). + * The most recently-added handler is tried first. + * @return An IDisposable you can call to remove this handler. + */ + addCsiHandler(flag: string, callback: (params: (number | number[])[], collect: string) => boolean): IDisposable; + + /** + * (EXPERIMENTAL) Adds a handler for OSC escape sequences. + * @param ident The number (first parameter) of the sequence. + * @param callback The function to handle the escape sequence. The callback + * is called with OSC data string. Return true if the sequence was handled; + * false if we should try a previous handler (set by addOscHandler or + * setOscHandler). The most recently-added handler is tried first. + * @return An IDisposable you can call to remove this handler. + */ + addOscHandler(ident: number, callback: (data: string) => boolean): IDisposable; + + /** + * (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) => 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; + + /** + * (EXPERIMENTAL) Registers a character joiner, allowing custom sequences of + * characters to be rendered as a single unit. This is useful in particular + * for rendering ligatures and graphemes, among other things. + * + * Each registered character joiner is called with a string of text + * representing a portion of a line in the terminal that can be rendered as + * a single unit. The joiner must return a sorted array, where each entry is + * itself an array of length two, containing the start (inclusive) and end + * (exclusive) index of a substring of the input that should be rendered as + * a single unit. When multiple joiners are provided, the results of each + * are collected. If there are any overlapping substrings between them, they + * are combined into one larger unit that is drawn together. + * + * All character joiners that are registered get called every time a line is + * rendered in the terminal, so it is essential for the handler function to + * run as quickly as possible to avoid slowdowns when rendering. Similarly, + * joiners should strive to return the smallest possible substrings to + * render together, since they aren't drawn as optimally as individual + * characters. + * + * NOTE: character joiners are only used by the canvas renderer. + * + * @param handler The function that determines character joins. It is called + * with a string of text that is eligible for joining and returns an array + * where each entry is an array containing the start (inclusive) and end + * (exclusive) indexes of ranges that should be rendered as a single unit. + * @return The ID of the new joiner, this can be used to deregister + */ + registerCharacterJoiner(handler: (text: string) => [number, number][]): number; + + /** + * (EXPERIMENTAL) Deregisters the character joiner if one was registered. + * NOTE: character joiners are only used by the canvas renderer. + * @param joinerId The character joiner's ID (returned after register) + */ + deregisterCharacterJoiner(joinerId: number): void; + + /** + * (EXPERIMENTAL) Adds a marker to the normal buffer and returns it. If the + * alt buffer is active, undefined is returned. + * @param cursorYOffset The y position offset of the marker from the cursor. + */ + addMarker(cursorYOffset: number): IMarker; + + /** + * Gets whether the terminal has an active selection. + */ + hasSelection(): boolean; + + /** + * Gets the terminal's current selection, this is useful for implementing + * copy behavior outside of xterm.js. + */ + getSelection(): string; + + /** + * Gets the selection position or undefined if there is no selection. + */ + getSelectionPosition(): ISelectionPosition | undefined; + + /** + * Clears the current terminal selection. + */ + clearSelection(): void; + + /** + * Selects text within the terminal. + * @param column The column the selection starts at.. + * @param row The row the selection starts at. + * @param length The length of the selection. + */ + select(column: number, row: number, length: number): void; + + /** + * Selects all text within the terminal. + */ + selectAll(): void; + + /** + * Selects text in the buffer between 2 lines. + * @param start The 0-based line index to select from (inclusive). + * @param end The 0-based line index to select to (inclusive). + */ + selectLines(start: number, end: number): void; + + /* + * Disposes of the terminal, detaching it from the DOM and removing any + * active listeners. + */ + dispose(): 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; + + /** + * Scrolls to a line within the buffer. + * @param line The 0-based line index to scroll to. + */ + scrollToLine(line: number): void; + + /** + * Clear the entire buffer, making the prompt line the new first line. + */ + clear(): void; + + /** + * Writes text to the terminal. + * @param data The text to write to the terminal. + */ + write(data: string): 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; + + /** + * Writes UTF8 data to the terminal. This has a slight performance advantage + * over the string based write method due to lesser data conversions needed + * on the way from the pty to xterm.js. + * @param data The data to write to the terminal. + */ + writeUtf8(data: Uint8Array): void; + + /** + * Retrieves an option's value from the terminal. + * @param key The option key. + */ + getOption(key: 'bellSound' | 'bellStyle' | 'cursorStyle' | 'fontFamily' | 'fontWeight' | 'fontWeightBold' | 'logLevel' | 'rendererType' | 'termName' | 'wordSeparator'): string; + /** + * Retrieves an option's value from the terminal. + * @param key The option key. + */ + getOption(key: 'allowTransparency' | 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'disableStdin' | 'macOptionIsMeta' | 'rightClickSelectsWord' | 'popOnBell' | 'screenKeys' | 'useFlowControl' | 'visualBell' | 'windowsMode'): 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' | 'letterSpacing' | 'lineHeight' | 'rows' | 'tabStopWidth' | 'scrollback'): 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' | 'wordSeparator', value: string): void; + /** + * Sets an option on the terminal. + * @param key The option key. + * @param value The option value. + */ + setOption(key: 'fontWeight' | 'fontWeightBold', value: null | 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900'): void; + /** + * Sets an option on the terminal. + * @param key The option key. + * @param value The option value. + */ + setOption(key: 'logLevel', value: LogLevel): void; + /** + * Sets an option on the terminal. + * @param key The option key. + * @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: 'allowTransparency' | 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'disableStdin' | 'macOptionIsMeta' | 'popOnBell' | 'rightClickSelectsWord' | 'screenKeys' | 'useFlowControl' | 'visualBell' | 'windowsMode', value: boolean): void; + /** + * Sets an option on the terminal. + * @param key The option key. + * @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: 'fontSize' | 'letterSpacing' | 'lineHeight' | 'tabStopWidth' | 'scrollback', value: 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: 'cols' | 'rows', value: number): 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 + + /** + * Applies an addon to the Terminal prototype, making it available to all + * newly created Terminals. + * @param addon The addon to apply. + * @deprecated Use the new loadAddon API/addon format. + */ + static applyAddon(addon: any): void; + + /** + * (EXPERIMENTAL) Loads an addon into this instance of xterm.js. + * @param addon The addon to load. + */ + loadAddon(addon: ITerminalAddon): void; + } + + /** + * An addon that can provide additional functionality to the terminal. + */ + export interface ITerminalAddon extends IDisposable { + /** + * (EXPERIMENTAL) This is called when the addon is activated. + */ + activate(terminal: Terminal): void; + } + + /** + * An object representing a selection within the terminal. + */ + interface ISelectionPosition { + /** + * The start column of the selection. + */ + startColumn: number; + + /** + * The start row of the selection. + */ + startRow: number; + + /** + * The end column of the selection. + */ + endColumn: number; + + /** + * The end row of the selection. + */ + endRow: number; + } + + /** + * Represents a terminal buffer. + */ + interface IBuffer { + /** + * The y position of the cursor. This ranges between `0` (when the + * cursor is at baseY) and `Terminal.rows - 1` (when the cursor is on the + * last row). + */ + readonly cursorY: number; + + /** + * The x position of the cursor. This ranges between `0` (left side) and + * `Terminal.cols - 1` (right side). + */ + readonly cursorX: number; + + /** + * The line within the buffer where the top of the viewport is. + */ + readonly viewportY: number; + + /** + * The line within the buffer where the top of the bottom page is (when + * fully scrolled down); + */ + readonly baseY: number; + + /** + * The amount of lines in the buffer. + */ + readonly length: number; + + /** + * Gets a line from the buffer, or undefined if the line index does not + * exist. + * + * Note that the result of this function should be used immediately after + * calling as when the terminal updates it could lead to unexpected + * behavior. + * + * @param y The line index to get. + */ + getLine(y: number): IBufferLine | undefined; + } + + /** + * Represents a line in the terminal's buffer. + */ + interface IBufferLine { + /** + * Whether the line is wrapped from the previous line. + */ + readonly isWrapped: boolean; + + /** + * Gets a cell from the line, or undefined if the line index does not exist. + * + * Note that the result of this function should be used immediately after + * calling as when the terminal updates it could lead to unexpected + * behavior. + * + * @param x The character index to get. + */ + getCell(x: number): IBufferCell | undefined; + + /** + * Gets the line as a string. Note that this is gets only the string for the + * line, not taking isWrapped into account. + * + * @param trimRight Whether to trim any whitespace at the right of the line. + * @param startColumn The column to start from (inclusive). + * @param endColumn The column to end at (exclusive). + */ + translateToString(trimRight?: boolean, startColumn?: number, endColumn?: number): string; + } + + /** + * Represents a single cell in the terminal's buffer. + */ + interface IBufferCell { + /** + * The character within the cell. + */ + readonly char: string; + + /** + * The width of the character. Some examples: + * + * - This is `1` for most cells. + * - This is `2` for wide character like CJK glyphs. + * - This is `0` for cells immediately following cells with a width of `2`. + */ + readonly width: number; + } +} + + + + + +// Modifications to official .d.ts below +declare module 'xterm' { + interface TerminalCore { + _onScroll: IEventEmitter; + _onKey: IEventEmitter<{ key: string }>; + + _charSizeService: { + width: number; + height: number; + }; + + _coreService: { + triggerDataEvent(data: string, wasUserInput?: boolean): void; + } + + _renderService: { + _renderer: { + _renderLayers: any[]; + }; + _onIntersectionChange: any; + }; + } + + interface IEventEmitter { + fire(e: T): void; + } + + interface Terminal { + _core: TerminalCore; + } +} \ No newline at end of file diff --git a/src/vs/base/browser/browser.ts b/src/vs/base/browser/browser.ts index 16414ef34..6d4436c23 100644 --- a/src/vs/base/browser/browser.ts +++ b/src/vs/base/browser/browser.ts @@ -45,13 +45,13 @@ class WindowManager { // --- Pixel Ratio public getPixelRatio(): number { - let ctx = document.createElement('canvas').getContext('2d'); + let ctx: any = document.createElement('canvas').getContext('2d'); let dpr = window.devicePixelRatio || 1; - let bsr = (ctx).webkitBackingStorePixelRatio || - (ctx).mozBackingStorePixelRatio || - (ctx).msBackingStorePixelRatio || - (ctx).oBackingStorePixelRatio || - (ctx).backingStorePixelRatio || 1; + let bsr = ctx.webkitBackingStorePixelRatio || + ctx.mozBackingStorePixelRatio || + ctx.msBackingStorePixelRatio || + ctx.oBackingStorePixelRatio || + ctx.backingStorePixelRatio || 1; return dpr / bsr; } @@ -122,6 +122,7 @@ export const isSafari = (!isChrome && (userAgent.indexOf('Safari') >= 0)); export const isWebkitWebView = (!isChrome && !isSafari && isWebKit); export const isIPad = (userAgent.indexOf('iPad') >= 0); export const isEdgeWebView = isEdge && (userAgent.indexOf('WebView/') >= 0); +export const isStandalone = (window.matchMedia && window.matchMedia('(display-mode: standalone)').matches); export function hasClipboardSupport() { if (isIE) { diff --git a/src/vs/base/browser/contextmenu.ts b/src/vs/base/browser/contextmenu.ts index 4fa0bf17c..54dc4d766 100644 --- a/src/vs/base/browser/contextmenu.ts +++ b/src/vs/base/browser/contextmenu.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IAction, IActionRunner } from 'vs/base/common/actions'; -import { IActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; +import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { ResolvedKeybinding } from 'vs/base/common/keyCodes'; import { SubmenuAction } from 'vs/base/browser/ui/menu/menu'; import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview'; @@ -24,8 +24,8 @@ export class ContextSubMenu extends SubmenuAction { export interface IContextMenuDelegate { getAnchor(): HTMLElement | { x: number; y: number; width?: number; height?: number; }; - getActions(): Array; - getActionItem?(action: IAction): IActionItem | undefined; + getActions(): ReadonlyArray; + getActionViewItem?(action: IAction): IActionViewItem | undefined; getActionsContext?(event?: IContextMenuEvent): any; getKeyBinding?(action: IAction): ResolvedKeybinding | undefined; getMenuClassName?(): string; diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index 85ce189ee..fa12f6290 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -11,9 +11,11 @@ import { TimeoutTimer } from 'vs/base/common/async'; import { CharCode } from 'vs/base/common/charCode'; import { onUnexpectedError } from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; -import { Disposable, IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import * as platform from 'vs/base/common/platform'; import { coalesce } from 'vs/base/common/arrays'; +import { URI } from 'vs/base/common/uri'; +import { Schemas } from 'vs/base/common/network'; export function clearNode(node: HTMLElement): void { while (node.firstChild) { @@ -32,18 +34,18 @@ export function isInDOM(node: Node | null): boolean { if (node === document.body) { return true; } - node = node.parentNode; + node = node.parentNode || (node as ShadowRoot).host; } return false; } interface IDomClassList { - hasClass(node: HTMLElement, className: string): boolean; - addClass(node: HTMLElement, className: string): void; - addClasses(node: HTMLElement, ...classNames: string[]): void; - removeClass(node: HTMLElement, className: string): void; - removeClasses(node: HTMLElement, ...classNames: string[]): void; - toggleClass(node: HTMLElement, className: string, shouldHaveIt?: boolean): void; + hasClass(node: HTMLElement | SVGElement, className: string): boolean; + addClass(node: HTMLElement | SVGElement, className: string): void; + addClasses(node: HTMLElement | SVGElement, ...classNames: string[]): void; + removeClass(node: HTMLElement | SVGElement, className: string): void; + removeClasses(node: HTMLElement | SVGElement, ...classNames: string[]): void; + toggleClass(node: HTMLElement | SVGElement, className: string, shouldHaveIt?: boolean): void; } const _manualClassList = new class implements IDomClassList { @@ -191,12 +193,12 @@ const _nativeClassList = new class implements IDomClassList { // In IE11 there is only partial support for `classList` which makes us keep our // custom implementation. Otherwise use the native implementation, see: http://caniuse.com/#search=classlist const _classList: IDomClassList = browser.isIE ? _manualClassList : _nativeClassList; -export const hasClass: (node: HTMLElement, className: string) => boolean = _classList.hasClass.bind(_classList); -export const addClass: (node: HTMLElement, className: string) => void = _classList.addClass.bind(_classList); -export const addClasses: (node: HTMLElement, ...classNames: string[]) => void = _classList.addClasses.bind(_classList); -export const removeClass: (node: HTMLElement, className: string) => void = _classList.removeClass.bind(_classList); -export const removeClasses: (node: HTMLElement, ...classNames: string[]) => void = _classList.removeClasses.bind(_classList); -export const toggleClass: (node: HTMLElement, className: string, shouldHaveIt?: boolean) => void = _classList.toggleClass.bind(_classList); +export const hasClass: (node: HTMLElement | SVGElement, className: string) => boolean = _classList.hasClass.bind(_classList); +export const addClass: (node: HTMLElement | SVGElement, className: string) => void = _classList.addClass.bind(_classList); +export const addClasses: (node: HTMLElement | SVGElement, ...classNames: string[]) => void = _classList.addClasses.bind(_classList); +export const removeClass: (node: HTMLElement | SVGElement, className: string) => void = _classList.removeClass.bind(_classList); +export const removeClasses: (node: HTMLElement | SVGElement, ...classNames: string[]) => void = _classList.removeClasses.bind(_classList); +export const toggleClass: (node: HTMLElement | SVGElement, className: string, shouldHaveIt?: boolean) => void = _classList.toggleClass.bind(_classList); class DomListener implements IDisposable { @@ -768,6 +770,10 @@ export function findParentWithClass(node: HTMLElement, clazz: string, stopAtClaz return null; } +export function hasParentWithClass(node: HTMLElement, clazz: string, stopAtClazzOrNode?: string | HTMLElement): boolean { + return !!findParentWithClass(node, clazz, stopAtClazzOrNode); +} + export function createStyleSheet(container: HTMLElement = document.getElementsByTagName('head')[0]): HTMLStyleElement { let style = document.createElement('style'); style.type = 'text/css'; @@ -854,6 +860,8 @@ export const EventType = { ERROR: 'error', RESIZE: 'resize', SCROLL: 'scroll', + FULLSCREEN_CHANGE: 'fullscreenchange', + WK_FULLSCREEN_CHANGE: 'webkitfullscreenchange', // Form SELECT: 'select', CHANGE: 'change', @@ -905,10 +913,9 @@ export const EventHelper = { } }; -export interface IFocusTracker { +export interface IFocusTracker extends Disposable { onDidFocus: Event; onDidBlur: Event; - dispose(): void; } export function saveParentsScrollTop(node: Element): number[] { @@ -929,21 +936,20 @@ export function restoreParentsScrollTop(node: Element, state: number[]): void { } } -class FocusTracker implements IFocusTracker { - - private _onDidFocus = new Emitter(); - readonly onDidFocus: Event = this._onDidFocus.event; +class FocusTracker extends Disposable implements IFocusTracker { - private _onDidBlur = new Emitter(); - readonly onDidBlur: Event = this._onDidBlur.event; + private readonly _onDidFocus = this._register(new Emitter()); + public readonly onDidFocus: Event = this._onDidFocus.event; - private disposables: IDisposable[] = []; + private readonly _onDidBlur = this._register(new Emitter()); + public readonly onDidBlur: Event = this._onDidBlur.event; constructor(element: HTMLElement | Window) { + super(); let hasFocus = isAncestor(document.activeElement, element); let loosingFocus = false; - let onFocus = () => { + const onFocus = () => { loosingFocus = false; if (!hasFocus) { hasFocus = true; @@ -951,7 +957,7 @@ class FocusTracker implements IFocusTracker { } }; - let onBlur = () => { + const onBlur = () => { if (hasFocus) { loosingFocus = true; window.setTimeout(() => { @@ -964,14 +970,8 @@ class FocusTracker implements IFocusTracker { } }; - domEvent(element, EventType.FOCUS, true)(onFocus, null, this.disposables); - domEvent(element, EventType.BLUR, true)(onBlur, null, this.disposables); - } - - dispose(): void { - this.disposables = dispose(this.disposables); - this._onDidFocus.dispose(); - this._onDidBlur.dispose(); + this._register(domEvent(element, EventType.FOCUS, true)(onFocus)); + this._register(domEvent(element, EventType.BLUR, true)(onBlur)); } } @@ -991,14 +991,28 @@ export function prepend(parent: HTMLElement, child: T): T { const SELECTOR_REGEX = /([\w\-]+)?(#([\w\-]+))?((.([\w\-]+))*)/; -export function $(description: string, attrs?: { [key: string]: any; }, ...children: Array): T { +export enum Namespace { + HTML = 'http://www.w3.org/1999/xhtml', + SVG = 'http://www.w3.org/2000/svg' +} + +function _$(namespace: Namespace, description: string, attrs?: { [key: string]: any; }, ...children: Array): T { let match = SELECTOR_REGEX.exec(description); if (!match) { throw new Error('Bad use of emmet'); } - let result = document.createElement(match[1] || 'div'); + attrs = { ...(attrs || {}) }; + + let tagName = match[1] || 'div'; + let result: T; + + if (namespace !== Namespace.HTML) { + result = document.createElementNS(namespace as string, tagName) as T; + } else { + result = document.createElement(tagName) as unknown as T; + } if (match[3]) { result.id = match[3]; @@ -1007,7 +1021,6 @@ export function $(description: string, attrs?: { [key: st result.className = match[4].replace(/\./g, ' ').trim(); } - attrs = attrs || {}; Object.keys(attrs).forEach(name => { const value = attrs![name]; if (/^on\w+$/.test(name)) { @@ -1034,6 +1047,14 @@ export function $(description: string, attrs?: { [key: st return result as T; } +export function $(description: string, attrs?: { [key: string]: any; }, ...children: Array): T { + return _$(Namespace.HTML, description, attrs, ...children); +} + +$.SVG = function (description: string, attrs?: { [key: string]: any; }, ...children: Array): T { + return _$(Namespace.SVG, description, attrs, ...children); +}; + export function join(nodes: Node[], separator: Node | string): Node[] { const result: Node[] = []; @@ -1163,3 +1184,23 @@ export function animate(fn: () => void): IDisposable { let stepDisposable = scheduleAtNextAnimationFrame(step); return toDisposable(() => stepDisposable.dispose()); } + + + +const _location = URI.parse(window.location.href); + +export function asDomUri(uri: URI): URI { + if (!uri) { + return uri; + } + if (!platform.isWeb) { + //todo@joh remove this once we have sw in electron going + return uri; + } + if (Schemas.vscodeRemote === uri.scheme) { + // rewrite vscode-remote-uris to uris of the window location + // so that they can be intercepted by the service worker + return _location.with({ path: '/vscode-resources/fetch', query: `u=${JSON.stringify(uri)}` }); + } + return uri; +} diff --git a/src/vs/base/browser/globalMouseMoveMonitor.ts b/src/vs/base/browser/globalMouseMoveMonitor.ts index 892100647..109f6f722 100644 --- a/src/vs/base/browser/globalMouseMoveMonitor.ts +++ b/src/vs/base/browser/globalMouseMoveMonitor.ts @@ -6,7 +6,7 @@ import * as dom from 'vs/base/browser/dom'; import { IframeUtils } from 'vs/base/browser/iframe'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; -import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; export interface IStandardMouseMoveEventData { leftButton: boolean; @@ -36,24 +36,16 @@ export function standardMouseMoveMerger(lastEvent: IStandardMouseMoveEventData, }; } -export class GlobalMouseMoveMonitor extends Disposable { +export class GlobalMouseMoveMonitor implements IDisposable { - private hooks: IDisposable[]; - private mouseMoveEventMerger: IEventMerger | null; - private mouseMoveCallback: IMouseMoveCallback | null; - private onStopCallback: IOnStopCallback | null; - - constructor() { - super(); - this.hooks = []; - this.mouseMoveEventMerger = null; - this.mouseMoveCallback = null; - this.onStopCallback = null; - } + private readonly hooks = new DisposableStore(); + private mouseMoveEventMerger: IEventMerger | null = null; + private mouseMoveCallback: IMouseMoveCallback | null = null; + private onStopCallback: IOnStopCallback | null = null; public dispose(): void { this.stopMonitoring(false); - super.dispose(); + this.hooks.dispose(); } public stopMonitoring(invokeStopCallback: boolean): void { @@ -63,10 +55,10 @@ export class GlobalMouseMoveMonitor extends Disposable { } // Unhook - this.hooks = dispose(this.hooks); + this.hooks.clear(); this.mouseMoveEventMerger = null; this.mouseMoveCallback = null; - let onStopCallback = this.onStopCallback; + const onStopCallback = this.onStopCallback; this.onStopCallback = null; if (invokeStopCallback && onStopCallback) { @@ -74,8 +66,8 @@ export class GlobalMouseMoveMonitor extends Disposable { } } - public isMonitoring() { - return this.hooks.length > 0; + public isMonitoring(): boolean { + return !!this.mouseMoveEventMerger; } public startMonitoring( @@ -93,32 +85,32 @@ export class GlobalMouseMoveMonitor extends Disposable { let windowChain = IframeUtils.getSameOriginWindowChain(); for (const element of windowChain) { - this.hooks.push(dom.addDisposableThrottledListener(element.window.document, 'mousemove', + this.hooks.add(dom.addDisposableThrottledListener(element.window.document, 'mousemove', (data: R) => this.mouseMoveCallback!(data), (lastEvent: R, currentEvent) => this.mouseMoveEventMerger!(lastEvent, currentEvent as MouseEvent) )); - this.hooks.push(dom.addDisposableListener(element.window.document, 'mouseup', (e: MouseEvent) => this.stopMonitoring(true))); + this.hooks.add(dom.addDisposableListener(element.window.document, 'mouseup', (e: MouseEvent) => this.stopMonitoring(true))); } if (IframeUtils.hasDifferentOriginAncestor()) { let lastSameOriginAncestor = windowChain[windowChain.length - 1]; // We might miss a mouse up if it happens outside the iframe // This one is for Chrome - this.hooks.push(dom.addDisposableListener(lastSameOriginAncestor.window.document, 'mouseout', (browserEvent: MouseEvent) => { + this.hooks.add(dom.addDisposableListener(lastSameOriginAncestor.window.document, 'mouseout', (browserEvent: MouseEvent) => { let e = new StandardMouseEvent(browserEvent); if (e.target.tagName.toLowerCase() === 'html') { this.stopMonitoring(true); } })); // This one is for FF - this.hooks.push(dom.addDisposableListener(lastSameOriginAncestor.window.document, 'mouseover', (browserEvent: MouseEvent) => { + this.hooks.add(dom.addDisposableListener(lastSameOriginAncestor.window.document, 'mouseover', (browserEvent: MouseEvent) => { let e = new StandardMouseEvent(browserEvent); if (e.target.tagName.toLowerCase() === 'html') { this.stopMonitoring(true); } })); // This one is for IE - this.hooks.push(dom.addDisposableListener(lastSameOriginAncestor.window.document.body, 'mouseleave', (browserEvent: MouseEvent) => { + this.hooks.add(dom.addDisposableListener(lastSameOriginAncestor.window.document.body, 'mouseleave', (browserEvent: MouseEvent) => { this.stopMonitoring(true); })); } diff --git a/src/vs/base/browser/hash.ts b/src/vs/base/browser/hash.ts deleted file mode 100644 index eee8c0f56..000000000 --- a/src/vs/base/browser/hash.ts +++ /dev/null @@ -1,15 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -export function createSHA1(content: string): Thenable { - if (typeof require !== 'undefined') { - const _crypto: typeof crypto = require.__$__nodeRequire('crypto'); - return Promise.resolve(_crypto['createHash']('sha1').update(content).digest('hex')); - } - return crypto.subtle.digest('SHA-1', new TextEncoder().encode(content)).then(buffer => { - // https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#Converting_a_digest_to_a_hex_string - return Array.prototype.map.call(new Uint8Array(buffer), (value: number) => `00${value.toString(16)}`.slice(-2)).join(''); - }); -} \ No newline at end of file diff --git a/src/vs/base/browser/htmlContentRenderer.ts b/src/vs/base/browser/htmlContentRenderer.ts index 931447742..4506912e1 100644 --- a/src/vs/base/browser/htmlContentRenderer.ts +++ b/src/vs/base/browser/htmlContentRenderer.ts @@ -6,10 +6,10 @@ import * as DOM from 'vs/base/browser/dom'; import { defaultGenerator } from 'vs/base/common/idGenerator'; import { escape } from 'vs/base/common/strings'; -import { removeMarkdownEscapes, IMarkdownString } from 'vs/base/common/htmlContent'; +import { removeMarkdownEscapes, IMarkdownString, parseHrefAndDimensions } from 'vs/base/common/htmlContent'; import * as marked from 'vs/base/common/marked/marked'; import { IMouseEvent } from 'vs/base/browser/mouseEvent'; -import { IDisposable } from 'vs/base/common/lifecycle'; +import { DisposableStore } from 'vs/base/common/lifecycle'; import { onUnexpectedError } from 'vs/base/common/errors'; import { URI } from 'vs/base/common/uri'; import { parse } from 'vs/base/common/marshalling'; @@ -17,7 +17,7 @@ import { cloneAndChange } from 'vs/base/common/objects'; export interface IContentActionHandler { callback: (content: string, event?: IMouseEvent) => void; - disposeables: IDisposable[]; + readonly disposeables: DisposableStore; } export interface RenderOptions { @@ -75,12 +75,15 @@ export function renderMarkdown(markdown: IMarkdownString, options: RenderOptions return encodeURIComponent(JSON.stringify(data)); }; - const _href = function (href: string): string { + const _href = function (href: string, isDomUri: boolean): string { const data = markdown.uris && markdown.uris[href]; if (!data) { return href; } let uri = URI.revive(data); + if (isDomUri) { + uri = DOM.asDomUri(uri); + } if (uri.query) { uri = uri.with({ query: _uriMassage(uri.query) }); } @@ -97,29 +100,11 @@ export function renderMarkdown(markdown: IMarkdownString, options: RenderOptions const renderer = new marked.Renderer(); renderer.image = (href: string, title: string, text: string) => { - href = _href(href); let dimensions: string[] = []; - if (href) { - const splitted = href.split('|').map(s => s.trim()); - href = splitted[0]; - const parameters = splitted[1]; - if (parameters) { - const heightFromParams = /height=(\d+)/.exec(parameters); - const widthFromParams = /width=(\d+)/.exec(parameters); - const height = heightFromParams ? heightFromParams[1] : ''; - const width = widthFromParams ? widthFromParams[1] : ''; - const widthIsFinite = isFinite(parseInt(width)); - const heightIsFinite = isFinite(parseInt(height)); - if (widthIsFinite) { - dimensions.push(`width="${width}"`); - } - if (heightIsFinite) { - dimensions.push(`height="${height}"`); - } - } - } let attributes: string[] = []; if (href) { + ({ href, dimensions } = parseHrefAndDimensions(href)); + href = _href(href, true); attributes.push(`src="${href}"`); } if (text) { @@ -138,7 +123,7 @@ export function renderMarkdown(markdown: IMarkdownString, options: RenderOptions if (href === text) { // raw link case text = removeMarkdownEscapes(text); } - href = _href(href); + href = _href(href, false); title = removeMarkdownEscapes(title); href = removeMarkdownEscapes(href); if ( @@ -189,7 +174,7 @@ export function renderMarkdown(markdown: IMarkdownString, options: RenderOptions } if (options.actionHandler) { - options.actionHandler.disposeables.push(DOM.addStandardDisposableListener(element, 'click', event => { + options.actionHandler.disposeables.add(DOM.addStandardDisposableListener(element, 'click', event => { let target: HTMLElement | null = event.target; if (target.tagName !== 'A') { target = target.parentElement; @@ -284,7 +269,7 @@ function _renderFormattedText(element: Node, treeNode: IFormatParseTree, actionH else if (treeNode.type === FormatType.Action && actionHandler) { const a = document.createElement('a'); a.href = '#'; - actionHandler.disposeables.push(DOM.addStandardDisposableListener(a, 'click', (event) => { + actionHandler.disposeables.add(DOM.addStandardDisposableListener(a, 'click', (event) => { actionHandler.callback(String(treeNode.index), event); })); @@ -315,7 +300,7 @@ function parseFormattedText(content: string): IFormatParseTree { children: [] }; - let actionItemIndex = 0; + let actionViewItemIndex = 0; let current = root; const stack: IFormatParseTree[] = []; const stream = new StringStream(content); @@ -345,8 +330,8 @@ function parseFormattedText(content: string): IFormatParseTree { }; if (type === FormatType.Action) { - newCurrent.index = actionItemIndex; - actionItemIndex++; + newCurrent.index = actionViewItemIndex; + actionViewItemIndex++; } current.children!.push(newCurrent); diff --git a/src/vs/base/browser/mouseEvent.ts b/src/vs/base/browser/mouseEvent.ts index dee572ce8..4c7295e3b 100644 --- a/src/vs/base/browser/mouseEvent.ts +++ b/src/vs/base/browser/mouseEvent.ts @@ -160,6 +160,8 @@ export class StandardWheelEvent { this.deltaY = e1.wheelDeltaY / 120; } else if (typeof e2.VERTICAL_AXIS !== 'undefined' && e2.axis === e2.VERTICAL_AXIS) { this.deltaY = -e2.detail / 3; + } else { + this.deltaY = -e.deltaY / 40; } // horizontal delta scroll @@ -171,6 +173,8 @@ export class StandardWheelEvent { } } else if (typeof e2.HORIZONTAL_AXIS !== 'undefined' && e2.axis === e2.HORIZONTAL_AXIS) { this.deltaX = -e.detail / 3; + } else { + this.deltaX = -e.deltaX / 40; } // Assume a vertical scroll if nothing else worked @@ -195,4 +199,4 @@ export class StandardWheelEvent { } } } -} \ No newline at end of file +} diff --git a/src/vs/base/browser/ui/actionbar/actionbar.ts b/src/vs/base/browser/ui/actionbar/actionbar.ts index bbe176c19..413a25648 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.ts +++ b/src/vs/base/browser/ui/actionbar/actionbar.ts @@ -6,7 +6,7 @@ import 'vs/css!./actionbar'; import * as platform from 'vs/base/common/platform'; import * as nls from 'vs/nls'; -import { Disposable, dispose } from 'vs/base/common/lifecycle'; +import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle'; import { SelectBox, ISelectOptionItem, ISelectBoxOptions } from 'vs/base/browser/ui/selectBox/selectBox'; import { IAction, IActionRunner, Action, IActionChangeEvent, ActionRunner, IRunEvent } from 'vs/base/common/actions'; import * as DOM from 'vs/base/browser/dom'; @@ -16,24 +16,22 @@ import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview'; import { Event, Emitter } from 'vs/base/common/event'; -import { asArray } from 'vs/base/common/arrays'; -export interface IActionItem { +export interface IActionViewItem extends IDisposable { actionRunner: IActionRunner; setActionContext(context: any): void; render(element: HTMLElement): void; isEnabled(): boolean; focus(fromRight?: boolean): void; blur(): void; - dispose(): void; } -export interface IBaseActionItemOptions { +export interface IBaseActionViewItemOptions { draggable?: boolean; isMenu?: boolean; } -export class BaseActionItem extends Disposable implements IActionItem { +export class BaseActionViewItem extends Disposable implements IActionViewItem { element?: HTMLElement; _context: any; @@ -41,7 +39,7 @@ export class BaseActionItem extends Disposable implements IActionItem { private _actionRunner: IActionRunner; - constructor(context: any, action: IAction, protected options?: IBaseActionItemOptions) { + constructor(context: any, action: IAction, protected options?: IBaseActionViewItemOptions) { super(); this._context = context || this; @@ -226,20 +224,20 @@ export class Separator extends Action { } } -export interface IActionItemOptions extends IBaseActionItemOptions { +export interface IActionViewItemOptions extends IBaseActionViewItemOptions { icon?: boolean; label?: boolean; keybinding?: string | null; } -export class ActionItem extends BaseActionItem { +export class ActionViewItem extends BaseActionViewItem { protected label: HTMLElement; - protected options: IActionItemOptions; + protected options: IActionViewItemOptions; private cssClass?: string; - constructor(context: any, action: IAction, options: IActionItemOptions = {}) { + constructor(context: any, action: IAction, options: IActionViewItemOptions = {}) { super(context, action, options); this.options = options; @@ -363,14 +361,14 @@ export interface ActionTrigger { keyDown: boolean; } -export interface IActionItemProvider { - (action: IAction): IActionItem | undefined; +export interface IActionViewItemProvider { + (action: IAction): IActionViewItem | undefined; } export interface IActionBarOptions { orientation?: ActionsOrientation; context?: any; - actionItemProvider?: IActionItemProvider; + actionViewItemProvider?: IActionViewItemProvider; actionRunner?: IActionRunner; ariaLabel?: string; animated?: boolean; @@ -386,7 +384,7 @@ const defaultOptions: IActionBarOptions = { } }; -export interface IActionOptions extends IActionItemOptions { +export interface IActionOptions extends IActionViewItemOptions { index?: number; } @@ -397,8 +395,8 @@ export class ActionBar extends Disposable implements IActionRunner { private _actionRunner: IActionRunner; private _context: any; - // Items - items: IActionItem[]; + // View Items + viewItems: IActionViewItem[]; protected focusedItem?: number; private focusTracker: DOM.IFocusTracker; @@ -407,16 +405,16 @@ export class ActionBar extends Disposable implements IActionRunner { protected actionsList: HTMLElement; private _onDidBlur = this._register(new Emitter()); - get onDidBlur(): Event { return this._onDidBlur.event; } + readonly onDidBlur: Event = this._onDidBlur.event; private _onDidCancel = this._register(new Emitter()); - get onDidCancel(): Event { return this._onDidCancel.event; } + readonly onDidCancel: Event = this._onDidCancel.event; private _onDidRun = this._register(new Emitter()); - get onDidRun(): Event { return this._onDidRun.event; } + readonly onDidRun: Event = this._onDidRun.event; private _onDidBeforeRun = this._register(new Emitter()); - get onDidBeforeRun(): Event { return this._onDidBeforeRun.event; } + readonly onDidBeforeRun: Event = this._onDidBeforeRun.event; constructor(container: HTMLElement, options: IActionBarOptions = defaultOptions) { super(); @@ -438,7 +436,7 @@ export class ActionBar extends Disposable implements IActionRunner { this._register(this._actionRunner.onDidRun(e => this._onDidRun.fire(e))); this._register(this._actionRunner.onDidBeforeRun(e => this._onDidBeforeRun.fire(e))); - this.items = []; + this.viewItems = []; this.focusedItem = undefined; this.domNode = document.createElement('div'); @@ -575,7 +573,7 @@ export class ActionBar extends Disposable implements IActionRunner { set context(context: any) { this._context = context; - this.items.forEach(i => i.setActionContext(context)); + this.viewItems.forEach(i => i.setActionContext(context)); } get actionRunner(): IActionRunner { @@ -585,7 +583,7 @@ export class ActionBar extends Disposable implements IActionRunner { set actionRunner(actionRunner: IActionRunner) { if (actionRunner) { this._actionRunner = actionRunner; - this.items.forEach(item => item.actionRunner = actionRunner); + this.viewItems.forEach(item => item.actionRunner = actionRunner); } } @@ -593,42 +591,42 @@ export class ActionBar extends Disposable implements IActionRunner { return this.domNode; } - push(arg: IAction | IAction[], options: IActionOptions = {}): void { - const actions: IAction[] = asArray(arg); + push(arg: IAction | ReadonlyArray, options: IActionOptions = {}): void { + const actions: ReadonlyArray = Array.isArray(arg) ? arg : [arg]; let index = types.isNumber(options.index) ? options.index : null; actions.forEach((action: IAction) => { - const actionItemElement = document.createElement('li'); - actionItemElement.className = 'action-item'; - actionItemElement.setAttribute('role', 'presentation'); + const actionViewItemElement = document.createElement('li'); + actionViewItemElement.className = 'action-item'; + actionViewItemElement.setAttribute('role', 'presentation'); // Prevent native context menu on actions - this._register(DOM.addDisposableListener(actionItemElement, DOM.EventType.CONTEXT_MENU, (e: DOM.EventLike) => { + this._register(DOM.addDisposableListener(actionViewItemElement, DOM.EventType.CONTEXT_MENU, (e: DOM.EventLike) => { e.preventDefault(); e.stopPropagation(); })); - let item: IActionItem | undefined; + let item: IActionViewItem | undefined; - if (this.options.actionItemProvider) { - item = this.options.actionItemProvider(action); + if (this.options.actionViewItemProvider) { + item = this.options.actionViewItemProvider(action); } if (!item) { - item = new ActionItem(this.context, action, options); + item = new ActionViewItem(this.context, action, options); } item.actionRunner = this._actionRunner; item.setActionContext(this.context); - item.render(actionItemElement); + item.render(actionViewItemElement); if (index === null || index < 0 || index >= this.actionsList.children.length) { - this.actionsList.appendChild(actionItemElement); - this.items.push(item); + this.actionsList.appendChild(actionViewItemElement); + this.viewItems.push(item); } else { - this.actionsList.insertBefore(actionItemElement, this.actionsList.children[index]); - this.items.splice(index, 0, item); + this.actionsList.insertBefore(actionViewItemElement, this.actionsList.children[index]); + this.viewItems.splice(index, 0, item); index++; } }); @@ -657,23 +655,23 @@ export class ActionBar extends Disposable implements IActionRunner { } pull(index: number): void { - if (index >= 0 && index < this.items.length) { + if (index >= 0 && index < this.viewItems.length) { this.actionsList.removeChild(this.actionsList.childNodes[index]); - dispose(this.items.splice(index, 1)); + dispose(this.viewItems.splice(index, 1)); } } clear(): void { - this.items = dispose(this.items); + this.viewItems = dispose(this.viewItems); DOM.clearNode(this.actionsList); } length(): number { - return this.items.length; + return this.viewItems.length; } isEmpty(): boolean { - return this.items.length === 0; + return this.viewItems.length === 0; } focus(index?: number): void; @@ -691,7 +689,7 @@ export class ActionBar extends Disposable implements IActionRunner { if (selectFirst && typeof this.focusedItem === 'undefined') { // Focus the first enabled item - this.focusedItem = this.items.length - 1; + this.focusedItem = this.viewItems.length - 1; this.focusNext(); } else { if (index !== undefined) { @@ -704,15 +702,15 @@ export class ActionBar extends Disposable implements IActionRunner { protected focusNext(): void { if (typeof this.focusedItem === 'undefined') { - this.focusedItem = this.items.length - 1; + this.focusedItem = this.viewItems.length - 1; } const startIndex = this.focusedItem; - let item: IActionItem; + let item: IActionViewItem; do { - this.focusedItem = (this.focusedItem + 1) % this.items.length; - item = this.items[this.focusedItem]; + this.focusedItem = (this.focusedItem + 1) % this.viewItems.length; + item = this.viewItems[this.focusedItem]; } while (this.focusedItem !== startIndex && !item.isEnabled()); if (this.focusedItem === startIndex && !item.isEnabled()) { @@ -728,16 +726,16 @@ export class ActionBar extends Disposable implements IActionRunner { } const startIndex = this.focusedItem; - let item: IActionItem; + let item: IActionViewItem; do { this.focusedItem = this.focusedItem - 1; if (this.focusedItem < 0) { - this.focusedItem = this.items.length - 1; + this.focusedItem = this.viewItems.length - 1; } - item = this.items[this.focusedItem]; + item = this.viewItems[this.focusedItem]; } while (this.focusedItem !== startIndex && !item.isEnabled()); if (this.focusedItem === startIndex && !item.isEnabled()) { @@ -752,21 +750,21 @@ export class ActionBar extends Disposable implements IActionRunner { this.actionsList.focus(); } - for (let i = 0; i < this.items.length; i++) { - const item = this.items[i]; - const actionItem = item; + for (let i = 0; i < this.viewItems.length; i++) { + const item = this.viewItems[i]; + const actionViewItem = item; if (i === this.focusedItem) { - if (types.isFunction(actionItem.isEnabled)) { - if (actionItem.isEnabled() && types.isFunction(actionItem.focus)) { - actionItem.focus(fromRight); + if (types.isFunction(actionViewItem.isEnabled)) { + if (actionViewItem.isEnabled() && types.isFunction(actionViewItem.focus)) { + actionViewItem.focus(fromRight); } else { this.actionsList.focus(); } } } else { - if (types.isFunction(actionItem.blur)) { - actionItem.blur(); + if (types.isFunction(actionViewItem.blur)) { + actionViewItem.blur(); } } } @@ -778,16 +776,16 @@ export class ActionBar extends Disposable implements IActionRunner { } // trigger action - const actionItem = this.items[this.focusedItem]; - if (actionItem instanceof BaseActionItem) { - const context = (actionItem._context === null || actionItem._context === undefined) ? event : actionItem._context; - this.run(actionItem._action, context); + const actionViewItem = this.viewItems[this.focusedItem]; + if (actionViewItem instanceof BaseActionViewItem) { + const context = (actionViewItem._context === null || actionViewItem._context === undefined) ? event : actionViewItem._context; + this.run(actionViewItem._action, context); } } private cancel(): void { if (document.activeElement instanceof HTMLElement) { - (document.activeElement).blur(); // remove focus from focused action + document.activeElement.blur(); // remove focus from focused action } this._onDidCancel.fire(); @@ -798,8 +796,8 @@ export class ActionBar extends Disposable implements IActionRunner { } dispose(): void { - dispose(this.items); - this.items = []; + dispose(this.viewItems); + this.viewItems = []; DOM.removeNode(this.getContainer()); @@ -807,7 +805,7 @@ export class ActionBar extends Disposable implements IActionRunner { } } -export class SelectActionItem extends BaseActionItem { +export class SelectActionViewItem extends BaseActionViewItem { protected selectBox: SelectBox; constructor(ctx: any, action: IAction, options: ISelectOptionItem[], selected: number, contextViewProvider: IContextViewProvider, selectBoxOptions?: ISelectBoxOptions) { diff --git a/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.css b/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.css index afade1a34..1e49da134 100644 --- a/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.css +++ b/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.css @@ -31,12 +31,16 @@ } .monaco-breadcrumbs .monaco-breadcrumb-item:not(:nth-child(2))::before { - background-image: url(./collapsed.svg); + background-image: url(./tree-collapsed-light.svg); opacity: .7; background-size: 16px; background-position: 50% 50%; } .vs-dark .monaco-breadcrumbs .monaco-breadcrumb-item:not(:nth-child(2))::before { - background-image: url(./collpased-dark.svg); + background-image: url(./tree-collapsed-dark.svg); +} + +.hc-black .monaco-breadcrumbs .monaco-breadcrumb-item:not(:nth-child(2))::before { + background-image: url(./tree-collapsed-hc.svg); } diff --git a/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts b/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts index 28658f3ee..13e4b9c34 100644 --- a/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts +++ b/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts @@ -9,7 +9,7 @@ import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableEle import { commonPrefixLength } from 'vs/base/common/arrays'; import { Color } from 'vs/base/common/color'; import { Emitter, Event } from 'vs/base/common/event'; -import { dispose, IDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; +import { dispose, IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { ScrollbarVisibility } from 'vs/base/common/scrollable'; import 'vs/css!./breadcrumbsWidget'; @@ -57,7 +57,7 @@ export interface IBreadcrumbsItemEvent { export class BreadcrumbsWidget { - private readonly _disposables = new Array(); + private readonly _disposables = new DisposableStore(); private readonly _domNode: HTMLDivElement; private readonly _styleElement: HTMLStyleElement; private readonly _scrollable: DomScrollableElement; @@ -94,26 +94,25 @@ export class BreadcrumbsWidget { useShadows: false, scrollYToX: true }); - this._disposables.push(this._scrollable); - this._disposables.push(dom.addStandardDisposableListener(this._domNode, 'click', e => this._onClick(e))); + this._disposables.add(this._scrollable); + this._disposables.add(dom.addStandardDisposableListener(this._domNode, 'click', e => this._onClick(e))); container.appendChild(this._scrollable.getDomNode()); this._styleElement = dom.createStyleSheet(this._domNode); - let focusTracker = dom.trackFocus(this._domNode); - this._disposables.push(focusTracker); - this._disposables.push(focusTracker.onDidBlur(_ => this._onDidChangeFocus.fire(false))); - this._disposables.push(focusTracker.onDidFocus(_ => this._onDidChangeFocus.fire(true))); + const focusTracker = dom.trackFocus(this._domNode); + this._disposables.add(focusTracker); + this._disposables.add(focusTracker.onDidBlur(_ => this._onDidChangeFocus.fire(false))); + this._disposables.add(focusTracker.onDidFocus(_ => this._onDidChangeFocus.fire(true))); } dispose(): void { - dispose(this._disposables); + this._disposables.dispose(); dispose(this._pendingLayout); this._onDidSelectItem.dispose(); this._onDidFocusItem.dispose(); this._onDidChangeFocus.dispose(); this._domNode.remove(); - this._disposables.length = 0; this._nodes.length = 0; this._freeNodes.length = 0; } @@ -134,14 +133,14 @@ export class BreadcrumbsWidget { } private _updateDimensions(dim: dom.Dimension): IDisposable { - let disposables: IDisposable[] = []; - disposables.push(dom.modify(() => { + const disposables = new DisposableStore(); + disposables.add(dom.modify(() => { this._dimension = dim; this._domNode.style.width = `${dim.width}px`; this._domNode.style.height = `${dim.height}px`; - disposables.push(this._updateScrollbar()); + disposables.add(this._updateScrollbar()); })); - return combinedDisposable(disposables); + return disposables; } private _updateScrollbar(): IDisposable { diff --git a/src/vs/base/browser/ui/breadcrumbs/collapsed.svg b/src/vs/base/browser/ui/breadcrumbs/collapsed.svg deleted file mode 100755 index 3a63808c3..000000000 --- a/src/vs/base/browser/ui/breadcrumbs/collapsed.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/base/browser/ui/breadcrumbs/collpased-dark.svg b/src/vs/base/browser/ui/breadcrumbs/collpased-dark.svg deleted file mode 100755 index cf5c3641a..000000000 --- a/src/vs/base/browser/ui/breadcrumbs/collpased-dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/base/browser/ui/breadcrumbs/tree-collapsed-dark.svg b/src/vs/base/browser/ui/breadcrumbs/tree-collapsed-dark.svg new file mode 100644 index 000000000..243be1451 --- /dev/null +++ b/src/vs/base/browser/ui/breadcrumbs/tree-collapsed-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/breadcrumbs/tree-collapsed-hc.svg b/src/vs/base/browser/ui/breadcrumbs/tree-collapsed-hc.svg new file mode 100644 index 000000000..40ba72b70 --- /dev/null +++ b/src/vs/base/browser/ui/breadcrumbs/tree-collapsed-hc.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/breadcrumbs/tree-collapsed-light.svg b/src/vs/base/browser/ui/breadcrumbs/tree-collapsed-light.svg new file mode 100644 index 000000000..0d746558a --- /dev/null +++ b/src/vs/base/browser/ui/breadcrumbs/tree-collapsed-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/centered/centeredViewLayout.ts b/src/vs/base/browser/ui/centered/centeredViewLayout.ts index a776ba92a..299b65348 100644 --- a/src/vs/base/browser/ui/centered/centeredViewLayout.ts +++ b/src/vs/base/browser/ui/centered/centeredViewLayout.ts @@ -6,8 +6,8 @@ import { SplitView, Orientation, ISplitViewStyles, IView as ISplitViewView } from 'vs/base/browser/ui/splitview/splitview'; import { $ } from 'vs/base/browser/dom'; import { Event } from 'vs/base/common/event'; -import { IView } from 'vs/base/browser/ui/grid/gridview'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IView, IViewSize } from 'vs/base/browser/ui/grid/grid'; +import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { Color } from 'vs/base/common/color'; export interface CenteredViewState { @@ -48,7 +48,7 @@ export interface ICenteredViewStyles extends ISplitViewStyles { background: Color; } -export class CenteredViewLayout { +export class CenteredViewLayout implements IDisposable { private splitView?: SplitView; private width: number = 0; @@ -56,7 +56,7 @@ export class CenteredViewLayout { private style: ICenteredViewStyles; private didLayout = false; private emptyViews: ISplitViewView[] | undefined; - private splitViewDisposables: IDisposable[] = []; + private readonly splitViewDisposables = new DisposableStore(); constructor(private container: HTMLElement, private view: IView, public readonly state: CenteredViewState = { leftMarginRatio: GOLDEN_RATIO.leftMarginRatio, rightMarginRatio: GOLDEN_RATIO.rightMarginRatio }) { this.container.appendChild(this.view.element); @@ -68,6 +68,7 @@ export class CenteredViewLayout { get maximumWidth(): number { return this.splitView ? this.splitView.maximumSize : this.view.maximumWidth; } get minimumHeight(): number { return this.view.minimumHeight; } get maximumHeight(): number { return this.view.maximumHeight; } + get onDidChange(): Event { return this.view.onDidChange; } layout(width: number, height: number): void { this.width = width; @@ -117,13 +118,13 @@ export class CenteredViewLayout { styles: this.style }); - this.splitViewDisposables.push(this.splitView.onDidSashChange(() => { + this.splitViewDisposables.add(this.splitView.onDidSashChange(() => { if (this.splitView) { this.state.leftMarginRatio = this.splitView.getViewSize(0) / this.width; this.state.rightMarginRatio = this.splitView.getViewSize(2) / this.width; } })); - this.splitViewDisposables.push(this.splitView.onDidSashReset(() => { + this.splitViewDisposables.add(this.splitView.onDidSashReset(() => { this.state.leftMarginRatio = GOLDEN_RATIO.leftMarginRatio; this.state.rightMarginRatio = GOLDEN_RATIO.rightMarginRatio; this.resizeMargins(); @@ -138,7 +139,7 @@ export class CenteredViewLayout { if (this.splitView) { this.container.removeChild(this.splitView.el); } - this.splitViewDisposables = dispose(this.splitViewDisposables); + this.splitViewDisposables.clear(); if (this.splitView) { this.splitView.dispose(); } @@ -153,7 +154,7 @@ export class CenteredViewLayout { } dispose(): void { - this.splitViewDisposables = dispose(this.splitViewDisposables); + this.splitViewDisposables.dispose(); if (this.splitView) { this.splitView.dispose(); diff --git a/src/vs/base/browser/ui/checkbox/checkbox.ts b/src/vs/base/browser/ui/checkbox/checkbox.ts index 73f7ca972..723f64dc4 100644 --- a/src/vs/base/browser/ui/checkbox/checkbox.ts +++ b/src/vs/base/browser/ui/checkbox/checkbox.ts @@ -11,8 +11,8 @@ import { Color } from 'vs/base/common/color'; import { Emitter, Event } from 'vs/base/common/event'; import { KeyCode } from 'vs/base/common/keyCodes'; import * as objects from 'vs/base/common/objects'; -import { BaseActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; +import { DisposableStore } from 'vs/base/common/lifecycle'; export interface ICheckboxOpts extends ICheckboxStyles { readonly actionClassName?: string; @@ -22,28 +22,30 @@ export interface ICheckboxOpts extends ICheckboxStyles { export interface ICheckboxStyles { inputActiveOptionBorder?: Color; + inputActiveOptionBackground?: Color; } const defaultOpts = { - inputActiveOptionBorder: Color.fromHex('#007ACC') + inputActiveOptionBorder: Color.fromHex('#007ACC00'), + inputActiveOptionBackground: Color.fromHex('#0E639C50') }; -export class CheckboxActionItem extends BaseActionItem { +export class CheckboxActionViewItem extends BaseActionViewItem { private checkbox: Checkbox; - private disposables: IDisposable[] = []; + private readonly disposables = new DisposableStore(); render(container: HTMLElement): void { this.element = container; - this.disposables = dispose(this.disposables); + this.disposables.clear(); this.checkbox = new Checkbox({ actionClassName: this._action.class, isChecked: this._action.checked, title: this._action.label }); - this.disposables.push(this.checkbox); - this.checkbox.onChange(() => this._action.checked = this.checkbox.checked, this, this.disposables); + this.disposables.add(this.checkbox); + this.disposables.add(this.checkbox.onChange(() => this._action.checked = this.checkbox.checked, this)); this.element.appendChild(this.checkbox.domNode); } @@ -63,20 +65,19 @@ export class CheckboxActionItem extends BaseActionItem { } } - dipsose(): void { - this.disposables = dispose(this.disposables); + dispose(): void { + this.disposables.dispose(); super.dispose(); } - } export class Checkbox extends Widget { private readonly _onChange = this._register(new Emitter()); - get onChange(): Event { return this._onChange.event; } + readonly onChange: Event = this._onChange.event; private readonly _onKeyDown = this._register(new Emitter()); - get onKeyDown(): Event { return this._onKeyDown.event; } + readonly onKeyDown: Event = this._onKeyDown.event; private readonly _opts: ICheckboxOpts; readonly domNode: HTMLElement; @@ -150,12 +151,16 @@ export class Checkbox extends Widget { if (styles.inputActiveOptionBorder) { this._opts.inputActiveOptionBorder = styles.inputActiveOptionBorder; } + if (styles.inputActiveOptionBackground) { + this._opts.inputActiveOptionBackground = styles.inputActiveOptionBackground; + } this.applyStyles(); } protected applyStyles(): void { if (this.domNode) { this.domNode.style.borderColor = this._checked && this._opts.inputActiveOptionBorder ? this._opts.inputActiveOptionBorder.toString() : 'transparent'; + this.domNode.style.backgroundColor = this._checked && this._opts.inputActiveOptionBackground ? this._opts.inputActiveOptionBackground.toString() : 'transparent'; } } diff --git a/src/vs/base/browser/ui/contextview/contextview.ts b/src/vs/base/browser/ui/contextview/contextview.ts index 193359ecc..719126e63 100644 --- a/src/vs/base/browser/ui/contextview/contextview.ts +++ b/src/vs/base/browser/ui/contextview/contextview.ts @@ -5,7 +5,7 @@ import 'vs/css!./contextview'; import * as DOM from 'vs/base/browser/dom'; -import { IDisposable, dispose, toDisposable, combinedDisposable, Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, toDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { Range } from 'vs/base/common/range'; export interface IAnchor { @@ -128,21 +128,21 @@ export class ContextView extends Disposable { this.container = container; this.container.appendChild(this.view); - const toDisposeOnSetContainer: IDisposable[] = []; + const toDisposeOnSetContainer = new DisposableStore(); ContextView.BUBBLE_UP_EVENTS.forEach(event => { - toDisposeOnSetContainer.push(DOM.addStandardDisposableListener(this.container!, event, (e: Event) => { - this.onDOMEvent(e, document.activeElement, false); + toDisposeOnSetContainer.add(DOM.addStandardDisposableListener(this.container!, event, (e: Event) => { + this.onDOMEvent(e, false); })); }); ContextView.BUBBLE_DOWN_EVENTS.forEach(event => { - toDisposeOnSetContainer.push(DOM.addStandardDisposableListener(this.container!, event, (e: Event) => { - this.onDOMEvent(e, document.activeElement, true); + toDisposeOnSetContainer.add(DOM.addStandardDisposableListener(this.container!, event, (e: Event) => { + this.onDOMEvent(e, true); }, true)); }); - this.toDisposeOnSetContainer = combinedDisposable(toDisposeOnSetContainer); + this.toDisposeOnSetContainer = toDisposeOnSetContainer; } } @@ -213,13 +213,11 @@ export class ContextView extends Disposable { height: elementPosition.height }; } else { - let realAnchor = anchor; - around = { - top: realAnchor.y, - left: realAnchor.x, - width: realAnchor.width || 1, - height: realAnchor.height || 2 + top: anchor.y, + left: anchor.x, + width: anchor.width || 1, + height: anchor.height || 2 }; } @@ -244,6 +242,9 @@ export class ContextView extends Disposable { // if view intersects vertically with anchor, shift it horizontally if (Range.intersects({ start: top, end: top + viewSizeHeight }, { start: verticalAnchor.offset, end: verticalAnchor.offset + verticalAnchor.size })) { horizontalAnchor.size = around.width; + if (anchorAlignment === AnchorAlignment.RIGHT) { + horizontalAnchor.offset = around.left; + } } const left = layout(window.innerWidth, viewSizeWidth, horizontalAnchor); @@ -259,12 +260,13 @@ export class ContextView extends Disposable { } hide(data?: any): void { - if (this.delegate && this.delegate.onHide) { - this.delegate.onHide(data); - } - + const delegate = this.delegate; this.delegate = null; + if (delegate && delegate.onHide) { + delegate.onHide(data); + } + if (this.toDisposeOnClean) { this.toDisposeOnClean.dispose(); this.toDisposeOnClean = null; @@ -277,7 +279,7 @@ export class ContextView extends Disposable { return !!this.delegate; } - private onDOMEvent(e: Event, element: HTMLElement, onCapture: boolean): void { + private onDOMEvent(e: Event, onCapture: boolean): void { if (this.delegate) { if (this.delegate.onDOMEvent) { this.delegate.onDOMEvent(e, document.activeElement); diff --git a/src/vs/base/browser/ui/countBadge/countBadge.css b/src/vs/base/browser/ui/countBadge/countBadge.css index 7429322f3..909fa7c8e 100644 --- a/src/vs/base/browser/ui/countBadge/countBadge.css +++ b/src/vs/base/browser/ui/countBadge/countBadge.css @@ -4,11 +4,12 @@ *--------------------------------------------------------------------------------------------*/ .monaco-count-badge { - padding: 0.3em 0.5em; - border-radius: 1em; - font-size: 85%; - min-width: 1.6em; - line-height: 1em; + padding: 3px 5px; + border-radius: 11px; + font-size: 11px; + min-width: 18px; + min-height: 18px; + line-height: 11px; font-weight: normal; text-align: center; display: inline-block; diff --git a/src/vs/base/browser/ui/dialog/close-dark.svg b/src/vs/base/browser/ui/dialog/close-dark.svg new file mode 100644 index 000000000..7305a8f09 --- /dev/null +++ b/src/vs/base/browser/ui/dialog/close-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/dialog/close-inverse.svg b/src/vs/base/browser/ui/dialog/close-inverse.svg deleted file mode 100644 index a174033d9..000000000 --- a/src/vs/base/browser/ui/dialog/close-inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/base/browser/ui/dialog/close-light.svg b/src/vs/base/browser/ui/dialog/close-light.svg new file mode 100644 index 000000000..ecddcd665 --- /dev/null +++ b/src/vs/base/browser/ui/dialog/close-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/dialog/close.svg b/src/vs/base/browser/ui/dialog/close.svg deleted file mode 100644 index f4038b8bf..000000000 --- a/src/vs/base/browser/ui/dialog/close.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/base/browser/ui/dialog/dialog.css b/src/vs/base/browser/ui/dialog/dialog.css index c909dada7..e05ed90a9 100644 --- a/src/vs/base/browser/ui/dialog/dialog.css +++ b/src/vs/base/browser/ui/dialog/dialog.css @@ -47,12 +47,12 @@ .monaco-workbench .dialog-box .dialog-close-action { - background: url('close.svg') center center no-repeat; + background: url('close-light.svg') center center no-repeat; } .vs-dark .monaco-workbench .dialog-box .dialog-close-action, .hc-black .monaco-workbench .dialog-box .dialog-close-action { - background: url('close-inverse.svg') center center no-repeat; + background: url('close-dark.svg') center center no-repeat; } /** Dialog: Message Row */ @@ -64,12 +64,12 @@ } .monaco-workbench .dialog-box .dialog-message-row .dialog-icon { - flex: 0 0 30px; - height: 30px; - padding-right: 4px; - padding-left: 4px; + flex: 0 0 40px; + height: 40px; + align-self: baseline; background-position: center; background-repeat: no-repeat; + background-size: 40px; } .vs .monaco-workbench .dialog-box .dialog-message-row .dialog-icon.icon-pending { @@ -77,15 +77,15 @@ } .vs .monaco-workbench .dialog-box .dialog-message-row .dialog-icon.icon-info { - background-image: url('info.svg'); + background-image: url('info-light.svg'); } .vs .monaco-workbench .dialog-box .dialog-message-row .dialog-icon.icon-warning { - background-image: url('warning.svg'); + background-image: url('warning-light.svg'); } .vs .monaco-workbench .dialog-box .dialog-message-row .dialog-icon.icon-error { - background-image: url('error.svg'); + background-image: url('error-light.svg'); } .vs-dark .monaco-workbench .dialog-box .dialog-message-row .dialog-icon.icon-pending { @@ -94,17 +94,17 @@ .vs-dark .monaco-workbench .dialog-box .dialog-message-row .dialog-icon.icon-info, .hc-black .monaco-workbench .dialog-box .dialog-message-row .dialog-icon.icon-info { - background-image: url('info-inverse.svg'); + background-image: url('info-dark.svg'); } .vs-dark .monaco-workbench .dialog-box .dialog-message-row .dialog-icon.icon-warning, .hc-black .monaco-workbench .dialog-box .dialog-message-row .dialog-icon.icon-warning { - background-image: url('warning-inverse.svg'); + background-image: url('warning-dark.svg'); } .vs-dark .monaco-workbench .dialog-box .dialog-message-row .dialog-icon.icon-error, .hc-black .monaco-workbench .dialog-box .dialog-message-row .dialog-icon.icon-error { - background-image: url('error-inverse.svg'); + background-image: url('error-dark.svg'); } .hc-black .monaco-workbench .dialog-box .dialog-message-row .dialog-icon.icon-pending { diff --git a/src/vs/base/browser/ui/dialog/dialog.ts b/src/vs/base/browser/ui/dialog/dialog.ts index c19356b43..2e95c5955 100644 --- a/src/vs/base/browser/ui/dialog/dialog.ts +++ b/src/vs/base/browser/ui/dialog/dialog.ts @@ -15,6 +15,7 @@ import { ButtonGroup, IButtonStyles } from 'vs/base/browser/ui/button/button'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { Action } from 'vs/base/common/actions'; import { mnemonicButtonLabel } from 'vs/base/common/labels'; +import { isMacintosh, isLinux } from 'vs/base/common/platform'; export interface IDialogOptions { cancelId?: number; @@ -30,6 +31,11 @@ export interface IDialogStyles extends IButtonStyles { dialogBorder?: Color; } +interface ButtonMapEntry { + label: string; + index: number; +} + export class Dialog extends Disposable { private element: HTMLElement | undefined; private modal: HTMLElement | undefined; @@ -91,13 +97,22 @@ export class Dialog extends Disposable { clearNode(this.buttonsContainer); let focusedButton = 0; - this.buttonGroup = new ButtonGroup(this.buttonsContainer, this.buttons.length, { title: true }); - this.buttonGroup.buttons.forEach((button, index) => { - button.label = mnemonicButtonLabel(this.buttons[index], true); + const buttonGroup = this.buttonGroup = new ButtonGroup(this.buttonsContainer, this.buttons.length, { title: true }); + const buttonMap = this.rearrangeButtons(this.buttons, this.options.cancelId); + + // Set focused button to UI index + buttonMap.forEach((value, index) => { + if (value.index === 0) { + focusedButton = index; + } + }); + + buttonGroup.buttons.forEach((button, index) => { + button.label = mnemonicButtonLabel(buttonMap[index].label, true); this._register(button.onDidClick(e => { EventHelper.stop(e); - resolve(index); + resolve(buttonMap[index].index); })); }); @@ -108,18 +123,16 @@ export class Dialog extends Disposable { } let eventHandled = false; - if (this.buttonGroup) { - if (evt.equals(KeyMod.Shift | KeyCode.Tab) || evt.equals(KeyCode.LeftArrow)) { - focusedButton = focusedButton + this.buttonGroup.buttons.length - 1; - focusedButton = focusedButton % this.buttonGroup.buttons.length; - this.buttonGroup.buttons[focusedButton].focus(); - eventHandled = true; - } else if (evt.equals(KeyCode.Tab) || evt.equals(KeyCode.RightArrow)) { - focusedButton++; - focusedButton = focusedButton % this.buttonGroup.buttons.length; - this.buttonGroup.buttons[focusedButton].focus(); - eventHandled = true; - } + if (evt.equals(KeyMod.Shift | KeyCode.Tab) || evt.equals(KeyCode.LeftArrow)) { + focusedButton = focusedButton + buttonGroup.buttons.length - 1; + focusedButton = focusedButton % buttonGroup.buttons.length; + buttonGroup.buttons[focusedButton].focus(); + eventHandled = true; + } else if (evt.equals(KeyCode.Tab) || evt.equals(KeyCode.RightArrow)) { + focusedButton++; + focusedButton = focusedButton % buttonGroup.buttons.length; + buttonGroup.buttons[focusedButton].focus(); + eventHandled = true; } if (eventHandled) { @@ -185,7 +198,7 @@ export class Dialog extends Disposable { show(this.element); // Focus first element - this.buttonGroup.buttons[focusedButton].focus(); + buttonGroup.buttons[focusedButton].focus(); }); } @@ -228,4 +241,23 @@ export class Dialog extends Disposable { this.focusToReturn = undefined; } } + + private rearrangeButtons(buttons: Array, cancelId: number | undefined): ButtonMapEntry[] { + const buttonMap: ButtonMapEntry[] = []; + // Maps each button to its current label and old index so that when we move them around it's not a problem + buttons.forEach((button, index) => { + buttonMap.push({ label: button, index: index }); + }); + + // macOS/linux: reverse button order + if (isMacintosh || isLinux) { + if (cancelId !== undefined) { + const cancelButton = buttonMap.splice(cancelId, 1)[0]; + buttonMap.reverse(); + buttonMap.splice(buttonMap.length - 1, 0, cancelButton); + } + } + + return buttonMap; + } } \ No newline at end of file diff --git a/src/vs/base/browser/ui/dialog/error-dark.svg b/src/vs/base/browser/ui/dialog/error-dark.svg new file mode 100644 index 000000000..efdc5f2ae --- /dev/null +++ b/src/vs/base/browser/ui/dialog/error-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/dialog/error-inverse.svg b/src/vs/base/browser/ui/dialog/error-inverse.svg deleted file mode 100644 index 51e9dc81b..000000000 --- a/src/vs/base/browser/ui/dialog/error-inverse.svg +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/src/vs/base/browser/ui/dialog/error-light.svg b/src/vs/base/browser/ui/dialog/error-light.svg new file mode 100644 index 000000000..d646c72c7 --- /dev/null +++ b/src/vs/base/browser/ui/dialog/error-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/dialog/error.svg b/src/vs/base/browser/ui/dialog/error.svg deleted file mode 100644 index 04b666890..000000000 --- a/src/vs/base/browser/ui/dialog/error.svg +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/src/vs/base/browser/ui/dialog/info-dark.svg b/src/vs/base/browser/ui/dialog/info-dark.svg new file mode 100644 index 000000000..bb851afdf --- /dev/null +++ b/src/vs/base/browser/ui/dialog/info-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/dialog/info-inverse.svg b/src/vs/base/browser/ui/dialog/info-inverse.svg deleted file mode 100644 index 64b801a63..000000000 --- a/src/vs/base/browser/ui/dialog/info-inverse.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - diff --git a/src/vs/base/browser/ui/dialog/info-light.svg b/src/vs/base/browser/ui/dialog/info-light.svg new file mode 100644 index 000000000..6faf670cc --- /dev/null +++ b/src/vs/base/browser/ui/dialog/info-light.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/vs/base/browser/ui/dialog/info.svg b/src/vs/base/browser/ui/dialog/info.svg deleted file mode 100644 index 3c603528a..000000000 --- a/src/vs/base/browser/ui/dialog/info.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - diff --git a/src/vs/base/browser/ui/dialog/warning-dark.svg b/src/vs/base/browser/ui/dialog/warning-dark.svg new file mode 100644 index 000000000..a267963e5 --- /dev/null +++ b/src/vs/base/browser/ui/dialog/warning-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/dialog/warning-inverse.svg b/src/vs/base/browser/ui/dialog/warning-inverse.svg deleted file mode 100644 index a7f4afbcc..000000000 --- a/src/vs/base/browser/ui/dialog/warning-inverse.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - -StatusWarning_16x - - - - - diff --git a/src/vs/base/browser/ui/dialog/warning-light.svg b/src/vs/base/browser/ui/dialog/warning-light.svg new file mode 100644 index 000000000..f2e2aa741 --- /dev/null +++ b/src/vs/base/browser/ui/dialog/warning-light.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/vs/base/browser/ui/dialog/warning.svg b/src/vs/base/browser/ui/dialog/warning.svg deleted file mode 100644 index 6d8cffe91..000000000 --- a/src/vs/base/browser/ui/dialog/warning.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - -StatusWarning_16x - - - - - diff --git a/src/vs/base/browser/ui/dropdown/dropdown.ts b/src/vs/base/browser/ui/dropdown/dropdown.ts index d033d75ef..1f9217cc9 100644 --- a/src/vs/base/browser/ui/dropdown/dropdown.ts +++ b/src/vs/base/browser/ui/dropdown/dropdown.ts @@ -6,7 +6,7 @@ import 'vs/css!./dropdown'; import { Gesture, EventType as GestureEventType } from 'vs/base/browser/touch'; import { ActionRunner, IAction, IActionRunner } from 'vs/base/common/actions'; -import { BaseActionItem, IActionItemProvider } from 'vs/base/browser/ui/actionbar/actionbar'; +import { BaseActionViewItem, IActionViewItemProvider } from 'vs/base/browser/ui/actionbar/actionbar'; import { IDisposable } from 'vs/base/common/lifecycle'; import { IContextViewProvider, IAnchor, AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview'; import { IMenuOptions } from 'vs/base/browser/ui/menu/menu'; @@ -108,6 +108,10 @@ export class BaseDropdown extends ActionRunner { this.visible = false; } + isVisible(): boolean { + return this.visible; + } + protected onEvent(e: Event, activeElement: HTMLElement): void { this.hide(); } @@ -192,12 +196,12 @@ export interface IContextMenuProvider { } export interface IActionProvider { - getActions(): IAction[]; + getActions(): ReadonlyArray; } export interface IDropdownMenuOptions extends IBaseDropdownOptions { contextMenuProvider: IContextMenuProvider; - actions?: IAction[]; + actions?: ReadonlyArray; actionProvider?: IActionProvider; menuClassName?: string; } @@ -205,7 +209,7 @@ export interface IDropdownMenuOptions extends IBaseDropdownOptions { export class DropdownMenu extends BaseDropdown { private _contextMenuProvider: IContextMenuProvider; private _menuOptions: IMenuOptions; - private _actions: IAction[]; + private _actions: ReadonlyArray; private actionProvider?: IActionProvider; private menuClassName: string; @@ -226,7 +230,7 @@ export class DropdownMenu extends BaseDropdown { return this._menuOptions; } - private get actions(): IAction[] { + private get actions(): ReadonlyArray { if (this.actionProvider) { return this.actionProvider.getActions(); } @@ -234,7 +238,7 @@ export class DropdownMenu extends BaseDropdown { return this._actions; } - private set actions(actions: IAction[]) { + private set actions(actions: ReadonlyArray) { this._actions = actions; } @@ -247,7 +251,7 @@ export class DropdownMenu extends BaseDropdown { getAnchor: () => this.element, getActions: () => this.actions, getActionsContext: () => this.menuOptions ? this.menuOptions.context : null, - getActionItem: action => this.menuOptions && this.menuOptions.actionItemProvider ? this.menuOptions.actionItemProvider(action) : undefined, + getActionViewItem: action => this.menuOptions && this.menuOptions.actionViewItemProvider ? this.menuOptions.actionViewItemProvider(action) : undefined, getKeyBinding: action => this.menuOptions && this.menuOptions.getKeyBinding ? this.menuOptions.getKeyBinding(action) : undefined, getMenuClassName: () => this.menuClassName, onHide: () => this.onHide(), @@ -266,23 +270,23 @@ export class DropdownMenu extends BaseDropdown { } } -export class DropdownMenuActionItem extends BaseActionItem { +export class DropdownMenuActionViewItem extends BaseActionViewItem { private menuActionsOrProvider: any; private dropdownMenu: DropdownMenu; private contextMenuProvider: IContextMenuProvider; - private actionItemProvider?: IActionItemProvider; + private actionViewItemProvider?: IActionViewItemProvider; private keybindings?: (action: IAction) => ResolvedKeybinding | undefined; private clazz: string | undefined; private anchorAlignmentProvider: (() => AnchorAlignment) | undefined; - constructor(action: IAction, menuActions: IAction[], contextMenuProvider: IContextMenuProvider, actionItemProvider: IActionItemProvider | undefined, actionRunner: IActionRunner, keybindings: ((action: IAction) => ResolvedKeybinding | undefined) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment); - constructor(action: IAction, actionProvider: IActionProvider, contextMenuProvider: IContextMenuProvider, actionItemProvider: IActionItemProvider | undefined, actionRunner: IActionRunner, keybindings: ((action: IAction) => ResolvedKeybinding) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment); - constructor(action: IAction, menuActionsOrProvider: any, contextMenuProvider: IContextMenuProvider, actionItemProvider: IActionItemProvider | undefined, actionRunner: IActionRunner, keybindings: ((action: IAction) => ResolvedKeybinding | undefined) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment) { + constructor(action: IAction, menuActions: ReadonlyArray, contextMenuProvider: IContextMenuProvider, actionViewItemProvider: IActionViewItemProvider | undefined, actionRunner: IActionRunner, keybindings: ((action: IAction) => ResolvedKeybinding | undefined) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment); + constructor(action: IAction, actionProvider: IActionProvider, contextMenuProvider: IContextMenuProvider, actionViewItemProvider: IActionViewItemProvider | undefined, actionRunner: IActionRunner, keybindings: ((action: IAction) => ResolvedKeybinding) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment); + constructor(action: IAction, menuActionsOrProvider: any, contextMenuProvider: IContextMenuProvider, actionViewItemProvider: IActionViewItemProvider | undefined, actionRunner: IActionRunner, keybindings: ((action: IAction) => ResolvedKeybinding | undefined) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment) { super(null, action); this.menuActionsOrProvider = menuActionsOrProvider; this.contextMenuProvider = contextMenuProvider; - this.actionItemProvider = actionItemProvider; + this.actionViewItemProvider = actionViewItemProvider; this.actionRunner = actionRunner; this.keybindings = keybindings; this.clazz = clazz; @@ -319,7 +323,7 @@ export class DropdownMenuActionItem extends BaseActionItem { this.dropdownMenu = this._register(new DropdownMenu(container, options)); this.dropdownMenu.menuOptions = { - actionItemProvider: this.actionItemProvider, + actionViewItemProvider: this.actionViewItemProvider, actionRunner: this.actionRunner, getKeyBinding: this.keybindings, context: this._context diff --git a/src/vs/base/browser/ui/findinput/case-sensitive-dark.svg b/src/vs/base/browser/ui/findinput/case-sensitive-dark.svg index ae5401720..40c9ed326 100644 --- a/src/vs/base/browser/ui/findinput/case-sensitive-dark.svg +++ b/src/vs/base/browser/ui/findinput/case-sensitive-dark.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + diff --git a/src/vs/base/browser/ui/findinput/case-sensitive-hc.svg b/src/vs/base/browser/ui/findinput/case-sensitive-hc.svg new file mode 100644 index 000000000..82501418d --- /dev/null +++ b/src/vs/base/browser/ui/findinput/case-sensitive-hc.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/findinput/case-sensitive-light.svg b/src/vs/base/browser/ui/findinput/case-sensitive-light.svg new file mode 100644 index 000000000..aa1dbd353 --- /dev/null +++ b/src/vs/base/browser/ui/findinput/case-sensitive-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/findinput/case-sensitive.svg b/src/vs/base/browser/ui/findinput/case-sensitive.svg deleted file mode 100644 index 1f3b1a2c5..000000000 --- a/src/vs/base/browser/ui/findinput/case-sensitive.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/base/browser/ui/findinput/findInput.ts b/src/vs/base/browser/ui/findinput/findInput.ts index 38a5082b1..180e660f3 100644 --- a/src/vs/base/browser/ui/findinput/findInput.ts +++ b/src/vs/base/browser/ui/findinput/findInput.ts @@ -33,6 +33,7 @@ export interface IFindInputOptions extends IFindInputStyles { export interface IFindInputStyles extends IInputBoxStyles { inputActiveOptionBorder?: Color; + inputActiveOptionBackground?: Color; } const NLS_DEFAULT_LABEL = nls.localize('defaultLabel', "input"); @@ -48,6 +49,7 @@ export class FindInput extends Widget { private fixFocusOnOptionClickEnabled = true; private inputActiveOptionBorder?: Color; + private inputActiveOptionBackground?: Color; private inputBackground?: Color; private inputForeground?: Color; private inputBorder?: Color; @@ -97,6 +99,7 @@ export class FindInput extends Widget { this.label = options.label || NLS_DEFAULT_LABEL; this.inputActiveOptionBorder = options.inputActiveOptionBorder; + this.inputActiveOptionBackground = options.inputActiveOptionBackground; this.inputBackground = options.inputBackground; this.inputForeground = options.inputForeground; this.inputBorder = options.inputBorder; @@ -173,6 +176,7 @@ export class FindInput extends Widget { public style(styles: IFindInputStyles): void { this.inputActiveOptionBorder = styles.inputActiveOptionBorder; + this.inputActiveOptionBackground = styles.inputActiveOptionBackground; this.inputBackground = styles.inputBackground; this.inputForeground = styles.inputForeground; this.inputBorder = styles.inputBorder; @@ -194,6 +198,7 @@ export class FindInput extends Widget { if (this.domNode) { const checkBoxStyles: ICheckboxStyles = { inputActiveOptionBorder: this.inputActiveOptionBorder, + inputActiveOptionBackground: this.inputActiveOptionBackground, }; this.regex.style(checkBoxStyles); this.wholeWords.style(checkBoxStyles); @@ -294,7 +299,8 @@ export class FindInput extends Widget { this.regex = this._register(new RegexCheckbox({ appendTitle: appendRegexLabel, isChecked: false, - inputActiveOptionBorder: this.inputActiveOptionBorder + inputActiveOptionBorder: this.inputActiveOptionBorder, + inputActiveOptionBackground: this.inputActiveOptionBackground })); this._register(this.regex.onChange(viaKeyboard => { this._onDidOptionChange.fire(viaKeyboard); @@ -310,7 +316,8 @@ export class FindInput extends Widget { this.wholeWords = this._register(new WholeWordsCheckbox({ appendTitle: appendWholeWordsLabel, isChecked: false, - inputActiveOptionBorder: this.inputActiveOptionBorder + inputActiveOptionBorder: this.inputActiveOptionBorder, + inputActiveOptionBackground: this.inputActiveOptionBackground })); this._register(this.wholeWords.onChange(viaKeyboard => { this._onDidOptionChange.fire(viaKeyboard); @@ -323,7 +330,8 @@ export class FindInput extends Widget { this.caseSensitive = this._register(new CaseSensitiveCheckbox({ appendTitle: appendCaseSensitiveLabel, isChecked: false, - inputActiveOptionBorder: this.inputActiveOptionBorder + inputActiveOptionBorder: this.inputActiveOptionBorder, + inputActiveOptionBackground: this.inputActiveOptionBackground })); this._register(this.caseSensitive.onChange(viaKeyboard => { this._onDidOptionChange.fire(viaKeyboard); diff --git a/src/vs/base/browser/ui/findinput/findInputCheckboxes.css b/src/vs/base/browser/ui/findinput/findInputCheckboxes.css index 37e890d7f..c72a7350f 100644 --- a/src/vs/base/browser/ui/findinput/findInputCheckboxes.css +++ b/src/vs/base/browser/ui/findinput/findInputCheckboxes.css @@ -4,28 +4,53 @@ *--------------------------------------------------------------------------------------------*/ .vs .monaco-custom-checkbox.monaco-case-sensitive { - background: url('case-sensitive.svg') center center no-repeat; + background: url('case-sensitive-light.svg') center center no-repeat; } -.hc-black .monaco-custom-checkbox.monaco-case-sensitive, -.hc-black .monaco-custom-checkbox.monaco-case-sensitive:hover, + .vs-dark .monaco-custom-checkbox.monaco-case-sensitive { background: url('case-sensitive-dark.svg') center center no-repeat; } +.hc-black .monaco-custom-checkbox.monaco-case-sensitive, +.hc-black .monaco-custom-checkbox.monaco-case-sensitive:hover { + background: url('case-sensitive-hc.svg') center center no-repeat; +} + +.vs .monaco-custom-checkbox.monaco-preserve-case { + background: url('preserve-case-light.svg') center center no-repeat; +} + +.vs-dark .monaco-custom-checkbox.monaco-preserve-case { + background: url('preserve-case-dark.svg') center center no-repeat; +} + +.hc-black .monaco-custom-checkbox.monaco-preserve-case, +.hc-black .monaco-custom-checkbox.monaco-preserve-case:hover { + background: url('preserve-case-hc.svg') center center no-repeat; +} + .vs .monaco-custom-checkbox.monaco-whole-word { - background: url('whole-word.svg') center center no-repeat; + background: url('whole-word-light.svg') center center no-repeat; } -.hc-black .monaco-custom-checkbox.monaco-whole-word, -.hc-black .monaco-custom-checkbox.monaco-whole-word:hover, + .vs-dark .monaco-custom-checkbox.monaco-whole-word { background: url('whole-word-dark.svg') center center no-repeat; } +.hc-black .monaco-custom-checkbox.monaco-whole-word, +.hc-black .monaco-custom-checkbox.monaco-whole-word:hover { + background: url('whole-word-hc.svg') center center no-repeat; +} + .vs .monaco-custom-checkbox.monaco-regex { - background: url('regex.svg') center center no-repeat; + background: url('regex-light.svg') center center no-repeat; } -.hc-black .monaco-custom-checkbox.monaco-regex, -.hc-black .monaco-custom-checkbox.monaco-regex:hover, + .vs-dark .monaco-custom-checkbox.monaco-regex { background: url('regex-dark.svg') center center no-repeat; } + +.hc-black .monaco-custom-checkbox.monaco-regex, +.hc-black .monaco-custom-checkbox.monaco-regex:hover { + background: url('regex-hc.svg') center center no-repeat; +} diff --git a/src/vs/base/browser/ui/findinput/findInputCheckboxes.ts b/src/vs/base/browser/ui/findinput/findInputCheckboxes.ts index 62451f1a4..effef734a 100644 --- a/src/vs/base/browser/ui/findinput/findInputCheckboxes.ts +++ b/src/vs/base/browser/ui/findinput/findInputCheckboxes.ts @@ -12,6 +12,7 @@ export interface IFindInputCheckboxOpts { readonly appendTitle: string; readonly isChecked: boolean; readonly inputActiveOptionBorder?: Color; + readonly inputActiveOptionBackground?: Color; } const NLS_CASE_SENSITIVE_CHECKBOX_LABEL = nls.localize('caseDescription', "Match Case"); @@ -24,7 +25,8 @@ export class CaseSensitiveCheckbox extends Checkbox { actionClassName: 'monaco-case-sensitive', title: NLS_CASE_SENSITIVE_CHECKBOX_LABEL + opts.appendTitle, isChecked: opts.isChecked, - inputActiveOptionBorder: opts.inputActiveOptionBorder + inputActiveOptionBorder: opts.inputActiveOptionBorder, + inputActiveOptionBackground: opts.inputActiveOptionBackground }); } } @@ -35,7 +37,8 @@ export class WholeWordsCheckbox extends Checkbox { actionClassName: 'monaco-whole-word', title: NLS_WHOLE_WORD_CHECKBOX_LABEL + opts.appendTitle, isChecked: opts.isChecked, - inputActiveOptionBorder: opts.inputActiveOptionBorder + inputActiveOptionBorder: opts.inputActiveOptionBorder, + inputActiveOptionBackground: opts.inputActiveOptionBackground }); } } @@ -46,7 +49,8 @@ export class RegexCheckbox extends Checkbox { actionClassName: 'monaco-regex', title: NLS_REGEX_CHECKBOX_LABEL + opts.appendTitle, isChecked: opts.isChecked, - inputActiveOptionBorder: opts.inputActiveOptionBorder + inputActiveOptionBorder: opts.inputActiveOptionBorder, + inputActiveOptionBackground: opts.inputActiveOptionBackground }); } } diff --git a/src/vs/base/browser/ui/findinput/preserve-case-dark.svg b/src/vs/base/browser/ui/findinput/preserve-case-dark.svg new file mode 100644 index 000000000..1c87e3471 --- /dev/null +++ b/src/vs/base/browser/ui/findinput/preserve-case-dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/vs/base/browser/ui/findinput/preserve-case-hc.svg b/src/vs/base/browser/ui/findinput/preserve-case-hc.svg new file mode 100644 index 000000000..f316948bb --- /dev/null +++ b/src/vs/base/browser/ui/findinput/preserve-case-hc.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/vs/base/browser/ui/findinput/preserve-case-light.svg b/src/vs/base/browser/ui/findinput/preserve-case-light.svg new file mode 100644 index 000000000..83954b665 --- /dev/null +++ b/src/vs/base/browser/ui/findinput/preserve-case-light.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/vs/base/browser/ui/findinput/regex-dark.svg b/src/vs/base/browser/ui/findinput/regex-dark.svg index c303032e6..cf43e9d95 100644 --- a/src/vs/base/browser/ui/findinput/regex-dark.svg +++ b/src/vs/base/browser/ui/findinput/regex-dark.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + diff --git a/src/vs/base/browser/ui/findinput/regex-hc.svg b/src/vs/base/browser/ui/findinput/regex-hc.svg new file mode 100644 index 000000000..116c547d1 --- /dev/null +++ b/src/vs/base/browser/ui/findinput/regex-hc.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/findinput/regex-light.svg b/src/vs/base/browser/ui/findinput/regex-light.svg new file mode 100644 index 000000000..b329c104f --- /dev/null +++ b/src/vs/base/browser/ui/findinput/regex-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/findinput/regex.svg b/src/vs/base/browser/ui/findinput/regex.svg deleted file mode 100644 index c677843be..000000000 --- a/src/vs/base/browser/ui/findinput/regex.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/base/browser/ui/findinput/whole-word-dark.svg b/src/vs/base/browser/ui/findinput/whole-word-dark.svg index d18e144f3..6c38eb215 100644 --- a/src/vs/base/browser/ui/findinput/whole-word-dark.svg +++ b/src/vs/base/browser/ui/findinput/whole-word-dark.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + diff --git a/src/vs/base/browser/ui/findinput/whole-word-hc.svg b/src/vs/base/browser/ui/findinput/whole-word-hc.svg new file mode 100644 index 000000000..fc1ff4326 --- /dev/null +++ b/src/vs/base/browser/ui/findinput/whole-word-hc.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/findinput/whole-word-light.svg b/src/vs/base/browser/ui/findinput/whole-word-light.svg new file mode 100644 index 000000000..345e65b2a --- /dev/null +++ b/src/vs/base/browser/ui/findinput/whole-word-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/findinput/whole-word.svg b/src/vs/base/browser/ui/findinput/whole-word.svg deleted file mode 100644 index 8244d95ab..000000000 --- a/src/vs/base/browser/ui/findinput/whole-word.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/base/browser/ui/grid/grid.ts b/src/vs/base/browser/ui/grid/grid.ts index 44e3deacd..eb8476e1b 100644 --- a/src/vs/base/browser/ui/grid/grid.ts +++ b/src/vs/base/browser/ui/grid/grid.ts @@ -5,14 +5,13 @@ import 'vs/css!./gridview'; import { Orientation } from 'vs/base/browser/ui/sash/sash'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { Disposable } from 'vs/base/common/lifecycle'; import { tail2 as tail, equals } from 'vs/base/common/arrays'; -import { orthogonal, IView, GridView, Sizing as GridViewSizing, Box, IGridViewStyles } from './gridview'; -import { Event, Emitter } from 'vs/base/common/event'; -import { $ } from 'vs/base/browser/dom'; -import { LayoutPriority } from 'vs/base/browser/ui/splitview/splitview'; +import { orthogonal, IView as IGridViewView, GridView, Sizing as GridViewSizing, Box, IGridViewStyles, IViewSize, ILayoutController, LayoutController } from './gridview'; +import { Event } from 'vs/base/common/event'; +import { InvisibleSizing } from 'vs/base/browser/ui/splitview/splitview'; -export { Orientation } from './gridview'; +export { Orientation, Sizing as GridViewSizing, IViewSize, orthogonal, LayoutPriority } from './gridview'; export const enum Direction { Up, @@ -30,9 +29,15 @@ function oppositeDirection(direction: Direction): Direction { } } +export interface IView extends IGridViewView { + readonly preferredHeight?: number; + readonly preferredWidth?: number; +} + export interface GridLeafNode { readonly view: T; readonly box: Box; + readonly cachedVisibleSize: number | undefined; } export interface GridBranchNode { @@ -117,10 +122,6 @@ function getDirectionOrientation(direction: Direction): Orientation { return direction === Direction.Up || direction === Direction.Down ? Orientation.VERTICAL : Orientation.HORIZONTAL; } -function getSize(dimensions: { width: number; height: number; }, orientation: Orientation) { - return orientation === Orientation.HORIZONTAL ? dimensions.width : dimensions.height; -} - export function getRelativeLocation(rootOrientation: Orientation, location: number[], direction: Direction): number[] { const orientation = getLocationOrientation(rootOrientation, location); const directionOrientation = getDirectionOrientation(direction); @@ -179,24 +180,30 @@ function getGridLocation(element: HTMLElement): number[] { return [...getGridLocation(ancestor), index]; } -export const enum Sizing { - Distribute = 'distribute', - Split = 'split' +export type DistributeSizing = { type: 'distribute' }; +export type SplitSizing = { type: 'split' }; +export type InvisibleSizing = { type: 'invisible', cachedVisibleSize: number }; +export type Sizing = DistributeSizing | SplitSizing | InvisibleSizing; + +export namespace Sizing { + export const Distribute: DistributeSizing = { type: 'distribute' }; + export const Split: SplitSizing = { type: 'split' }; + export function Invisible(cachedVisibleSize: number): InvisibleSizing { return { type: 'invisible', cachedVisibleSize }; } } export interface IGridStyles extends IGridViewStyles { } export interface IGridOptions { - styles?: IGridStyles; - proportionalLayout?: boolean; + readonly styles?: IGridStyles; + readonly proportionalLayout?: boolean; + readonly firstViewVisibleCachedSize?: number; + readonly layoutController?: ILayoutController; } -export class Grid implements IDisposable { +export class Grid extends Disposable { protected gridview: GridView; private views = new Map(); - private disposables: IDisposable[] = []; - get orientation(): Orientation { return this.gridview.orientation; } set orientation(orientation: Orientation) { this.gridview.orientation = orientation; } @@ -211,15 +218,20 @@ export class Grid implements IDisposable { get element(): HTMLElement { return this.gridview.element; } - sashResetSizing: Sizing = Sizing.Distribute; + private didLayout = false; constructor(view: T, options: IGridOptions = {}) { + super(); this.gridview = new GridView(options); - this.disposables.push(this.gridview); + this._register(this.gridview); + + this._register(this.gridview.onDidSashReset(this.onDidSashReset, this)); - this.gridview.onDidSashReset(this.doResetViewSize, this, this.disposables); + const size: number | GridViewSizing = typeof options.firstViewVisibleCachedSize === 'number' + ? GridViewSizing.Invisible(options.firstViewVisibleCachedSize) + : 0; - this._addView(view, 0, [0]); + this._addView(view, size, [0]); } style(styles: IGridStyles): void { @@ -228,6 +240,7 @@ export class Grid implements IDisposable { layout(width: number, height: number): void { this.gridview.layout(width, height); + this.didLayout = true; } hasView(view: T): boolean { @@ -250,10 +263,12 @@ export class Grid implements IDisposable { let viewSize: number | GridViewSizing; - if (size === Sizing.Split) { + if (typeof size === 'number') { + viewSize = size; + } else if (size.type === 'split') { const [, index] = tail(referenceLocation); viewSize = GridViewSizing.Split(index); - } else if (size === Sizing.Distribute) { + } else if (size.type === 'distribute') { viewSize = GridViewSizing.Distribute; } else { viewSize = size; @@ -273,7 +288,7 @@ export class Grid implements IDisposable { } const location = this.getViewLocation(view); - this.gridview.removeView(location, sizing === Sizing.Distribute ? GridViewSizing.Distribute : undefined); + this.gridview.removeView(location, (sizing && sizing.type === 'distribute') ? GridViewSizing.Distribute : undefined); this.views.delete(view); } @@ -299,19 +314,12 @@ export class Grid implements IDisposable { return this.gridview.swapViews(fromLocation, toLocation); } - resizeView(view: T, size: number): void { + resizeView(view: T, size: IViewSize): void { const location = this.getViewLocation(view); return this.gridview.resizeView(location, size); } - getViewSize(view: T): number { - const location = this.getViewLocation(view); - const viewSize = this.gridview.getViewSize(location); - return getLocationOrientation(this.orientation, location) === Orientation.HORIZONTAL ? viewSize.width : viewSize.height; - } - - // TODO@joao cleanup - getViewSize2(view: T): { width: number; height: number; } { + getViewSize(view: T): IViewSize { const location = this.getViewLocation(view); return this.gridview.getViewSize(location); } @@ -325,11 +333,25 @@ export class Grid implements IDisposable { this.gridview.distributeViewSizes(); } + isViewVisible(view: T): boolean { + const location = this.getViewLocation(view); + return this.gridview.isViewVisible(location); + } + + setViewVisible(view: T, visible: boolean): void { + const location = this.getViewLocation(view); + this.gridview.setViewVisible(location, visible); + } + getViews(): GridBranchNode { - return this.gridview.getViews() as GridBranchNode; + return this.gridview.getView() as GridBranchNode; } getNeighborViews(view: T, direction: Direction, wrap: boolean = false): T[] { + if (!this.didLayout) { + throw new Error('Can\'t call getNeighborViews before first layout'); + } + const location = this.getViewLocation(view); const root = this.getViews(); const node = getGridNode(root, location); @@ -361,23 +383,37 @@ export class Grid implements IDisposable { return getGridLocation(element); } - private doResetViewSize(location: number[]): void { - if (this.sashResetSizing === Sizing.Split) { - const orientation = getLocationOrientation(this.orientation, location); - const firstViewSize = getSize(this.gridview.getViewSize(location), orientation); - const [parentLocation, index] = tail(location); - const secondViewSize = getSize(this.gridview.getViewSize([...parentLocation, index + 1]), orientation); - const totalSize = firstViewSize + secondViewSize; - this.gridview.resizeView(location, Math.floor(totalSize / 2)); + private onDidSashReset(location: number[]): void { + const resizeToPreferredSize = (location: number[]): boolean => { + const node = this.gridview.getView(location) as GridNode; - } else { - const [parentLocation,] = tail(location); - this.gridview.distributeViewSizes(parentLocation); + if (isGridBranchNode(node)) { + return false; + } + + const direction = getLocationOrientation(this.orientation, location); + const size = direction === Orientation.HORIZONTAL ? node.view.preferredWidth : node.view.preferredHeight; + + if (typeof size !== 'number') { + return false; + } + + const viewSize = direction === Orientation.HORIZONTAL ? { width: Math.round(size) } : { height: Math.round(size) }; + this.gridview.resizeView(location, viewSize); + return true; + }; + + if (resizeToPreferredSize(location)) { + return; + } + + const [parentLocation, index] = tail(location); + + if (resizeToPreferredSize([...parentLocation, index + 1])) { + return; } - } - dispose(): void { - this.disposables = dispose(this.disposables); + this.gridview.distributeViewSizes(parentLocation); } } @@ -399,6 +435,7 @@ export interface ISerializedLeafNode { type: 'leaf'; data: object | null; size: number; + visible?: boolean; } export interface ISerializedBranchNode { @@ -422,6 +459,10 @@ export class SerializableGrid extends Grid { const size = orientation === Orientation.VERTICAL ? node.box.width : node.box.height; if (!isGridBranchNode(node)) { + if (typeof node.cachedVisibleSize === 'number') { + return { type: 'leaf', data: node.view.toJSON(), size: node.cachedVisibleSize, visible: false }; + } + return { type: 'leaf', data: node.view.toJSON(), size }; } @@ -446,25 +487,26 @@ export class SerializableGrid extends Grid { throw new Error('Invalid JSON: \'size\' property of node must be a number.'); } + const childSize = child.type === 'leaf' && child.visible === false ? 0 : child.size; const childBox: Box = orientation === Orientation.HORIZONTAL - ? { top: box.top, left: box.left + offset, width: child.size, height: box.height } - : { top: box.top + offset, left: box.left, width: box.width, height: child.size }; + ? { top: box.top, left: box.left + offset, width: childSize, height: box.height } + : { top: box.top + offset, left: box.left, width: box.width, height: childSize }; children.push(SerializableGrid.deserializeNode(child, orthogonal(orientation), childBox, deserializer)); - offset += child.size; + offset += childSize; } return { children, box }; } else if (json.type === 'leaf') { const view: T = deserializer.fromJSON(json.data); - return { view, box }; + return { view, box, cachedVisibleSize: json.visible === false ? json.size : undefined }; } throw new Error('Invalid JSON: \'type\' property must be either \'branch\' or \'leaf\'.'); } - private static getFirstLeaf(node: GridNode): GridLeafNode | undefined { + private static getFirstLeaf(node: GridNode): GridLeafNode { if (!isGridBranchNode(node)) { return node; } @@ -493,11 +535,19 @@ export class SerializableGrid extends Grid { throw new Error('Invalid serialized state, first leaf not found'); } + const layoutController = new LayoutController(false); + options = { ...options, layoutController }; + + if (typeof firstLeaf.cachedVisibleSize === 'number') { + options = { ...options, firstViewVisibleCachedSize: firstLeaf.cachedVisibleSize }; + } + const result = new SerializableGrid(firstLeaf.view, options); result.orientation = orientation; result.restoreViews(firstLeaf.view, orientation, root); result.initialLayoutContext = { width, height, root }; + layoutController.isLayoutEnabled = true; return result; } @@ -542,13 +592,16 @@ export class SerializableGrid extends Grid { const firstLeaves = node.children.map(c => SerializableGrid.getFirstLeaf(c)); for (let i = 1; i < firstLeaves.length; i++) { - const size = orientation === Orientation.VERTICAL ? firstLeaves[i]!.box.height : firstLeaves[i]!.box.width; - this.addView(firstLeaves[i]!.view, size, referenceView, direction); - referenceView = firstLeaves[i]!.view; + const node = firstLeaves[i]; + const size: number | InvisibleSizing = typeof node.cachedVisibleSize === 'number' + ? GridViewSizing.Invisible(node.cachedVisibleSize) + : (orientation === Orientation.VERTICAL ? node.box.height : node.box.width); + this.addView(node.view, size, referenceView, direction); + referenceView = node.view; } for (let i = 0; i < node.children.length; i++) { - this.restoreViews(firstLeaves[i]!.view, orthogonal(orientation), node.children[i]); + this.restoreViews(firstLeaves[i].view, orthogonal(orientation), node.children[i]); } } @@ -568,8 +621,11 @@ export class SerializableGrid extends Grid { const childLocation = [...location, i]; if (i < node.children.length - 1) { - const size = orientation === Orientation.VERTICAL ? child.box.height : child.box.width; - this.gridview.resizeView(childLocation, Math.floor(size * scale)); + const size = orientation === Orientation.VERTICAL + ? { height: Math.floor(child.box.height * scale) } + : { width: Math.floor(child.box.width * scale) }; + + this.gridview.resizeView(childLocation, size); } this.restoreViewsSize(childLocation, child, orthogonal(orientation), widthScale, heightScale); @@ -653,63 +709,3 @@ export function createSerializedGrid(gridDescriptor: GridDescriptor): ISerialize height: height || 1 }; } - -export class View implements IView { - - readonly element = $('.grid-view-view'); - - private visible = false; - private width: number | undefined; - private height: number | undefined; - private orientation: Orientation = Orientation.HORIZONTAL; - - get minimumWidth(): number { return this.visible ? this.view.minimumWidth : 0; } - get maximumWidth(): number { return this.visible ? this.view.maximumWidth : (this.orientation === Orientation.HORIZONTAL ? 0 : Number.POSITIVE_INFINITY); } - get minimumHeight(): number { return this.visible ? this.view.minimumHeight : 0; } - get maximumHeight(): number { return this.visible ? this.view.maximumHeight : (this.orientation === Orientation.VERTICAL ? 0 : Number.POSITIVE_INFINITY); } - - private onDidChangeVisibility = new Emitter<{ width: number; height: number; } | undefined>(); - readonly onDidChange: Event<{ width: number; height: number; } | undefined>; - - get priority(): LayoutPriority | undefined { return this.view.priority; } - get snapSize(): number | undefined { return this.visible ? this.view.snapSize : undefined; } - - constructor(private view: IView) { - this.show(); - this.onDidChange = Event.any(this.onDidChangeVisibility.event, Event.filter(view.onDidChange, () => this.visible)); - } - - show(): void { - if (this.visible) { - return; - } - - this.visible = true; - - this.element.appendChild(this.view.element); - this.onDidChangeVisibility.fire(typeof this.width === 'number' ? { width: this.width, height: this.height! } : undefined); - } - - hide(): void { - if (!this.visible) { - return; - } - - this.visible = false; - - this.element.removeChild(this.view.element); - this.onDidChangeVisibility.fire(undefined); - } - - layout(width: number, height: number, orientation: Orientation): void { - this.orientation = orientation; - - if (!this.visible) { - return; - } - - this.view.layout(width, height, orientation); - this.width = width; - this.height = height; - } -} \ No newline at end of file diff --git a/src/vs/base/browser/ui/grid/gridview.ts b/src/vs/base/browser/ui/grid/gridview.ts index e4e6f8909..81a6950a6 100644 --- a/src/vs/base/browser/ui/grid/gridview.ts +++ b/src/vs/base/browser/ui/grid/gridview.ts @@ -15,16 +15,22 @@ import { Color } from 'vs/base/common/color'; export { Sizing, LayoutPriority } from 'vs/base/browser/ui/splitview/splitview'; export { Orientation } from 'vs/base/browser/ui/sash/sash'; +export interface IViewSize { + readonly width: number; + readonly height: number; +} + export interface IView { readonly element: HTMLElement; readonly minimumWidth: number; readonly maximumWidth: number; readonly minimumHeight: number; readonly maximumHeight: number; - readonly onDidChange: Event<{ width: number; height: number; } | undefined>; + readonly onDidChange: Event; readonly priority?: LayoutPriority; - readonly snapSize?: number; + readonly snap?: boolean; layout(width: number, height: number, orientation: Orientation): void; + setVisible?(visible: boolean): void; } export function orthogonal(orientation: Orientation): Orientation { @@ -41,6 +47,7 @@ export interface Box { export interface GridLeafNode { readonly view: IView; readonly box: Box; + readonly cachedVisibleSize: number | undefined; } export interface GridBranchNode { @@ -60,9 +67,18 @@ const defaultStyles: IGridViewStyles = { separatorBorder: Color.transparent }; +export interface ILayoutController { + readonly isLayoutEnabled: boolean; +} + +export class LayoutController implements ILayoutController { + constructor(public isLayoutEnabled: boolean) { } +} + export interface IGridViewOptions { - styles?: IGridViewStyles; - proportionalLayout?: boolean; // default true + readonly styles?: IGridViewStyles; + readonly proportionalLayout?: boolean; // default true + readonly layoutController?: ILayoutController; } class BranchNode implements ISplitView, IDisposable { @@ -96,6 +112,22 @@ class BranchNode implements ISplitView, IDisposable { return Math.min(...this.children.map(c => c.maximumOrthogonalSize)); } + get priority(): LayoutPriority { + if (this.children.length === 0) { + return LayoutPriority.Normal; + } + + const priorities = this.children.map(c => typeof c.priority === 'undefined' ? LayoutPriority.Normal : c.priority); + + if (priorities.some(p => p === LayoutPriority.High)) { + return LayoutPriority.High; + } else if (priorities.some(p => p === LayoutPriority.Low)) { + return LayoutPriority.Low; + } + + return LayoutPriority.Normal; + } + get minimumOrthogonalSize(): number { return this.splitview.minimumSize; } @@ -173,6 +205,12 @@ class BranchNode implements ISplitView, IDisposable { } } + setVisible(visible: boolean): void { + for (const child of this.children) { + child.setVisible(visible); + } + } + orthogonalLayout(size: number): void { this._size = size; this.splitview.layout(size); @@ -299,6 +337,30 @@ class BranchNode implements ISplitView, IDisposable { return this.splitview.getViewSize(index); } + isChildVisible(index: number): boolean { + if (index < 0 || index >= this.children.length) { + throw new Error('Invalid index'); + } + + return this.splitview.isViewVisible(index); + } + + setChildVisible(index: number, visible: boolean): void { + if (index < 0 || index >= this.children.length) { + throw new Error('Invalid index'); + } + + this.splitview.setViewVisible(index, visible); + } + + getChildCachedVisibleSize(index: number): number | undefined { + if (index < 0 || index >= this.children.length) { + throw new Error('Invalid index'); + } + + return this.splitview.getViewCachedVisibleSize(index); + } + private onDidChildrenChange(): void { const onDidChildrenChange = Event.map(Event.any(...this.children.map(c => c.onDidChange)), () => undefined); this.childrenChangeDisposable.dispose(); @@ -380,6 +442,9 @@ class LeafNode implements ISplitView, IDisposable { private _size: number = 0; get size(): number { return this._size; } + private _cachedVisibleSize: number | undefined; + get cachedVisibleSize(): number | undefined { return this._cachedVisibleSize; } + private _orthogonalSize: number; get orthogonalSize(): number { return this._orthogonalSize; } @@ -410,7 +475,8 @@ class LeafNode implements ISplitView, IDisposable { constructor( readonly view: IView, readonly orientation: Orientation, - orthogonalSize: number = 0 + readonly layoutController: ILayoutController, + orthogonalSize: number ) { this._orthogonalSize = orthogonalSize; @@ -458,8 +524,8 @@ class LeafNode implements ISplitView, IDisposable { return this.view.priority; } - get snapSize(): number | undefined { - return this.view.snapSize; + get snap(): boolean | undefined { + return this.view.snap; } get minimumOrthogonalSize(): number { @@ -480,12 +546,30 @@ class LeafNode implements ISplitView, IDisposable { layout(size: number): void { this._size = size; - return this.view.layout(this.width, this.height, orthogonal(this.orientation)); + + if (this.layoutController.isLayoutEnabled) { + this.view.layout(this.width, this.height, orthogonal(this.orientation)); + } + } + + setVisible(visible: boolean): void { + if (visible) { + this._cachedVisibleSize = undefined; + } else { + this._cachedVisibleSize = this._size; + } + + if (this.view.setVisible) { + this.view.setVisible(visible); + } } orthogonalLayout(size: number): void { this._orthogonalSize = size; - return this.view.layout(this.width, this.height, orthogonal(this.orientation)); + + if (this.layoutController.isLayoutEnabled) { + this.view.layout(this.width, this.height, orthogonal(this.orientation)); + } } dispose(): void { } @@ -516,7 +600,7 @@ function flipNode(node: T, size: number, orthogonalSize: number) return result as T; } else { - return new LeafNode((node as LeafNode).view, orthogonal(node.orientation), orthogonalSize) as T; + return new LeafNode((node as LeafNode).view, orthogonal(node.orientation), (node as LeafNode).layoutController, orthogonalSize) as T; } } @@ -573,14 +657,17 @@ export class GridView implements IDisposable { get maximumWidth(): number { return this.root.maximumHeight; } get maximumHeight(): number { return this.root.maximumHeight; } - private _onDidChange = new Relay<{ width: number; height: number; } | undefined>(); + private _onDidChange = new Relay(); readonly onDidChange = this._onDidChange.event; + private layoutController: LayoutController; + constructor(options: IGridViewOptions = {}) { this.element = $('.monaco-grid-view'); this.styles = options.styles || defaultStyles; this.proportionalLayout = typeof options.proportionalLayout !== 'undefined' ? !!options.proportionalLayout : true; this.root = new BranchNode(Orientation.VERTICAL, this.styles, this.proportionalLayout); + this.layoutController = options.layoutController || new LayoutController(true); } style(styles: IGridViewStyles): void { @@ -602,26 +689,34 @@ export class GridView implements IDisposable { const [pathToParent, parent] = this.getNode(rest); if (parent instanceof BranchNode) { - const node = new LeafNode(view, orthogonal(parent.orientation), parent.orthogonalSize); + const node = new LeafNode(view, orthogonal(parent.orientation), this.layoutController, parent.orthogonalSize); parent.addChild(node, size, index); } else { const [, grandParent] = tail(pathToParent); const [, parentIndex] = tail(rest); + + let newSiblingSize: number | Sizing = 0; + + const newSiblingCachedVisibleSize = grandParent.getChildCachedVisibleSize(parentIndex); + if (typeof newSiblingCachedVisibleSize === 'number') { + newSiblingSize = Sizing.Invisible(newSiblingCachedVisibleSize); + } + grandParent.removeChild(parentIndex); const newParent = new BranchNode(parent.orientation, this.styles, this.proportionalLayout, parent.size, parent.orthogonalSize); grandParent.addChild(newParent, parent.size, parentIndex); newParent.orthogonalLayout(parent.orthogonalSize); - const newSibling = new LeafNode(parent.view, grandParent.orientation, parent.size); - newParent.addChild(newSibling, 0, 0); + const newSibling = new LeafNode(parent.view, grandParent.orientation, this.layoutController, parent.size); + newParent.addChild(newSibling, newSiblingSize, 0); if (typeof size !== 'number' && size.type === 'split') { size = Sizing.Split(0); } - const node = new LeafNode(view, grandParent.orientation, parent.size); + const node = new LeafNode(view, grandParent.orientation, this.layoutController, parent.size); newParent.addChild(node, size, index); } } @@ -683,7 +778,7 @@ export class GridView implements IDisposable { grandParent.addChild(child, child.size, parentIndex + i); } } else { - const newSibling = new LeafNode(sibling.view, orthogonal(sibling.orientation), sibling.size); + const newSibling = new LeafNode(sibling.view, orthogonal(sibling.orientation), this.layoutController, sibling.size); grandParent.addChild(newSibling, sibling.orthogonalSize, parentIndex); } @@ -747,18 +842,33 @@ export class GridView implements IDisposable { } } - resizeView(location: number[], size: number): void { + resizeView(location: number[], { width, height }: Partial): void { const [rest, index] = tail(location); - const [, parent] = this.getNode(rest); + const [pathToParent, parent] = this.getNode(rest); if (!(parent instanceof BranchNode)) { throw new Error('Invalid location'); } - parent.resizeChild(index, size); + if (!width && !height) { + return; + } + + const [parentSize, grandParentSize] = parent.orientation === Orientation.HORIZONTAL ? [width, height] : [height, width]; + + if (typeof grandParentSize === 'number' && pathToParent.length > 0) { + const [, grandParent] = tail(pathToParent); + const [, parentIndex] = tail(rest); + + grandParent.resizeChild(parentIndex, grandParentSize); + } + + if (typeof parentSize === 'number') { + parent.resizeChild(index, parentSize); + } } - getViewSize(location: number[]): { width: number; height: number; } { + getViewSize(location: number[]): IViewSize { const [, node] = this.getNode(location); return { width: node.width, height: node.height }; } @@ -790,13 +900,38 @@ export class GridView implements IDisposable { node.distributeViewSizes(); } - getViews(): GridBranchNode { - return this._getViews(this.root, this.orientation, { top: 0, left: 0, width: this.width, height: this.height }) as GridBranchNode; + isViewVisible(location: number[]): boolean { + const [rest, index] = tail(location); + const [, parent] = this.getNode(rest); + + if (!(parent instanceof BranchNode)) { + throw new Error('Invalid from location'); + } + + return parent.isChildVisible(index); + } + + setViewVisible(location: number[], visible: boolean): void { + const [rest, index] = tail(location); + const [, parent] = this.getNode(rest); + + if (!(parent instanceof BranchNode)) { + throw new Error('Invalid from location'); + } + + parent.setChildVisible(index, visible); + } + + getView(): GridBranchNode; + getView(location?: number[]): GridNode; + getView(location?: number[]): GridNode { + const node = location ? this.getNode(location)[1] : this._root; + return this._getViews(node, this.orientation, { top: 0, left: 0, width: this.width, height: this.height }); } private _getViews(node: Node, orientation: Orientation, box: Box): GridNode { if (node instanceof LeafNode) { - return { view: node.view, box }; + return { view: node.view, box, cachedVisibleSize: node.cachedVisibleSize }; } const children: GridNode[] = []; diff --git a/src/vs/base/browser/ui/inputbox/inputBox.ts b/src/vs/base/browser/ui/inputbox/inputBox.ts index 83e914e00..011d1f56d 100644 --- a/src/vs/base/browser/ui/inputbox/inputBox.ts +++ b/src/vs/base/browser/ui/inputbox/inputBox.ts @@ -28,7 +28,7 @@ export interface IInputOptions extends IInputBoxStyles { readonly type?: string; readonly validationOptions?: IInputValidationOptions; readonly flexibleHeight?: boolean; - readonly actions?: IAction[]; + readonly actions?: ReadonlyArray; } export interface IInputBoxStyles { @@ -93,7 +93,7 @@ export class InputBox extends Widget { private placeholder: string; private ariaLabel: string; private validation?: IInputValidator; - private state: string | null = 'idle'; + private state: 'idle' | 'open' | 'closed' = 'idle'; private cachedHeight: number | null; private inputBackground?: Color; @@ -150,7 +150,7 @@ export class InputBox extends Widget { let tagName = this.options.flexibleHeight ? 'textarea' : 'input'; let wrapper = dom.append(this.element, $('.wrapper')); - this.input = dom.append(wrapper, $(tagName + '.input')); + this.input = dom.append(wrapper, $(tagName + '.input')); this.input.setAttribute('autocorrect', 'off'); this.input.setAttribute('autocapitalize', 'off'); this.input.setAttribute('spellcheck', 'false'); @@ -389,8 +389,6 @@ export class InputBox extends Widget { let div: HTMLElement; let layout = () => div.style.width = dom.getTotalWidth(this.element) + 'px'; - this.state = 'open'; - this.contextViewProvider.showContextView({ getAnchor: () => this.element, anchorAlignment: AnchorAlignment.RIGHT, @@ -421,18 +419,25 @@ export class InputBox extends Widget { return null; }, + onHide: () => { + this.state = 'closed'; + }, layout: layout }); + + this.state = 'open'; } private _hideMessage(): void { - if (!this.contextViewProvider || this.state !== 'open') { + if (!this.contextViewProvider) { return; } - this.state = 'idle'; + if (this.state === 'open') { + this.contextViewProvider.hideContextView(); + } - this.contextViewProvider.hideContextView(); + this.state = 'idle'; } private onValueChange(): void { @@ -522,7 +527,7 @@ export class InputBox extends Widget { this.contextViewProvider = undefined; this.message = null; this.validation = undefined; - this.state = null; + this.state = null!; // StrictNullOverride: nulling out ok in dispose this.actionbar = undefined; super.dispose(); diff --git a/src/vs/base/browser/ui/list/list.css b/src/vs/base/browser/ui/list/list.css index 73756ce78..1c1fa4c82 100644 --- a/src/vs/base/browser/ui/list/list.css +++ b/src/vs/base/browser/ui/list/list.css @@ -126,13 +126,13 @@ -webkit-appearance: none; width: 16px; height: 16px; - background: url("media/no-filter.svg"); + background: url("media/no-filter-light.svg"); background-position: 50% 50%; cursor: pointer; } .monaco-list-type-filter > .controls > .filter:checked { - background-image: url("media/filter.svg"); + background-image: url("media/filter-light.svg"); } .vs-dark .monaco-list-type-filter > .controls > .filter { @@ -153,7 +153,7 @@ .monaco-list-type-filter > .controls > .clear { border: none; - background: url("media/close.svg"); + background: url("media/close-light.svg"); cursor: pointer; } @@ -186,9 +186,9 @@ /* Electron */ .monaco-list-type-filter { - cursor: -webkit-grab; + cursor: grab; } .monaco-list-type-filter.dragging { - cursor: -webkit-grabbing; + cursor: grabbing; } \ No newline at end of file diff --git a/src/vs/base/browser/ui/list/list.ts b/src/vs/base/browser/ui/list/list.ts index d18e381d3..2536dd0f2 100644 --- a/src/vs/base/browser/ui/list/list.ts +++ b/src/vs/base/browser/ui/list/list.ts @@ -17,8 +17,8 @@ export interface IListVirtualDelegate { export interface IListRenderer { templateId: string; renderTemplate(container: HTMLElement): TTemplateData; - renderElement(element: T, index: number, templateData: TTemplateData, dynamicHeightProbing?: boolean): void; - disposeElement?(element: T, index: number, templateData: TTemplateData, dynamicHeightProbing?: boolean): void; + renderElement(element: T, index: number, templateData: TTemplateData, height: number | undefined): void; + disposeElement?(element: T, index: number, templateData: TTemplateData, height: number | undefined): void; disposeTemplate(templateData: TTemplateData): void; } diff --git a/src/vs/base/browser/ui/list/listPaging.ts b/src/vs/base/browser/ui/list/listPaging.ts index 3d1fe4154..90736af0a 100644 --- a/src/vs/base/browser/ui/list/listPaging.ts +++ b/src/vs/base/browser/ui/list/listPaging.ts @@ -35,7 +35,7 @@ class PagedRenderer implements IListRenderer { } } }; } - renderElement(index: number, _: number, data: ITemplateData, dynamicHeightProbing?: boolean): void { + renderElement(index: number, _: number, data: ITemplateData, height: number | undefined): void { if (data.disposable) { data.disposable.dispose(); } @@ -47,7 +47,7 @@ class PagedRenderer implements IListRenderer implements IListRenderer cts.cancel() }; this.renderer.renderPlaceholder(index, data.data); - promise.then(entry => this.renderer.renderElement(entry, index, data.data!, dynamicHeightProbing)); + promise.then(entry => this.renderer.renderElement(entry, index, data.data!, height)); } disposeTemplate(data: ITemplateData): void { diff --git a/src/vs/base/browser/ui/list/listView.ts b/src/vs/base/browser/ui/list/listView.ts index a99b55931..d42777bec 100644 --- a/src/vs/base/browser/ui/list/listView.ts +++ b/src/vs/base/browser/ui/list/listView.ts @@ -41,9 +41,11 @@ export interface IListViewDragAndDrop extends IListDragAndDrop { getDragElements(element: T): T[]; } -export interface IAriaSetProvider { +export interface IAriaProvider { getSetSize(element: T, index: number, listLength: number): number; getPosInSet(element: T, index: number): number; + getRole?(element: T): string; + isChecked?(element: T): boolean; } export interface IListViewOptions { @@ -54,7 +56,7 @@ export interface IListViewOptions { readonly supportDynamicHeights?: boolean; readonly mouseSupport?: boolean; readonly horizontalScrolling?: boolean; - readonly ariaSetProvider?: IAriaSetProvider; + readonly ariaProvider?: IAriaProvider; } const DefaultOptions = { @@ -174,7 +176,7 @@ export class ListView implements ISpliceable, IDisposable { private setRowLineHeight: boolean; private supportDynamicHeights: boolean; private horizontalScrolling: boolean; - private ariaSetProvider: IAriaSetProvider; + private ariaProvider: IAriaProvider; private scrollWidth: number | undefined; private canUseTranslate3d: boolean | undefined = undefined; @@ -227,7 +229,7 @@ export class ListView implements ISpliceable, IDisposable { this.horizontalScrolling = getOrDefault(options, o => o.horizontalScrolling, DefaultOptions.horizontalScrolling); DOM.toggleClass(this.domNode, 'horizontal-scrolling', this.horizontalScrolling); - this.ariaSetProvider = options.ariaSetProvider || { getSetSize: (e, i, length) => length, getPosInSet: (_, index) => index + 1 }; + this.ariaProvider = options.ariaProvider || { getSetSize: (e, i, length) => length, getPosInSet: (_, index) => index + 1 }; this.rowsContainer = document.createElement('div'); this.rowsContainer.className = 'monaco-list-rows'; @@ -566,7 +568,12 @@ export class ListView implements ISpliceable, IDisposable { if (!item.row) { item.row = this.cache.alloc(item.templateId); - item.row!.domNode!.setAttribute('role', 'treeitem'); + const role = this.ariaProvider.getRole ? this.ariaProvider.getRole(item.element) : 'treeitem'; + item.row!.domNode!.setAttribute('role', role); + const checked = this.ariaProvider.isChecked ? this.ariaProvider.isChecked(item.element) : undefined; + if (typeof checked !== 'undefined') { + item.row!.domNode!.setAttribute('aria-checked', String(checked)); + } } if (!item.row.domNode!.parentElement) { @@ -586,7 +593,7 @@ export class ListView implements ISpliceable, IDisposable { } if (renderer) { - renderer.renderElement(item.element, index, item.row.templateData); + renderer.renderElement(item.element, index, item.row.templateData, item.size); } const uri = this.dnd.getDragURI(item.element); @@ -634,8 +641,8 @@ export class ListView implements ISpliceable, IDisposable { item.row!.domNode!.setAttribute('data-index', `${index}`); item.row!.domNode!.setAttribute('data-last-element', index === this.length - 1 ? 'true' : 'false'); - item.row!.domNode!.setAttribute('aria-setsize', String(this.ariaSetProvider.getSetSize(item.element, index, this.length))); - item.row!.domNode!.setAttribute('aria-posinset', String(this.ariaSetProvider.getPosInSet(item.element, index))); + item.row!.domNode!.setAttribute('aria-setsize', String(this.ariaProvider.getSetSize(item.element, index, this.length))); + item.row!.domNode!.setAttribute('aria-posinset', String(this.ariaProvider.getPosInSet(item.element, index))); item.row!.domNode!.setAttribute('id', this.getElementDomId(index)); DOM.toggleClass(item.row!.domNode!, 'drop-target', item.dropTarget); @@ -647,7 +654,7 @@ export class ListView implements ISpliceable, IDisposable { const renderer = this.renderers.get(item.templateId); if (renderer && renderer.disposeElement) { - renderer.disposeElement(item.element, index, item.row!.templateData); + renderer.disposeElement(item.element, index, item.row!.templateData, item.size); } this.cache.release(item.row!); @@ -1088,10 +1095,10 @@ export class ListView implements ISpliceable, IDisposable { const renderer = this.renderers.get(item.templateId); if (renderer) { - renderer.renderElement(item.element, index, row.templateData, true); + renderer.renderElement(item.element, index, row.templateData, undefined); if (renderer.disposeElement) { - renderer.disposeElement(item.element, index, row.templateData, true); + renderer.disposeElement(item.element, index, row.templateData, undefined); } } diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index 5babdbf0d..6b920ee1e 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -5,7 +5,7 @@ import 'vs/css!./list'; import { localize } from 'vs/nls'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle'; import { isNumber } from 'vs/base/common/types'; import { range, firstIndex, binarySearch } from 'vs/base/common/arrays'; import { memoize } from 'vs/base/common/decorators'; @@ -17,7 +17,7 @@ import { StandardKeyboardEvent, IKeyboardEvent } from 'vs/base/browser/keyboardE import { Event, Emitter, EventBufferer } from 'vs/base/common/event'; import { domEvent } from 'vs/base/browser/event'; import { IListVirtualDelegate, IListRenderer, IListEvent, IListContextMenuEvent, IListMouseEvent, IListTouchEvent, IListGestureEvent, IIdentityProvider, IKeyboardNavigationLabelProvider, IListDragAndDrop, IListDragOverReaction, ListAriaRootRole } from './list'; -import { ListView, IListViewOptions, IListViewDragAndDrop, IAriaSetProvider } from './listView'; +import { ListView, IListViewOptions, IListViewDragAndDrop, IAriaProvider } from './listView'; import { Color } from 'vs/base/common/color'; import { mixin } from 'vs/base/common/objects'; import { ScrollbarVisibility, ScrollEvent } from 'vs/base/common/scrollable'; @@ -111,7 +111,7 @@ class Trait implements ISpliceable, IDisposable { private sortedIndexes: number[] = []; private _onChange = new Emitter(); - get onChange(): Event { return this._onChange.event; } + readonly onChange: Event = this._onChange.event; get trait(): string { return this._trait; } @@ -228,7 +228,7 @@ function isInputElement(e: HTMLElement): boolean { class KeyboardController implements IDisposable { - private disposables: IDisposable[]; + private readonly disposables = new DisposableStore(); private openController: IOpenController; constructor( @@ -236,8 +236,7 @@ class KeyboardController implements IDisposable { private view: ListView, options: IListOptions ) { - const multipleSelectionSupport = !(options.multipleSelectionSupport === false); - this.disposables = []; + const multipleSelectionSupport = options.multipleSelectionSupport !== false; this.openController = options.openController || DefaultOpenController; @@ -314,7 +313,7 @@ class KeyboardController implements IDisposable { } dispose() { - this.disposables = dispose(this.disposables); + this.disposables.dispose(); } } @@ -330,6 +329,7 @@ export function mightProducePrintableCharacter(event: IKeyboardEvent): boolean { return (event.keyCode >= KeyCode.KEY_A && event.keyCode <= KeyCode.KEY_Z) || (event.keyCode >= KeyCode.KEY_0 && event.keyCode <= KeyCode.KEY_9) + || (event.keyCode >= KeyCode.NUMPAD_0 && event.keyCode <= KeyCode.NUMPAD_9) || (event.keyCode >= KeyCode.US_SEMICOLON && event.keyCode <= KeyCode.US_QUOTE); } @@ -341,8 +341,8 @@ class TypeLabelController implements IDisposable { private automaticKeyboardNavigation = true; private triggered = false; - private enabledDisposables: IDisposable[] = []; - private disposables: IDisposable[] = []; + private readonly enabledDisposables = new DisposableStore(); + private readonly disposables = new DisposableStore(); constructor( private list: List, @@ -398,7 +398,7 @@ class TypeLabelController implements IDisposable { return; } - this.enabledDisposables = dispose(this.enabledDisposables); + this.enabledDisposables.clear(); this.enabled = false; this.triggered = false; } @@ -430,20 +430,19 @@ class TypeLabelController implements IDisposable { dispose() { this.disable(); - this.disposables = dispose(this.disposables); + this.enabledDisposables.dispose(); + this.disposables.dispose(); } } class DOMFocusController implements IDisposable { - private disposables: IDisposable[] = []; + private readonly disposables = new DisposableStore(); constructor( private list: List, private view: ListView ) { - this.disposables = []; - const onKeyDown = Event.chain(domEvent(view.domNode, 'keydown')) .filter(e => !isInputElement(e.target as HTMLElement)) .map(e => new StandardKeyboardEvent(e)); @@ -486,7 +485,7 @@ class DOMFocusController implements IDisposable { } dispose() { - this.disposables = dispose(this.disposables); + this.disposables.dispose(); } } @@ -523,7 +522,7 @@ export class MouseController implements IDisposable { readonly multipleSelectionController: IMultipleSelectionController; private openController: IOpenController; private mouseSupport: boolean; - private disposables: IDisposable[] = []; + private readonly disposables = new DisposableStore(); constructor(protected list: List) { this.multipleSelectionSupport = !(list.options.multipleSelectionSupport === false); @@ -663,7 +662,7 @@ export class MouseController implements IDisposable { } dispose() { - this.disposables = dispose(this.disposables); + this.disposables.dispose(); } } @@ -833,7 +832,7 @@ export interface IListOptions extends IListStyles { readonly supportDynamicHeights?: boolean; readonly mouseSupport?: boolean; readonly horizontalScrolling?: boolean; - readonly ariaSetProvider?: IAriaSetProvider; + readonly ariaProvider?: IAriaProvider; } export interface IListStyles { @@ -857,6 +856,7 @@ export interface IListStyles { listFilterWidgetOutline?: Color; listFilterWidgetNoMatchesOutline?: Color; listMatchesShadow?: Color; + treeIndentGuidesStroke?: Color; } const defaultStyles: IListStyles = { @@ -867,7 +867,8 @@ const defaultStyles: IListStyles = { listFocusAndSelectionForeground: Color.fromHex('#FFFFFF'), listInactiveSelectionBackground: Color.fromHex('#3F3F46'), listHoverBackground: Color.fromHex('#2A2D2E'), - listDropBackground: Color.fromHex('#383B3D') + listDropBackground: Color.fromHex('#383B3D'), + treeIndentGuidesStroke: Color.fromHex('#a9a9a9') }; const DefaultOptions = { @@ -979,20 +980,20 @@ class PipelineRenderer implements IListRenderer { return this.renderers.map(r => r.renderTemplate(container)); } - renderElement(element: T, index: number, templateData: any[], dynamicHeightProbing?: boolean): void { + renderElement(element: T, index: number, templateData: any[], height: number | undefined): void { let i = 0; for (const renderer of this.renderers) { - renderer.renderElement(element, index, templateData[i++], dynamicHeightProbing); + renderer.renderElement(element, index, templateData[i++], height); } } - disposeElement(element: T, index: number, templateData: any[], dynamicHeightProbing?: boolean): void { + disposeElement(element: T, index: number, templateData: any[], height: number | undefined): void { let i = 0; for (const renderer of this.renderers) { if (renderer.disposeElement) { - renderer.disposeElement(element, index, templateData[i], dynamicHeightProbing); + renderer.disposeElement(element, index, templateData[i], height); } i += 1; @@ -1094,7 +1095,7 @@ export class List implements ISpliceable, IDisposable { private styleController: IStyleController; private typeLabelController?: TypeLabelController; - protected disposables: IDisposable[]; + protected readonly disposables = new DisposableStore(); @memoize get onFocusChange(): Event> { return Event.map(this.eventBufferer.wrapEvent(this.focus.onChange), e => this.toListEvent(e)); @@ -1112,6 +1113,7 @@ export class List implements ISpliceable, IDisposable { return Event.map(this._onPin.event, indexes => this.toListEvent({ indexes })); } + get domId(): string { return this.view.domId; } get onDidScroll(): Event { return this.view.onDidScroll; } get onMouseClick(): Event> { return this.view.onMouseClick; } get onMouseDblClick(): Event> { return this.view.onMouseDblClick; } @@ -1163,7 +1165,7 @@ export class List implements ISpliceable, IDisposable { readonly onDidBlur: Event; private _onDidDispose = new Emitter(); - get onDidDispose(): Event { return this._onDidDispose.event; } + readonly onDidDispose: Event = this._onDidDispose.event; constructor( container: HTMLElement, @@ -1207,24 +1209,27 @@ export class List implements ISpliceable, IDisposable { this.view ]); - this.disposables = [this.focus, this.selection, this.view, this._onDidDispose]; + this.disposables.add(this.focus); + this.disposables.add(this.selection); + this.disposables.add(this.view); + this.disposables.add(this._onDidDispose); this.onDidFocus = Event.map(domEvent(this.view.domNode, 'focus', true), () => null!); this.onDidBlur = Event.map(domEvent(this.view.domNode, 'blur', true), () => null!); - this.disposables.push(new DOMFocusController(this, this.view)); + this.disposables.add(new DOMFocusController(this, this.view)); if (typeof _options.keyboardSupport !== 'boolean' || _options.keyboardSupport) { const controller = new KeyboardController(this, this.view, _options); - this.disposables.push(controller); + this.disposables.add(controller); } if (_options.keyboardNavigationLabelProvider) { this.typeLabelController = new TypeLabelController(this, this.view, _options.keyboardNavigationLabelProvider); - this.disposables.push(this.typeLabelController); + this.disposables.add(this.typeLabelController); } - this.disposables.push(this.createMouseController(_options)); + this.disposables.add(this.createMouseController(_options)); this.onFocusChange(this._onFocusChange, this, this.disposables); this.onSelectionChange(this._onSelectionChange, this, this.disposables); @@ -1607,7 +1612,7 @@ export class List implements ISpliceable, IDisposable { dispose(): void { this._onDidDispose.fire(); - this.disposables = dispose(this.disposables); + this.disposables.dispose(); this._onDidOpen.dispose(); this._onPin.dispose(); diff --git a/src/vs/base/browser/ui/list/media/close-dark.svg b/src/vs/base/browser/ui/list/media/close-dark.svg index 751e89b3b..7305a8f09 100644 --- a/src/vs/base/browser/ui/list/media/close-dark.svg +++ b/src/vs/base/browser/ui/list/media/close-dark.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + diff --git a/src/vs/base/browser/ui/list/media/close-hc.svg b/src/vs/base/browser/ui/list/media/close-hc.svg index c20895c60..7305a8f09 100644 --- a/src/vs/base/browser/ui/list/media/close-hc.svg +++ b/src/vs/base/browser/ui/list/media/close-hc.svg @@ -1,33 +1,3 @@ - - - - - - image/svg+xml - - - - - - - + + diff --git a/src/vs/base/browser/ui/list/media/close-light.svg b/src/vs/base/browser/ui/list/media/close-light.svg new file mode 100644 index 000000000..ecddcd665 --- /dev/null +++ b/src/vs/base/browser/ui/list/media/close-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/list/media/filter-dark.svg b/src/vs/base/browser/ui/list/media/filter-dark.svg index 0925909a1..46c35f437 100644 --- a/src/vs/base/browser/ui/list/media/filter-dark.svg +++ b/src/vs/base/browser/ui/list/media/filter-dark.svg @@ -1,5 +1,3 @@ - - - + diff --git a/src/vs/base/browser/ui/list/media/filter-hc.svg b/src/vs/base/browser/ui/list/media/filter-hc.svg index 0e2724f52..d7b6bdd39 100644 --- a/src/vs/base/browser/ui/list/media/filter-hc.svg +++ b/src/vs/base/browser/ui/list/media/filter-hc.svg @@ -1,5 +1,3 @@ - - - + diff --git a/src/vs/base/browser/ui/list/media/filter-light.svg b/src/vs/base/browser/ui/list/media/filter-light.svg new file mode 100644 index 000000000..2550d80cb --- /dev/null +++ b/src/vs/base/browser/ui/list/media/filter-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/list/media/filter.svg b/src/vs/base/browser/ui/list/media/filter.svg deleted file mode 100644 index f8c011064..000000000 --- a/src/vs/base/browser/ui/list/media/filter.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/base/browser/ui/list/media/no-filter-dark.svg b/src/vs/base/browser/ui/list/media/no-filter-dark.svg index 5f495c006..6fc07d81a 100644 --- a/src/vs/base/browser/ui/list/media/no-filter-dark.svg +++ b/src/vs/base/browser/ui/list/media/no-filter-dark.svg @@ -1,5 +1,3 @@ - - - + diff --git a/src/vs/base/browser/ui/list/media/no-filter-hc.svg b/src/vs/base/browser/ui/list/media/no-filter-hc.svg index 31d8f70f0..6fc07d81a 100644 --- a/src/vs/base/browser/ui/list/media/no-filter-hc.svg +++ b/src/vs/base/browser/ui/list/media/no-filter-hc.svg @@ -1,5 +1,3 @@ - - - + diff --git a/src/vs/base/browser/ui/list/media/no-filter-light.svg b/src/vs/base/browser/ui/list/media/no-filter-light.svg new file mode 100644 index 000000000..3608b15d2 --- /dev/null +++ b/src/vs/base/browser/ui/list/media/no-filter-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/list/media/no-filter.svg b/src/vs/base/browser/ui/list/media/no-filter.svg deleted file mode 100644 index 760cc3c44..000000000 --- a/src/vs/base/browser/ui/list/media/no-filter.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/base/browser/ui/list/rangeMap.ts b/src/vs/base/browser/ui/list/rangeMap.ts index 73c6b7419..1bf7217d0 100644 --- a/src/vs/base/browser/ui/list/rangeMap.ts +++ b/src/vs/base/browser/ui/list/rangeMap.ts @@ -190,4 +190,4 @@ export class RangeMap { dispose() { this.groups = null!; // StrictNullOverride: nulling out ok in dispose } -} \ No newline at end of file +} diff --git a/src/vs/base/browser/ui/menu/check.svg b/src/vs/base/browser/ui/menu/check.svg index 3f365c480..865cc83c3 100644 --- a/src/vs/base/browser/ui/menu/check.svg +++ b/src/vs/base/browser/ui/menu/check.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + diff --git a/src/vs/base/browser/ui/menu/ellipsis.svg b/src/vs/base/browser/ui/menu/ellipsis.svg index e3f856233..2c52e359f 100644 --- a/src/vs/base/browser/ui/menu/ellipsis.svg +++ b/src/vs/base/browser/ui/menu/ellipsis.svg @@ -1 +1,5 @@ -Ellipsis_bold_16x \ No newline at end of file + + + + + diff --git a/src/vs/base/browser/ui/menu/menu.css b/src/vs/base/browser/ui/menu/menu.css index f1cdb6f3e..cbd6ce1a9 100644 --- a/src/vs/base/browser/ui/menu/menu.css +++ b/src/vs/base/browser/ui/menu/menu.css @@ -133,7 +133,7 @@ } .monaco-menu .monaco-action-bar.vertical .action-item { - border: 1px solid transparent; /* prevents jumping behaviour on hover or focus */ + border: thin solid transparent; /* prevents jumping behaviour on hover or focus */ } diff --git a/src/vs/base/browser/ui/menu/menu.ts b/src/vs/base/browser/ui/menu/menu.ts index 26d89db30..7913bb42f 100644 --- a/src/vs/base/browser/ui/menu/menu.ts +++ b/src/vs/base/browser/ui/menu/menu.ts @@ -7,18 +7,18 @@ import 'vs/css!./menu'; import * as nls from 'vs/nls'; import * as strings from 'vs/base/common/strings'; import { IActionRunner, IAction, Action } from 'vs/base/common/actions'; -import { ActionBar, IActionItemProvider, ActionsOrientation, Separator, ActionItem, IActionItemOptions, BaseActionItem } from 'vs/base/browser/ui/actionbar/actionbar'; +import { ActionBar, IActionViewItemProvider, ActionsOrientation, Separator, ActionViewItem, IActionViewItemOptions, BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { ResolvedKeybinding, KeyCode } from 'vs/base/common/keyCodes'; import { addClass, EventType, EventHelper, EventLike, removeTabIndexAndUpdateFocus, isAncestor, hasClass, addDisposableListener, removeClass, append, $, addClasses, removeClasses } from 'vs/base/browser/dom'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { RunOnceScheduler } from 'vs/base/common/async'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { DisposableStore } from 'vs/base/common/lifecycle'; import { Color } from 'vs/base/common/color'; import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; import { ScrollbarVisibility, ScrollEvent } from 'vs/base/common/scrollable'; import { Event, Emitter } from 'vs/base/common/event'; import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview'; -import { isLinux } from 'vs/base/common/platform'; +import { isLinux, isMacintosh } from 'vs/base/common/platform'; function createMenuMnemonicRegExp() { try { @@ -39,7 +39,7 @@ export const MENU_ESCAPED_MNEMONIC_REGEX: RegExp = createMenuEscapedMnemonicRegE export interface IMenuOptions { context?: any; - actionItemProvider?: IActionItemProvider; + actionViewItemProvider?: IActionViewItemProvider; actionRunner?: IActionRunner; getKeyBinding?: (action: IAction) => ResolvedKeybinding | undefined; ariaLabel?: string; @@ -59,7 +59,7 @@ export interface IMenuStyles { } export class SubmenuAction extends Action { - constructor(label: string, public entries: Array, cssClass?: string) { + constructor(label: string, public entries: ReadonlyArray, cssClass?: string) { super(!!cssClass ? cssClass : 'submenu', label, '', true); } } @@ -70,16 +70,15 @@ interface ISubMenuData { } export class Menu extends ActionBar { - private mnemonics: Map>; - private menuDisposables: IDisposable[]; + private mnemonics: Map>; + private readonly menuDisposables: DisposableStore; private scrollableElement: DomScrollableElement; private menuElement: HTMLElement; private scrollTopHold: number | undefined; private readonly _onScroll: Emitter; - constructor(container: HTMLElement, actions: IAction[], options: IMenuOptions = {}) { - + constructor(container: HTMLElement, actions: ReadonlyArray, options: IMenuOptions = {}) { addClass(container, 'monaco-menu-container'); container.setAttribute('role', 'presentation'); const menuElement = document.createElement('div'); @@ -88,11 +87,11 @@ export class Menu extends ActionBar { super(menuElement, { orientation: ActionsOrientation.VERTICAL, - actionItemProvider: action => this.doGetActionItem(action, options, parentData), + actionViewItemProvider: action => this.doGetActionViewItem(action, options, parentData), context: options.context, actionRunner: options.actionRunner, ariaLabel: options.ariaLabel, - triggerKeys: { keys: [KeyCode.Enter], keyDown: true } + triggerKeys: { keys: [KeyCode.Enter, ...(isMacintosh ? [KeyCode.Space] : [])], keyDown: true } }); this.menuElement = menuElement; @@ -103,17 +102,26 @@ export class Menu extends ActionBar { this.actionsList.tabIndex = 0; - this.menuDisposables = []; + this.menuDisposables = this._register(new DisposableStore()); + + addDisposableListener(menuElement, EventType.KEY_DOWN, (e) => { + const event = new StandardKeyboardEvent(e); + + // Stop tab navigation of menus + if (event.equals(KeyCode.Tab)) { + e.preventDefault(); + } + }); if (options.enableMnemonics) { - this.menuDisposables.push(addDisposableListener(menuElement, EventType.KEY_DOWN, (e) => { + this.menuDisposables.add(addDisposableListener(menuElement, EventType.KEY_DOWN, (e) => { const key = e.key.toLocaleLowerCase(); if (this.mnemonics.has(key)) { EventHelper.stop(e, true); const actions = this.mnemonics.get(key)!; if (actions.length === 1) { - if (actions[0] instanceof SubmenuActionItem) { + if (actions[0] instanceof SubmenuMenuActionViewItem) { this.focusItemByElement(actions[0].container); } @@ -138,7 +146,7 @@ export class Menu extends ActionBar { const event = new StandardKeyboardEvent(e); if (event.equals(KeyCode.Home) || event.equals(KeyCode.PageUp)) { - this.focusedItem = this.items.length - 1; + this.focusedItem = this.viewItems.length - 1; this.focusNext(); EventHelper.stop(e, true); } else if (event.equals(KeyCode.End) || event.equals(KeyCode.PageDown)) { @@ -189,7 +197,7 @@ export class Menu extends ActionBar { parent: this }; - this.mnemonics = new Map>(); + this.mnemonics = new Map>(); this.push(actions, { icon: true, label: true, isMenu: true }); @@ -208,9 +216,9 @@ export class Menu extends ActionBar { menuElement.style.maxHeight = `${Math.max(10, window.innerHeight - container.getBoundingClientRect().top - 30)}px`; - this.scrollableElement.onScroll(() => { + this.menuDisposables.add(this.scrollableElement.onScroll(() => { this._onScroll.fire(); - }, this, this.menuDisposables); + }, this)); this._register(addDisposableListener(this.menuElement, EventType.SCROLL, (e: ScrollEvent) => { if (this.scrollTopHold !== undefined) { @@ -223,7 +231,7 @@ export class Menu extends ActionBar { container.appendChild(this.scrollableElement.getDomNode()); this.scrollableElement.scanDomNode(); - this.items.filter(item => !(item instanceof MenuSeparatorActionItem)).forEach((item: MenuActionItem, index: number, array: any[]) => { + this.viewItems.filter(item => !(item instanceof MenuSeparatorActionViewItem)).forEach((item: BaseMenuActionViewItem, index: number, array: any[]) => { item.updatePositionInSet(index + 1, array.length); }); } @@ -241,9 +249,9 @@ export class Menu extends ActionBar { this.domNode.style.backgroundColor = bgColor; container.style.boxShadow = shadow; - if (this.items) { - this.items.forEach(item => { - if (item instanceof MenuActionItem || item instanceof MenuSeparatorActionItem) { + if (this.viewItems) { + this.viewItems.forEach(item => { + if (item instanceof BaseMenuActionViewItem || item instanceof MenuSeparatorActionViewItem) { item.style(style); } }); @@ -263,12 +271,12 @@ export class Menu extends ActionBar { } trigger(index: number): void { - if (index <= this.items.length && index >= 0) { - const item = this.items[index]; - if (item instanceof SubmenuActionItem) { + if (index <= this.viewItems.length && index >= 0) { + const item = this.viewItems[index]; + if (item instanceof SubmenuMenuActionViewItem) { super.focus(index); item.open(true); - } else if (item instanceof MenuActionItem) { + } else if (item instanceof BaseMenuActionViewItem) { super.run(item._action, item._context); } else { return; @@ -295,27 +303,27 @@ export class Menu extends ActionBar { } } - private doGetActionItem(action: IAction, options: IMenuOptions, parentData: ISubMenuData): BaseActionItem { + private doGetActionViewItem(action: IAction, options: IMenuOptions, parentData: ISubMenuData): BaseActionViewItem { if (action instanceof Separator) { - return new MenuSeparatorActionItem(options.context, action, { icon: true }); + return new MenuSeparatorActionViewItem(options.context, action, { icon: true }); } else if (action instanceof SubmenuAction) { - const menuActionItem = new SubmenuActionItem(action, action.entries, parentData, options); + const menuActionViewItem = new SubmenuMenuActionViewItem(action, action.entries, parentData, options); if (options.enableMnemonics) { - const mnemonic = menuActionItem.getMnemonic(); - if (mnemonic && menuActionItem.isEnabled()) { - let actionItems: MenuActionItem[] = []; + const mnemonic = menuActionViewItem.getMnemonic(); + if (mnemonic && menuActionViewItem.isEnabled()) { + let actionViewItems: BaseMenuActionViewItem[] = []; if (this.mnemonics.has(mnemonic)) { - actionItems = this.mnemonics.get(mnemonic)!; + actionViewItems = this.mnemonics.get(mnemonic)!; } - actionItems.push(menuActionItem); + actionViewItems.push(menuActionViewItem); - this.mnemonics.set(mnemonic, actionItems); + this.mnemonics.set(mnemonic, actionViewItems); } } - return menuActionItem; + return menuActionViewItem; } else { const menuItemOptions: IMenuItemOptions = { enableMnemonics: options.enableMnemonics }; if (options.getKeyBinding) { @@ -329,32 +337,32 @@ export class Menu extends ActionBar { } } - const menuActionItem = new MenuActionItem(options.context, action, menuItemOptions); + const menuActionViewItem = new BaseMenuActionViewItem(options.context, action, menuItemOptions); if (options.enableMnemonics) { - const mnemonic = menuActionItem.getMnemonic(); - if (mnemonic && menuActionItem.isEnabled()) { - let actionItems: MenuActionItem[] = []; + const mnemonic = menuActionViewItem.getMnemonic(); + if (mnemonic && menuActionViewItem.isEnabled()) { + let actionViewItems: BaseMenuActionViewItem[] = []; if (this.mnemonics.has(mnemonic)) { - actionItems = this.mnemonics.get(mnemonic)!; + actionViewItems = this.mnemonics.get(mnemonic)!; } - actionItems.push(menuActionItem); + actionViewItems.push(menuActionViewItem); - this.mnemonics.set(mnemonic, actionItems); + this.mnemonics.set(mnemonic, actionViewItems); } } - return menuActionItem; + return menuActionViewItem; } } } -interface IMenuItemOptions extends IActionItemOptions { +interface IMenuItemOptions extends IActionViewItemOptions { enableMnemonics?: boolean; } -class MenuActionItem extends BaseActionItem { +class BaseMenuActionViewItem extends BaseActionViewItem { public container: HTMLElement; @@ -548,7 +556,7 @@ class MenuActionItem extends BaseActionItem { const isSelected = this.element && hasClass(this.element, 'focused'); const fgColor = isSelected && this.menuStyle.selectionForegroundColor ? this.menuStyle.selectionForegroundColor : this.menuStyle.foregroundColor; const bgColor = isSelected && this.menuStyle.selectionBackgroundColor ? this.menuStyle.selectionBackgroundColor : this.menuStyle.backgroundColor; - const border = isSelected && this.menuStyle.selectionBorderColor ? `1px solid ${this.menuStyle.selectionBorderColor}` : null; + const border = isSelected && this.menuStyle.selectionBorderColor ? `thin solid ${this.menuStyle.selectionBorderColor}` : null; this.item.style.color = fgColor ? `${fgColor}` : null; this.check.style.backgroundColor = fgColor ? `${fgColor}` : null; @@ -562,18 +570,18 @@ class MenuActionItem extends BaseActionItem { } } -class SubmenuActionItem extends MenuActionItem { +class SubmenuMenuActionViewItem extends BaseMenuActionViewItem { private mysubmenu: Menu | null; private submenuContainer: HTMLElement | undefined; private submenuIndicator: HTMLElement; - private submenuDisposables: IDisposable[] = []; + private readonly submenuDisposables = this._register(new DisposableStore()); private mouseOver: boolean; private showScheduler: RunOnceScheduler; private hideScheduler: RunOnceScheduler; constructor( action: IAction, - private submenuActions: IAction[], + private submenuActions: ReadonlyArray, private parentData: ISubMenuData, private submenuOptions?: IMenuOptions ) { @@ -666,7 +674,7 @@ class SubmenuActionItem extends MenuActionItem { this.parentData.submenu = undefined; if (this.submenuContainer) { - this.submenuDisposables = dispose(this.submenuDisposables); + this.submenuDisposables.clear(); this.submenuContainer = undefined; } } @@ -699,7 +707,7 @@ class SubmenuActionItem extends MenuActionItem { this.submenuContainer.style.top = `${this.element.offsetTop - this.parentData.parent.scrollOffset - paddingTop}px`; } - this.submenuDisposables.push(addDisposableListener(this.submenuContainer, EventType.KEY_UP, e => { + this.submenuDisposables.add(addDisposableListener(this.submenuContainer, EventType.KEY_UP, e => { let event = new StandardKeyboardEvent(e); if (event.equals(KeyCode.LeftArrow)) { EventHelper.stop(e, true); @@ -711,12 +719,12 @@ class SubmenuActionItem extends MenuActionItem { this.parentData.submenu = undefined; } - this.submenuDisposables = dispose(this.submenuDisposables); + this.submenuDisposables.clear(); this.submenuContainer = undefined; } })); - this.submenuDisposables.push(addDisposableListener(this.submenuContainer, EventType.KEY_DOWN, e => { + this.submenuDisposables.add(addDisposableListener(this.submenuContainer, EventType.KEY_DOWN, e => { let event = new StandardKeyboardEvent(e); if (event.equals(KeyCode.LeftArrow)) { EventHelper.stop(e, true); @@ -724,7 +732,7 @@ class SubmenuActionItem extends MenuActionItem { })); - this.submenuDisposables.push(this.parentData.submenu.onDidCancel(() => { + this.submenuDisposables.add(this.parentData.submenu.onDidCancel(() => { this.parentData.parent.focus(); if (this.parentData.submenu) { @@ -732,7 +740,7 @@ class SubmenuActionItem extends MenuActionItem { this.parentData.submenu = undefined; } - this.submenuDisposables = dispose(this.submenuDisposables); + this.submenuDisposables.clear(); this.submenuContainer = undefined; })); @@ -772,13 +780,12 @@ class SubmenuActionItem extends MenuActionItem { } if (this.submenuContainer) { - this.submenuDisposables = dispose(this.submenuDisposables); this.submenuContainer = undefined; } } } -class MenuSeparatorActionItem extends ActionItem { +class MenuSeparatorActionViewItem extends ActionViewItem { style(style: IMenuStyles): void { this.label.style.borderBottomColor = style.separatorColor ? `${style.separatorColor}` : null; } diff --git a/src/vs/base/browser/ui/menu/menubar.ts b/src/vs/base/browser/ui/menu/menubar.ts index 631b81f70..1ffcb47b9 100644 --- a/src/vs/base/browser/ui/menu/menubar.ts +++ b/src/vs/base/browser/ui/menu/menubar.ts @@ -14,22 +14,25 @@ import { cleanMnemonic, IMenuOptions, Menu, MENU_ESCAPED_MNEMONIC_REGEX, MENU_MN import { ActionRunner, IAction, IActionRunner } from 'vs/base/common/actions'; import { RunOnceScheduler } from 'vs/base/common/async'; import { Event, Emitter } from 'vs/base/common/event'; -import { KeyCode, ResolvedKeybinding } from 'vs/base/common/keyCodes'; -import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { KeyCode, ResolvedKeybinding, KeyMod } from 'vs/base/common/keyCodes'; +import { Disposable, dispose, IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { withNullAsUndefined } from 'vs/base/common/types'; import { asArray } from 'vs/base/common/arrays'; +import { ScanCodeUtils, ScanCode } from 'vs/base/common/scanCode'; +import { isMacintosh } from 'vs/base/common/platform'; const $ = DOM.$; export interface IMenuBarOptions { enableMnemonics?: boolean; + disableAltFocus?: boolean; visibility?: string; getKeybinding?: (action: IAction) => ResolvedKeybinding | undefined; alwaysOnMnemonics?: boolean; } export interface MenuBarMenu { - actions: IAction[]; + actions: ReadonlyArray; label: string; } @@ -48,7 +51,7 @@ export class MenuBar extends Disposable { buttonElement: HTMLElement; titleElement: HTMLElement; label: string; - actions?: IAction[]; + actions?: ReadonlyArray; }[]; private overflowMenu: { @@ -114,9 +117,9 @@ export class MenuBar extends Disposable { let eventHandled = true; const key = !!e.key ? e.key.toLocaleLowerCase() : ''; - if (event.equals(KeyCode.LeftArrow)) { + if (event.equals(KeyCode.LeftArrow) || (isMacintosh && event.equals(KeyCode.Tab | KeyMod.Shift))) { this.focusPrevious(); - } else if (event.equals(KeyCode.RightArrow)) { + } else if (event.equals(KeyCode.RightArrow) || (isMacintosh && event.equals(KeyCode.Tab))) { this.focusNext(); } else if (event.equals(KeyCode.Escape) && this.isFocused && !this.isOpen) { this.setUnfocusedState(); @@ -127,6 +130,11 @@ export class MenuBar extends Disposable { eventHandled = false; } + // Never allow default tab behavior + if (event.equals(KeyCode.Tab | KeyMod.Shift) || event.equals(KeyCode.Tab)) { + event.preventDefault(); + } + if (eventHandled) { event.preventDefault(); event.stopPropagation(); @@ -776,6 +784,13 @@ export class MenuBar extends Disposable { return; } + // Prevent alt-key default if the menu is not hidden and we use alt to focus + if (modifierKeyStatus.event && !this.options.disableAltFocus) { + if (ScanCodeUtils.toEnum(modifierKeyStatus.event.code) === ScanCode.AltLeft) { + modifierKeyStatus.event.preventDefault(); + } + } + // Alt key pressed while menu is focused. This should return focus away from the menubar if (this.isFocused && modifierKeyStatus.lastKeyPressed === 'alt' && modifierKeyStatus.altKey) { this.setUnfocusedState(); @@ -786,7 +801,7 @@ export class MenuBar extends Disposable { // Clean alt key press and release if (allModifiersReleased && modifierKeyStatus.lastKeyPressed === 'alt' && modifierKeyStatus.lastKeyReleased === 'alt') { if (!this.awaitingAltRelease) { - if (!this.isFocused) { + if (!this.isFocused && !(this.options.disableAltFocus && this.options.visibility !== 'toggle')) { this.mnemonicsInUse = true; this.focusedMenu = { index: this.numMenusShown > 0 ? 0 : MenuBar.OVERFLOW_INDEX }; this.focusState = MenubarState.FOCUSED; @@ -891,12 +906,13 @@ interface IModifierKeyStatus { ctrlKey: boolean; lastKeyPressed?: ModifierKey; lastKeyReleased?: ModifierKey; + event?: KeyboardEvent; } class ModifierKeyEmitter extends Emitter { - private _subscriptions: IDisposable[] = []; + private readonly _subscriptions = new DisposableStore(); private _keyStatus: IModifierKeyStatus; private static instance: ModifierKeyEmitter; @@ -909,7 +925,7 @@ class ModifierKeyEmitter extends Emitter { ctrlKey: false }; - this._subscriptions.push(domEvent(document.body, 'keydown', true)(e => { + this._subscriptions.add(domEvent(document.body, 'keydown', true)(e => { const event = new StandardKeyboardEvent(e); if (e.altKey && !this._keyStatus.altKey) { @@ -929,11 +945,12 @@ class ModifierKeyEmitter extends Emitter { this._keyStatus.shiftKey = e.shiftKey; if (this._keyStatus.lastKeyPressed) { + this._keyStatus.event = e; this.fire(this._keyStatus); } })); - this._subscriptions.push(domEvent(document.body, 'keyup', true)(e => { + this._subscriptions.add(domEvent(document.body, 'keyup', true)(e => { if (!e.altKey && this._keyStatus.altKey) { this._keyStatus.lastKeyReleased = 'alt'; } else if (!e.ctrlKey && this._keyStatus.ctrlKey) { @@ -953,25 +970,26 @@ class ModifierKeyEmitter extends Emitter { this._keyStatus.shiftKey = e.shiftKey; if (this._keyStatus.lastKeyReleased) { + this._keyStatus.event = e; this.fire(this._keyStatus); } })); - this._subscriptions.push(domEvent(document.body, 'mousedown', true)(e => { + this._subscriptions.add(domEvent(document.body, 'mousedown', true)(e => { this._keyStatus.lastKeyPressed = undefined; })); - this._subscriptions.push(domEvent(document.body, 'mouseup', true)(e => { + this._subscriptions.add(domEvent(document.body, 'mouseup', true)(e => { this._keyStatus.lastKeyPressed = undefined; })); - this._subscriptions.push(domEvent(document.body, 'mousemove', true)(e => { + this._subscriptions.add(domEvent(document.body, 'mousemove', true)(e => { if (e.buttons) { this._keyStatus.lastKeyPressed = undefined; } })); - this._subscriptions.push(domEvent(window, 'blur')(e => { + this._subscriptions.add(domEvent(window, 'blur')(e => { this._keyStatus.lastKeyPressed = undefined; this._keyStatus.lastKeyReleased = undefined; this._keyStatus.altKey = false; @@ -992,6 +1010,6 @@ class ModifierKeyEmitter extends Emitter { dispose() { super.dispose(); - this._subscriptions = dispose(this._subscriptions); + this._subscriptions.dispose(); } } \ No newline at end of file diff --git a/src/vs/base/browser/ui/octiconLabel/octicons/octicons.css b/src/vs/base/browser/ui/octiconLabel/octicons/octicons.css index d58373304..d9cc1b7a4 100644 --- a/src/vs/base/browser/ui/octiconLabel/octicons/octicons.css +++ b/src/vs/base/browser/ui/octiconLabel/octicons/octicons.css @@ -1,7 +1,7 @@ @font-face { font-family: "octicons"; - src: url("./octicons.ttf?91284a5a76ea88faeb754359b7f7cd03") format("truetype"), -url("./octicons.svg?91284a5a76ea88faeb754359b7f7cd03#octicons") format("svg"); + src: url("./octicons.ttf?1b0f2a9535896866c74dd24eedeb4374") format("truetype"), +url("./octicons.svg?1b0f2a9535896866c74dd24eedeb4374#octicons") format("svg"); } .octicon, .mega-octicon { @@ -235,10 +235,14 @@ url("./octicons.svg?91284a5a76ea88faeb754359b7f7cd03#octicons") format("svg"); .octicon-zap:before { content: "\26a1" } .octicon-archive:before { content: "\f101" } .octicon-arrow-both:before { content: "\f102" } -.octicon-eye-closed:before { content: "\f103" } -.octicon-fold-down:before { content: "\f104" } -.octicon-fold-up:before { content: "\f105" } -.octicon-github-action:before { content: "\f106" } -.octicon-play:before { content: "\f107" } -.octicon-remote:before { content: "\f108" } -.octicon-request-changes:before { content: "\f109" } +.octicon-error:before { content: "\f103" } +.octicon-eye-closed:before { content: "\f104" } +.octicon-fold-down:before { content: "\f105" } +.octicon-fold-up:before { content: "\f106" } +.octicon-github-action:before { content: "\f107" } +.octicon-info-outline:before { content: "\f108" } +.octicon-play:before { content: "\f109" } +.octicon-remote:before { content: "\f10a" } +.octicon-request-changes:before { content: "\f10b" } +.octicon-smiley-outline:before { content: "\f10c" } +.octicon-warning:before { content: "\f10d" } diff --git a/src/vs/base/browser/ui/octiconLabel/octicons/octicons.svg b/src/vs/base/browser/ui/octiconLabel/octicons/octicons.svg index af8396097..3f4ab4f18 100644 --- a/src/vs/base/browser/ui/octiconLabel/octicons/octicons.svg +++ b/src/vs/base/browser/ui/octiconLabel/octicons/octicons.svg @@ -42,10 +42,10 @@ horiz-adv-x="625" d=" M312.5 632.5L0 257.5H187.5V7.5H437.5V257.5H625L312.5 632.5z" /> + horiz-adv-x="1000" d=" M881.8625 -40.39375L697.0187500000001 374.6875V593.4375H751.7062500000001V648.125H259.51625V593.4375H314.20375V374.6875L129.906875 -40.39375C113.500625 -76.4874999999999 140.2975 -117.5 179.6725 -117.5H832.6437500000001C872.01875 -117.5 898.26875 -76.4874999999999 882.40625 -40.39375H881.8625zM300.531875 210.625L368.89125 374.6875V593.4375H642.3312500000001V374.6875L710.6875 210.625H300.531875V210.625zM532.95375 320H587.64125V265.3125H532.95375V320V320zM478.26625 374.6875H423.57875V429.375H478.26625V374.6875V374.6875zM478.26625 538.75H532.95375V484.0625H478.26625V538.75V538.75zM478.26625 702.8125H423.57875V757.5H478.26625V702.8125V702.8125z" /> + horiz-adv-x="875" d=" M816.66875 115.83125V57.5H0V115.83125L42.5833125 149.6687499999999C87.5 194.58125 89.833125 298.416875 112 407.5C156.916875 627.416875 350 699.166875 350 699.166875C350 731.25 376.25 757.5 408.333125 757.5C440.416875 757.5 466.666875 731.25 466.666875 699.166875C466.666875 699.166875 664.4187499999999 627.416875 709.33125 407.5C731.5 297.833125 733.8312500000001 194 778.75 149.6687499999999L817.25 115.83125H816.66875zM408.333125 -117.5C473.083125 -117.5 525 -65.5812499999999 525 -0.8312500000001H291.666875C291.666875 -65.5812499999999 343.583125 -117.5 408.333125 -117.5V-117.5z" /> @@ -166,8 +166,11 @@ - + + + horiz-adv-x="1000" d=" M500 757.5C257.6925 757.5 62.5 562.3075 62.5 320C62.5 77.69375 257.6925 -117.5 500 -117.5C742.30625 -117.5 937.5 77.69375 937.5 320C937.5 562.3075 742.30625 757.5 500 757.5zM560.57625 10.3812499999999H432.6925V447.884375H560.57625V10.3812499999999zM560.57625 508.460625H432.6925V636.346875H560.57625V508.460625z" /> @@ -392,7 +398,7 @@ unicode="" horiz-adv-x="1000" d=" M625 745V695L656.25 632.5L375 445H137.5C110 445 95.625 411.875 116.25 391.25L312.5 195L62.5 -117.5L375 132.5L571.25 -63.75A31.25 31.25 0 0 1 625 -42.5V195L812.5 476.25L875 445H925C952.5 445 966.875 478.125 946.25 498.75L678.75 766.25A31.25 31.25 0 0 1 625 745z" /> + horiz-adv-x="937.5" d=" M605.46875 101.25H769.53125V648.125H605.46875V101.25V101.25zM386.71875 210.625H550.78125V648.125H386.71875V210.625V210.625zM167.96875 -8.125H332.03125V648.125H167.96875V-8.125V-8.125zM113.28125 -62.8125H824.21875V702.8125H113.28125V-62.8125V-62.8125zM824.21875 757.5H113.28125C83.09375 757.5 58.59375 733 58.59375 702.8125V-62.8125C58.59375 -93 83.09375 -117.5 113.28125 -117.5H824.21875C854.40625 -117.5 878.90625 -93 878.90625 -62.8125V702.8125C878.90625 733 854.40625 757.5 824.21875 757.5V757.5V757.5z" /> @@ -422,7 +428,7 @@ unicode="" horiz-adv-x="1000" d=" M299.375 438.125C315 453.75 315 480 299.375 495.625C279.375 516.25 269.3750000000001 543.125 269.3750000000001 570C269.3750000000001 596.875 279.3750000000001 623.75 299.3750000000001 644.375C315.0000000000001 660.625 315.0000000000001 686.25 299.3750000000001 701.875A38.3125 38.3125 0 0 1 271.2500000000001 713.75C261.2500000000001 713.75 250.6250000000001 710 243.1250000000001 701.875C207.5000000000001 665.625 190 617.5 190 570C190 522.5 208.125 474.375 243.1250000000001 438.1250000000001C258.7500000000001 422.5000000000001 284.3750000000001 422.5000000000001 299.3750000000001 438.1250000000001zM145.625 787.5A40.6875 40.6875 0 0 1 88.125 787.5C30 727.5 0.625 648.75 0.625 570.625C0.625 491.875 30 413.125 88.125 353.125C103.75 336.875 129.375 336.875 145 353.125S160.625 395.625 145 411.875C102.5 455.6249999999999 81.25 513.125 81.25 570.625C81.25 628.1249999999999 102.5 685.6249999999999 145 729.3749999999999A41.25 41.25 0 0 1 145.625 787.4999999999999zM501.25 468.7500000000001A101.25 101.25 0 1 1 400 570C399.3750000000001 514.375 445 468.75 501.25 468.75zM911.875 786.875A39.25 39.25 0 0 1 855 786.875C839.375 770.625 839.375 744.375 855 728.125C897.5 684.375 918.75 626.875 918.75 569.375C918.75 511.875 897.5 455 855 410.625C839.375 394.375 839.375 368.1250000000001 855 351.875A40.6875 40.6875 0 0 1 912.5 351.875C970.625 411.875 1000 490.625 1000 569.375A315.5 315.5 0 0 1 911.875 786.875zM501.25 387.5C475.6249999999999 387.5 449.375 393.75 426.25 406.25L229.375 -116.8749999999999H322.5L376.25 -54.3749999999999H626.25L678.75 -116.8749999999999H771.875L575.625 406.25C551.875 393.75 526.8750000000001 387.5 501.2500000000001 387.5zM500.625 357.5L563.75 132.5H438.75L500.625 357.5zM376.25 8.125L438.75 70.625H563.75L626.25 8.125H376.25zM700.625 701.875C685 686.25 685 660 700.625 644.375C720.6250000000001 623.75 730.6250000000001 596.875 730.6250000000001 570C730.6250000000001 543.125 720.6250000000001 516.25 700.625 495.6250000000001C685 479.3750000000001 685 453.7500000000001 700.625 438.1250000000001A39.375 39.375 0 0 1 756.8750000000001 438.1250000000001C792.5000000000001 474.3750000000001 810 522.5 810 570C810 617.5 792.5000000000001 665.625 756.8750000000001 701.875A39.625 39.625 0 0 1 700.625 701.875z" /> + + horiz-adv-x="1000" d=" M500 757.5C258.375 757.5 62.5 561.625 62.5 320C62.5 78.375 258.375 -117.5 500 -117.5C741.625 -117.5 937.5 78.375 937.5 320C937.5 561.625 741.625 757.5 500 757.5zM653.125 582.5C689.375 582.5 718.75 543.3125 718.75 495C718.75 446.6875 689.375 407.5 653.125 407.5C616.875 407.5 587.5 446.6875 587.5 495C587.5 543.3125 616.875 582.5 653.125 582.5zM346.875 582.5C383.125 582.5 412.5 543.3125 412.5 495C412.5 446.6875 383.125 407.5 346.875 407.5C310.625 407.5 281.25 446.6875 281.25 495C281.25 543.3125 310.625 582.5 346.875 582.5zM778.1875 221.5625C736.4375 103.8125 624.6875 24.6875 500 24.6875C375.3125 24.6875 263.5 103.8125 221.8125 221.5C215.75 238.5625 224.6875 257.3125 241.75 263.375C258.9375 269.4375 277.625 260.4375 283.625 243.375C316.0625 151.8125 403 90.25 499.9375 90.25C596.875 90.25 683.75 151.75 716.25 243.375C722.3125 260.4375 741.25 269.4375 758.125 263.375C775.25 257.375 784.25 238.625 778.1875 221.5625z" /> @@ -525,7 +534,7 @@ horiz-adv-x="1000" d=" M998.75 309.375L938.125 -62.5000000000001C927.5 -148.75 820.625 -180 750 -180H355.625C343.125 -180 331.8750000000001 -176.875 322.5 -171.25L232.5 -117.5H125C58.75 -117.5 0 -58.75 0 7.5V257.5C0 323.7500000000001 58.75 383.75 125 382.5H250C306.875 382.5 336.875 410.625 399.3750000000001 479.375C456.2500000000001 541.875 454.3750000000001 591.875 438.7500000000001 683.75C433.75 715 442.5 746.25 465 772.5C489.375 801.875 526.25 820 562.5 820C676.875 820 750 588.125 750 506.875L748.75 445.625H876.25C948.75 445.625 998.1249999999998 395.625 1000 322.5C1000 315.625 998.75 309.375 998.75 309.375zM875.625 383.75H751.25C707.5 383.75 686.875 401.25 686.875 444.375L688.75 508.75C688.75 588.125 615.625 758.75 563.75 758.75C532.5 758.75 496.2499999999999 727.5 501.25 696.25C516.875 597.5 522.5 522.5 445.625 437.5C381.875 366.875 335 320 250 320V-55L354.375 -117.5H750C795.625 -117.5 871.875 -98.125 875 -55L876.25 -53.75L938.75 321.25C936.875 361.25 914.9999999999998 383.75 876.25 383.75H875.625z" /> + horiz-adv-x="1000" d=" M307.5 359.920625C321.71875 345.701875 377.5 287.18625 377.5 287.18625L408.125 318.9050000000001L360 368.6706250000001L452.421875 467.108125C452.421875 467.108125 410.859375 507.576875 428.90625 491.7175C446.40625 556.795625 430.546875 628.983125 381.328125 679.8425C332.109375 730.155 262.65625 746.56125 200.3125 729.608125L305.859375 620.233125L277.96875 513.045625L174.609375 484.608125L69.0625 593.983125C52.1095625 529.451875 67.96875 457.81125 117.1875 407.4987500000001C168.59375 353.9050000000001 242.421875 338.5925000000001 307.5 359.920625V359.920625zM659.6875 253.826875L532.265625 128.0437499999999L742.2687500000001 -89.6125000000001C759.21875 -107.65625 782.1875 -116.40625 804.6125 -116.40625C827.03125 -116.40625 849.4562500000001 -107.65625 866.95625 -89.6125000000001C901.40625 -54.0625 901.40625 3.35625 866.95625 38.90625L659.6875 253.826875V253.826875zM937.5 619.140625L803.51875 757.5L408.671875 349.53125L456.796875 299.765625L221.09375 55.8625L166.953125 26.875L90.9375 -97.2687499999999L110.078125 -117.5L230.390625 -38.75L258.28125 17.03125L494.53125 260.9375L542.65625 211.171875L937.5 619.140625V619.140625z" /> @@ -556,6 +565,9 @@ + diff --git a/src/vs/base/browser/ui/octiconLabel/octicons/octicons.ttf b/src/vs/base/browser/ui/octiconLabel/octicons/octicons.ttf index 8c29d3383..4eb17f904 100644 Binary files a/src/vs/base/browser/ui/octiconLabel/octicons/octicons.ttf and b/src/vs/base/browser/ui/octiconLabel/octicons/octicons.ttf differ diff --git a/src/vs/base/browser/ui/sash/sash.ts b/src/vs/base/browser/ui/sash/sash.ts index 8c7168bad..874bc9482 100644 --- a/src/vs/base/browser/ui/sash/sash.ts +++ b/src/vs/base/browser/ui/sash/sash.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./sash'; -import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { isIPad } from 'vs/base/browser/browser'; import { isMacintosh } from 'vs/base/common/platform'; import * as types from 'vs/base/common/types'; @@ -95,14 +95,14 @@ export class Sash extends Disposable { linkedSash: Sash | undefined = undefined; - private orthogonalStartSashDisposables: IDisposable[] = []; + private readonly orthogonalStartSashDisposables = this._register(new DisposableStore()); private _orthogonalStartSash: Sash | undefined; get orthogonalStartSash(): Sash | undefined { return this._orthogonalStartSash; } set orthogonalStartSash(sash: Sash | undefined) { - this.orthogonalStartSashDisposables = dispose(this.orthogonalStartSashDisposables); + this.orthogonalStartSashDisposables.clear(); if (sash) { - sash.onDidEnablementChange(this.onOrthogonalStartSashEnablementChange, this, this.orthogonalStartSashDisposables); + this.orthogonalStartSashDisposables.add(sash.onDidEnablementChange(this.onOrthogonalStartSashEnablementChange, this)); this.onOrthogonalStartSashEnablementChange(sash.state); } else { this.onOrthogonalStartSashEnablementChange(SashState.Disabled); @@ -111,14 +111,14 @@ export class Sash extends Disposable { this._orthogonalStartSash = sash; } - private orthogonalEndSashDisposables: IDisposable[] = []; + private readonly orthogonalEndSashDisposables = this._register(new DisposableStore()); private _orthogonalEndSash: Sash | undefined; get orthogonalEndSash(): Sash | undefined { return this._orthogonalEndSash; } set orthogonalEndSash(sash: Sash | undefined) { - this.orthogonalEndSashDisposables = dispose(this.orthogonalEndSashDisposables); + this.orthogonalEndSashDisposables.clear(); if (sash) { - sash.onDidEnablementChange(this.onOrthogonalEndSashEnablementChange, this, this.orthogonalEndSashDisposables); + this.orthogonalEndSashDisposables.add(sash.onDidEnablementChange(this.onOrthogonalEndSashEnablementChange, this)); this.onOrthogonalEndSashEnablementChange(sash.state); } else { this.onOrthogonalEndSashEnablementChange(SashState.Disabled); @@ -212,7 +212,13 @@ export class Sash extends Disposable { return; } - const iframes = getElementsByTagName('iframe'); + // Select both iframes and webviews; internally Electron nests an iframe + // in its component, but this isn't queryable. + const iframes = [ + ...getElementsByTagName('iframe'), + ...getElementsByTagName('webview'), + ]; + for (const iframe of iframes) { iframe.style.pointerEvents = 'none'; // disable mouse events on iframes as long as we drag the sash } @@ -254,7 +260,7 @@ export class Sash extends Disposable { style.innerHTML = `* { cursor: ${cursor} !important; }`; }; - const disposables: IDisposable[] = []; + const disposables = new DisposableStore(); updateStyle(); @@ -278,9 +284,8 @@ export class Sash extends Disposable { removeClass(this.el, 'active'); this._onDidEnd.fire(); - dispose(disposables); + disposables.dispose(); - const iframes = getElementsByTagName('iframe'); for (const iframe of iframes) { iframe.style.pointerEvents = 'auto'; } @@ -384,9 +389,6 @@ export class Sash extends Disposable { dispose(): void { super.dispose(); - this.orthogonalStartSashDisposables = dispose(this.orthogonalStartSashDisposables); - this.orthogonalEndSashDisposables = dispose(this.orthogonalEndSashDisposables); - if (this.el && this.el.parentElement) { this.el.parentElement.removeChild(this.el); } diff --git a/src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts b/src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts index 7de8f3fa7..21ccdfa0e 100644 --- a/src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts +++ b/src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts @@ -108,6 +108,12 @@ export abstract class AbstractScrollbar extends Widget { this._sliderMouseDown(e, () => { /*nothing to do*/ }); } }); + + this.onclick(this.slider.domNode, e => { + if (e.leftButton) { + e.stopPropagation(); + } + }); } // ----------------- Update state diff --git a/src/vs/base/browser/ui/scrollbar/scrollableElement.ts b/src/vs/base/browser/ui/scrollbar/scrollableElement.ts index fbf8d5dcd..1c1ded9eb 100644 --- a/src/vs/base/browser/ui/scrollbar/scrollableElement.ts +++ b/src/vs/base/browser/ui/scrollbar/scrollableElement.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/scrollbars'; +import { isEdgeOrIE } from 'vs/base/browser/browser'; import * as dom from 'vs/base/browser/dom'; import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode'; import { IMouseEvent, StandardWheelEvent, IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; @@ -312,7 +313,7 @@ export abstract class AbstractScrollableElement extends Widget { this._onMouseWheel(new StandardWheelEvent(browserEvent)); }; - this._mouseWheelToDispose.push(dom.addDisposableListener(this._listenOnDomNode, 'mousewheel', onMouseWheel)); + this._mouseWheelToDispose.push(dom.addDisposableListener(this._listenOnDomNode, isEdgeOrIE ? 'mousewheel' : 'wheel', onMouseWheel)); } } diff --git a/src/vs/base/browser/ui/selectBox/selectBox.ts b/src/vs/base/browser/ui/selectBox/selectBox.ts index d74c30c8d..7832680e2 100644 --- a/src/vs/base/browser/ui/selectBox/selectBox.ts +++ b/src/vs/base/browser/ui/selectBox/selectBox.ts @@ -14,11 +14,12 @@ import { IListStyles } from 'vs/base/browser/ui/list/listWidget'; import { SelectBoxNative } from 'vs/base/browser/ui/selectBox/selectBoxNative'; import { SelectBoxList } from 'vs/base/browser/ui/selectBox/selectBoxCustom'; import { isMacintosh } from 'vs/base/common/platform'; +import { IDisposable } from 'vs/base/common/lifecycle'; // Public SelectBox interface - Calls routed to appropriate select implementation class -export interface ISelectBoxDelegate { +export interface ISelectBoxDelegate extends IDisposable { // Public SelectBox Interface readonly onDidSelect: Event; @@ -27,7 +28,6 @@ export interface ISelectBoxDelegate { setAriaLabel(label: string): void; focus(): void; blur(): void; - dispose(): void; // Delegated Widget interface render(container: HTMLElement): void; @@ -129,4 +129,4 @@ export class SelectBox extends Widget implements ISelectBoxDelegate { public applyStyles(): void { this.selectBoxDelegate.applyStyles(); } -} \ No newline at end of file +} diff --git a/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts b/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts index 8908d68e3..f26942d54 100644 --- a/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts +++ b/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts @@ -5,7 +5,7 @@ import 'vs/css!./selectBoxCustom'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; import { Event, Emitter } from 'vs/base/common/event'; import { KeyCode, KeyCodeUtils } from 'vs/base/common/keyCodes'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; @@ -38,8 +38,8 @@ class SelectListRenderer implements IListRendererObject.create(null); + renderTemplate(container: HTMLElement): ISelectListTemplateData { + const data: ISelectListTemplateData = Object.create(null); data.disposables = []; data.root = container; data.text = dom.append(container, $('.option-text')); @@ -51,10 +51,10 @@ class SelectListRenderer implements IListRenderertemplateData; - const text = (element).text; - const decoratorRight = (element).decoratorRight; - const isDisabled = (element).isDisabled; + const data: ISelectListTemplateData = templateData; + const text = element.text; + const decoratorRight = element.decoratorRight; + const isDisabled = element.isDisabled; data.text.textContent = text; data.decoratorRight.innerText = (!!decoratorRight ? decoratorRight : ''); @@ -68,10 +68,10 @@ class SelectListRenderer implements IListRendererdata.root), 'option-disabled'); + dom.addClass(data.root, 'option-disabled'); } else { // Make sure we do class removal from prior template rendering - dom.removeClass((data.root), 'option-disabled'); + dom.removeClass(data.root, 'option-disabled'); } } @@ -80,7 +80,7 @@ class SelectListRenderer implements IListRenderer { +export class SelectBoxList extends Disposable implements ISelectBoxDelegate, IListVirtualDelegate { private static readonly DEFAULT_DROPDOWN_MINIMUM_BOTTOM_MARGIN = 32; private static readonly DEFAULT_DROPDOWN_MINIMUM_TOP_MARGIN = 2; @@ -92,7 +92,6 @@ export class SelectBoxList implements ISelectBoxDelegate, IListVirtualDelegate; - private toDispose: IDisposable[]; private styles: ISelectBoxStyles; private listRenderer: SelectListRenderer; private contextViewProvider: IContextViewProvider; @@ -111,7 +110,7 @@ export class SelectBoxList implements ISelectBoxDelegate, IListVirtualDelegate(); - this.toDispose.push(this._onDidSelect); + this._register(this._onDidSelect); this.styles = styles; @@ -185,18 +184,21 @@ export class SelectBoxList implements ISelectBoxDelegate, IListVirtualDelegate { + this._register(dom.addStandardDisposableListener(this.selectElement, 'change', (e) => { this.selected = e.target.selectedIndex; this._onDidSelect.fire({ index: e.target.selectedIndex, selected: e.target.value }); + if (!!this.options[this.selected] && !!this.options[this.selected].text) { + this.selectElement.title = this.options[this.selected].text; + } })); // Have to implement both keyboard and mouse controllers to handle disabled options // Intercept mouse events to override normal select actions on parents - this.toDispose.push(dom.addDisposableListener(this.selectElement, dom.EventType.CLICK, (e) => { + this._register(dom.addDisposableListener(this.selectElement, dom.EventType.CLICK, (e) => { dom.EventHelper.stop(e); if (this._isVisible) { @@ -206,13 +208,13 @@ export class SelectBoxList implements ISelectBoxDelegate, IListVirtualDelegate { + this._register(dom.addDisposableListener(this.selectElement, dom.EventType.MOUSE_DOWN, (e) => { dom.EventHelper.stop(e); })); // Intercept keyboard handling - this.toDispose.push(dom.addDisposableListener(this.selectElement, dom.EventType.KEY_DOWN, (e: KeyboardEvent) => { + this._register(dom.addDisposableListener(this.selectElement, dom.EventType.KEY_DOWN, (e: KeyboardEvent) => { const event = new StandardKeyboardEvent(e); let showDropDown = false; @@ -282,6 +284,9 @@ export class SelectBoxList implements ISelectBoxDelegate, IListVirtualDelegate this.selectList.length > 0) .map(e => new StandardKeyboardEvent(e)); - onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.Enter).on(e => this.onEnter(e), this, this.toDispose); - onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.Escape).on(e => this.onEscape(e), this, this.toDispose); - onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.UpArrow).on(this.onUpArrow, this, this.toDispose); - onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.DownArrow).on(this.onDownArrow, this, this.toDispose); - onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.PageDown).on(this.onPageDown, this, this.toDispose); - onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.PageUp).on(this.onPageUp, this, this.toDispose); - onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.Home).on(this.onHome, this, this.toDispose); - onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.End).on(this.onEnd, this, this.toDispose); - onSelectDropDownKeyDown.filter(e => (e.keyCode >= KeyCode.KEY_0 && e.keyCode <= KeyCode.KEY_Z) || (e.keyCode >= KeyCode.US_SEMICOLON && e.keyCode <= KeyCode.NUMPAD_DIVIDE)).on(this.onCharacter, this, this.toDispose); + this._register(onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.Enter).on(e => this.onEnter(e), this)); + this._register(onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.Escape).on(e => this.onEscape(e), this)); + this._register(onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.UpArrow).on(this.onUpArrow, this)); + this._register(onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.DownArrow).on(this.onDownArrow, this)); + this._register(onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.PageDown).on(this.onPageDown, this)); + this._register(onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.PageUp).on(this.onPageUp, this)); + this._register(onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.Home).on(this.onHome, this)); + this._register(onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.End).on(this.onEnd, this)); + this._register(onSelectDropDownKeyDown.filter(e => (e.keyCode >= KeyCode.KEY_0 && e.keyCode <= KeyCode.KEY_Z) || (e.keyCode >= KeyCode.US_SEMICOLON && e.keyCode <= KeyCode.NUMPAD_DIVIDE)).on(this.onCharacter, this)); // SetUp list mouse controller - control navigation, disabled items, focus - Event.chain(domEvent(this.selectList.getHTMLElement(), 'mouseup')) + this._register(Event.chain(domEvent(this.selectList.getHTMLElement(), 'mouseup')) .filter(() => this.selectList.length > 0) - .on(e => this.onMouseUp(e), this, this.toDispose); + .on(e => this.onMouseUp(e), this)); + - this.toDispose.push( - this.selectList.onDidBlur(_ => this.onListBlur()), - this.selectList.onMouseOver(e => typeof e.index !== 'undefined' && this.selectList.setFocus([e.index])), - this.selectList.onFocusChange(e => this.onListFocus(e)) - ); + this._register(this.selectList.onDidBlur(_ => this.onListBlur())); + this._register(this.selectList.onMouseOver(e => typeof e.index !== 'undefined' && this.selectList.setFocus([e.index]))); + this._register(this.selectList.onFocusChange(e => this.onListFocus(e))); this.selectList.getHTMLElement().setAttribute('aria-label', this.selectBoxOptions.ariaLabel || ''); this.selectList.getHTMLElement().setAttribute('aria-expanded', 'true'); @@ -798,7 +802,11 @@ export class SelectBoxList implements ISelectBoxDelegate, IListVirtualDelegate { for (let i = 0; i < element.childNodes.length; i++) { - const child = element.childNodes.item(i); + const child = element.childNodes.item(i); - const tagName = (child).tagName && (child).tagName.toLowerCase(); + const tagName = child.tagName && child.tagName.toLowerCase(); if (tagName === 'img') { element.removeChild(child); } else { @@ -891,6 +899,9 @@ export class SelectBoxList implements ISelectBoxDelegate, IListVirtualDelegate; - private toDispose: IDisposable[]; private styles: ISelectBoxStyles; constructor(options: ISelectOptionItem[], selected: number, styles: ISelectBoxStyles, selectBoxOptions?: ISelectBoxOptions) { - this.toDispose = []; + super(); this.selectBoxOptions = selectBoxOptions || Object.create(null); this.options = []; @@ -35,8 +34,7 @@ export class SelectBoxNative implements ISelectBoxDelegate { this.selectElement.setAttribute('aria-label', this.selectBoxOptions.ariaLabel); } - this._onDidSelect = new Emitter(); - this.toDispose.push(this._onDidSelect); + this._onDidSelect = this._register(new Emitter()); this.styles = styles; @@ -46,7 +44,7 @@ export class SelectBoxNative implements ISelectBoxDelegate { private registerListeners() { - this.toDispose.push(dom.addStandardDisposableListener(this.selectElement, 'change', (e) => { + this._register(dom.addStandardDisposableListener(this.selectElement, 'change', (e) => { this.selectElement.title = e.target.value; this._onDidSelect.fire({ index: e.target.selectedIndex, @@ -54,7 +52,7 @@ export class SelectBoxNative implements ISelectBoxDelegate { }); })); - this.toDispose.push(dom.addStandardDisposableListener(this.selectElement, 'keydown', (e) => { + this._register(dom.addStandardDisposableListener(this.selectElement, 'keydown', (e) => { let showSelect = false; if (isMacintosh) { @@ -168,8 +166,4 @@ export class SelectBoxNative implements ISelectBoxDelegate { return option; } - - public dispose(): void { - this.toDispose = dispose(this.toDispose); - } } diff --git a/src/vs/base/browser/ui/splitview/arrow-collapse-dark.svg b/src/vs/base/browser/ui/splitview/arrow-collapse-dark.svg deleted file mode 100644 index 6f3abfce7..000000000 --- a/src/vs/base/browser/ui/splitview/arrow-collapse-dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/base/browser/ui/splitview/arrow-collapse.svg b/src/vs/base/browser/ui/splitview/arrow-collapse.svg deleted file mode 100644 index 5dcb87c77..000000000 --- a/src/vs/base/browser/ui/splitview/arrow-collapse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/base/browser/ui/splitview/arrow-expand-dark.svg b/src/vs/base/browser/ui/splitview/arrow-expand-dark.svg deleted file mode 100644 index 22dfac04f..000000000 --- a/src/vs/base/browser/ui/splitview/arrow-expand-dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/base/browser/ui/splitview/arrow-expand.svg b/src/vs/base/browser/ui/splitview/arrow-expand.svg deleted file mode 100644 index e55ccd923..000000000 --- a/src/vs/base/browser/ui/splitview/arrow-expand.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/base/browser/ui/splitview/panelview.css b/src/vs/base/browser/ui/splitview/panelview.css index 4801a2bd3..d4def5846 100644 --- a/src/vs/base/browser/ui/splitview/panelview.css +++ b/src/vs/base/browser/ui/splitview/panelview.css @@ -27,23 +27,31 @@ } .monaco-panel-view .panel > .panel-header { - background-image: url('arrow-collapse.svg'); + background-image: url('tree-collapsed-light.svg'); background-position: 2px center; background-repeat: no-repeat; } .monaco-panel-view .panel > .panel-header.expanded { - background-image: url('arrow-expand.svg'); + background-image: url('tree-expanded-light.svg'); background-position: 2px center; background-repeat: no-repeat; } .vs-dark .monaco-panel-view .panel > .panel-header { - background-image: url('arrow-collapse-dark.svg'); + background-image: url('tree-collapsed-dark.svg'); } .vs-dark .monaco-panel-view .panel > .panel-header.expanded { - background-image: url('arrow-expand-dark.svg'); + background-image: url('tree-expanded-dark.svg'); +} + +.hc-black .monaco-panel-view .panel > .panel-header { + background-image: url('tree-collapsed-hc.svg'); +} + +.hc-black .monaco-panel-view .panel > .panel-header.expanded { + background-image: url('tree-expanded-hc.svg'); } /* TODO: actions should be part of the panel, but they aren't yet */ diff --git a/src/vs/base/browser/ui/splitview/panelview.ts b/src/vs/base/browser/ui/splitview/panelview.ts index 735c201e8..4d2fc8a61 100644 --- a/src/vs/base/browser/ui/splitview/panelview.ts +++ b/src/vs/base/browser/ui/splitview/panelview.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./panelview'; -import { IDisposable, dispose, combinedDisposable, Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { Event, Emitter } from 'vs/base/common/event'; import { domEvent } from 'vs/base/browser/event'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; @@ -37,7 +37,7 @@ export interface IPanelStyles { * Subclasses wouldn't be able to set own properties * before the `render()` call, thus forbiding their use. */ -export abstract class Panel implements IView { +export abstract class Panel extends Disposable implements IView { private static readonly HEADER_SIZE = 22; @@ -55,11 +55,9 @@ export abstract class Panel implements IView { private styles: IPanelStyles = {}; private animationTimer: number | undefined = undefined; - private _onDidChange = new Emitter(); + private readonly _onDidChange = this._register(new Emitter()); readonly onDidChange: Event = this._onDidChange.event; - protected disposables: IDisposable[] = []; - get draggableElement(): HTMLElement { return this.header; } @@ -114,6 +112,7 @@ export abstract class Panel implements IView { width: number; constructor(options: IPanelOptions = {}) { + super(); this._expanded = typeof options.expanded === 'undefined' ? true : !!options.expanded; this.ariaHeaderLabel = options.ariaHeaderLabel || ''; this._minimumBodySize = typeof options.minimumBodySize === 'number' ? options.minimumBodySize : 120; @@ -172,26 +171,26 @@ export abstract class Panel implements IView { this.renderHeader(this.header); const focusTracker = trackFocus(this.header); - this.disposables.push(focusTracker); - focusTracker.onDidFocus(() => addClass(this.header, 'focused'), null, this.disposables); - focusTracker.onDidBlur(() => removeClass(this.header, 'focused'), null, this.disposables); + this._register(focusTracker); + this._register(focusTracker.onDidFocus(() => addClass(this.header, 'focused'), null)); + this._register(focusTracker.onDidBlur(() => removeClass(this.header, 'focused'), null)); this.updateHeader(); const onHeaderKeyDown = Event.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); + this._register(onHeaderKeyDown.filter(e => e.keyCode === KeyCode.Enter || e.keyCode === KeyCode.Space) + .event(() => this.setExpanded(!this.isExpanded()), null)); - onHeaderKeyDown.filter(e => e.keyCode === KeyCode.LeftArrow) - .event(() => this.setExpanded(false), null, this.disposables); + this._register(onHeaderKeyDown.filter(e => e.keyCode === KeyCode.LeftArrow) + .event(() => this.setExpanded(false), null)); - onHeaderKeyDown.filter(e => e.keyCode === KeyCode.RightArrow) - .event(() => this.setExpanded(true), null, this.disposables); + this._register(onHeaderKeyDown.filter(e => e.keyCode === KeyCode.RightArrow) + .event(() => this.setExpanded(true), null)); - domEvent(this.header, 'click') - (() => this.setExpanded(!this.isExpanded()), null, this.disposables); + this._register(domEvent(this.header, 'click') + (() => this.setExpanded(!this.isExpanded()), null)); this.body = append(this.element, $('.panel-body')); this.renderBody(this.body); @@ -234,12 +233,6 @@ export abstract class Panel implements IView { protected abstract renderHeader(container: HTMLElement): void; protected abstract renderBody(container: HTMLElement): void; protected abstract layoutBody(height: number, width: number): void; - - dispose(): void { - this.disposables = dispose(this.disposables); - - this._onDidChange.dispose(); - } } interface IDndContext { @@ -397,24 +390,24 @@ export class PanelView extends Disposable { } addPanel(panel: Panel, size: number, index = this.splitview.length): void { - const disposables: IDisposable[] = []; + const disposables = new DisposableStore(); // https://github.com/Microsoft/vscode/issues/59950 let shouldAnimate = false; - disposables.push(scheduleAtNextAnimationFrame(() => shouldAnimate = true)); + disposables.add(scheduleAtNextAnimationFrame(() => shouldAnimate = true)); - Event.filter(panel.onDidChange, () => shouldAnimate) - (this.setupAnimation, this, disposables); + disposables.add(Event.filter(panel.onDidChange, () => shouldAnimate) + (this.setupAnimation, this)); - const panelItem = { panel, disposable: combinedDisposable(disposables) }; + const panelItem = { panel, disposable: disposables }; this.panelItems.splice(index, 0, panelItem); panel.width = this.width; this.splitview.addView(panel, size, index); if (this.dnd) { const draggable = new PanelDraggable(panel, this.dnd, this.dndContext); - disposables.push(draggable); - draggable.onDidDrop(this._onDidDrop.fire, this._onDidDrop, disposables); + disposables.add(draggable); + disposables.add(draggable.onDidDrop(this._onDidDrop.fire, this._onDidDrop)); } } diff --git a/src/vs/base/browser/ui/splitview/splitview.css b/src/vs/base/browser/ui/splitview/splitview.css index 7479f5178..6fb8f1c61 100644 --- a/src/vs/base/browser/ui/splitview/splitview.css +++ b/src/vs/base/browser/ui/splitview/splitview.css @@ -41,6 +41,10 @@ position: relative; } +.monaco-split-view2 > .split-view-container > .split-view-view:not(.visible) { + display: none; +} + .monaco-split-view2.vertical > .split-view-container > .split-view-view { width: 100%; } diff --git a/src/vs/base/browser/ui/splitview/splitview.ts b/src/vs/base/browser/ui/splitview/splitview.ts index b4142731b..6f031dac5 100644 --- a/src/vs/base/browser/ui/splitview/splitview.ts +++ b/src/vs/base/browser/ui/splitview/splitview.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./splitview'; -import { IDisposable, combinedDisposable, toDisposable, Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, toDisposable, Disposable, combinedDisposable } from 'vs/base/common/lifecycle'; import { Event, Emitter } from 'vs/base/common/event'; import * as types from 'vs/base/common/types'; import * as dom from 'vs/base/browser/dom'; @@ -47,7 +47,9 @@ export interface IView { readonly maximumSize: number; readonly onDidChange: Event; readonly priority?: LayoutPriority; + readonly snap?: boolean; layout(size: number, orientation: Orientation): void; + setVisible?(visible: boolean): void; } interface ISashEvent { @@ -57,12 +59,98 @@ interface ISashEvent { alt: boolean; } -interface IViewItem { - view: IView; - size: number; - container: HTMLElement; - disposable: IDisposable; - layout(): void; +type ViewItemSize = number | { cachedVisibleSize: number }; + +abstract class ViewItem { + + private _size: number; + set size(size: number) { + this._size = size; + } + + get size(): number { + return this._size; + } + + private _cachedVisibleSize: number | undefined = undefined; + get cachedVisibleSize(): number | undefined { return this._cachedVisibleSize; } + + get visible(): boolean { + return typeof this._cachedVisibleSize === 'undefined'; + } + + set visible(visible: boolean) { + if (visible === this.visible) { + return; + } + + if (visible) { + this.size = clamp(this._cachedVisibleSize!, this.viewMinimumSize, this.viewMaximumSize); + this._cachedVisibleSize = undefined; + } else { + this._cachedVisibleSize = this.size; + this.size = 0; + } + + dom.toggleClass(this.container, 'visible', visible); + + if (this.view.setVisible) { + this.view.setVisible(visible); + } + } + + get minimumSize(): number { return this.visible ? this.view.minimumSize : 0; } + get viewMinimumSize(): number { return this.view.minimumSize; } + + get maximumSize(): number { return this.visible ? this.view.maximumSize : 0; } + get viewMaximumSize(): number { return this.view.maximumSize; } + + get priority(): LayoutPriority | undefined { return this.view.priority; } + get snap(): boolean { return !!this.view.snap; } + + constructor( + protected container: HTMLElement, + private view: IView, + size: ViewItemSize, + private disposable: IDisposable + ) { + if (typeof size === 'number') { + this._size = size; + this._cachedVisibleSize = undefined; + } else { + this._size = 0; + this._cachedVisibleSize = size.cachedVisibleSize; + } + + dom.addClass(container, 'visible'); + } + + abstract layout(): void; + + layoutView(orientation: Orientation): void { + this.view.layout(this.size, orientation); + } + + dispose(): IView { + this.disposable.dispose(); + return this.view; + } +} + +class VerticalViewItem extends ViewItem { + + layout(): void { + this.container.style.height = `${this.size}px`; + this.layoutView(Orientation.VERTICAL); + } +} + +class HorizontalViewItem extends ViewItem { + + layout(): void { + this.container.style.width = `${this.size}px`; + this.layoutView(Orientation.HORIZONTAL); + } } interface ISashItem { @@ -70,6 +158,11 @@ interface ISashItem { disposable: IDisposable; } +interface ISashDragSnapState { + readonly index: number; + readonly limitDelta: number; +} + interface ISashDragState { index: number; start: number; @@ -78,6 +171,8 @@ interface ISashDragState { minDelta: number; maxDelta: number; alt: boolean; + snapBefore: ISashDragSnapState | undefined; + snapAfter: ISashDragSnapState | undefined; disposable: IDisposable; } @@ -88,11 +183,13 @@ enum State { export type DistributeSizing = { type: 'distribute' }; export type SplitSizing = { type: 'split', index: number }; -export type Sizing = DistributeSizing | SplitSizing; +export type InvisibleSizing = { type: 'invisible', cachedVisibleSize: number }; +export type Sizing = DistributeSizing | SplitSizing | InvisibleSizing; export namespace Sizing { export const Distribute: DistributeSizing = { type: 'distribute' }; export function Split(index: number): SplitSizing { return { type: 'split', index }; } + export function Invisible(cachedVisibleSize: number): InvisibleSizing { return { type: 'invisible', cachedVisibleSize }; } } export class SplitView extends Disposable { @@ -104,7 +201,7 @@ export class SplitView extends Disposable { private size = 0; private contentSize = 0; private proportions: undefined | number[] = undefined; - private viewItems: IViewItem[] = []; + private viewItems: ViewItem[] = []; private sashItems: ISashItem[] = []; private sashDragState: ISashDragState; private state: State = State.Idle; @@ -122,11 +219,11 @@ export class SplitView extends Disposable { } get minimumSize(): number { - return this.viewItems.reduce((r, item) => r + item.view.minimumSize, 0); + return this.viewItems.reduce((r, item) => r + item.minimumSize, 0); } get maximumSize(): number { - return this.length === 0 ? Number.POSITIVE_INFINITY : this.viewItems.reduce((r, item) => r + item.view.maximumSize, 0); + return this.length === 0 ? Number.POSITIVE_INFINITY : this.viewItems.reduce((r, item) => r + item.maximumSize, 0); } private _orthogonalStartSash: Sash | undefined; @@ -199,28 +296,24 @@ export class SplitView extends Disposable { const onChangeDisposable = view.onDidChange(size => this.onViewChange(item, size)); const containerDisposable = toDisposable(() => this.viewContainer.removeChild(container)); - const disposable = combinedDisposable([onChangeDisposable, containerDisposable]); + const disposable = combinedDisposable(onChangeDisposable, containerDisposable); - const layoutContainer = this.orientation === Orientation.VERTICAL - ? () => item.container.style.height = `${item.size}px` - : () => item.container.style.width = `${item.size}px`; - - const layout = () => { - layoutContainer(); - item.view.layout(item.size, this.orientation); - }; - - let viewSize: number; + let viewSize: ViewItemSize; if (typeof size === 'number') { viewSize = size; } else if (size.type === 'split') { viewSize = this.getViewSize(size.index) / 2; + } else if (size.type === 'invisible') { + viewSize = { cachedVisibleSize: size.cachedVisibleSize }; } else { viewSize = view.minimumSize; } - const item: IViewItem = { view, container, size: viewSize, layout, disposable }; + const item = this.orientation === Orientation.VERTICAL + ? new VerticalViewItem(container, view, viewSize, disposable) + : new HorizontalViewItem(container, view, viewSize, disposable); + this.viewItems.splice(index, 0, item); // Add sash @@ -234,8 +327,8 @@ export class SplitView extends Disposable { }); const sashEventMapper = this.orientation === Orientation.VERTICAL - ? (e: IBaseSashEvent) => ({ sash, start: e.startY, current: e.currentY, alt: e.altKey } as ISashEvent) - : (e: IBaseSashEvent) => ({ sash, start: e.startX, current: e.currentX, alt: e.altKey } as ISashEvent); + ? (e: IBaseSashEvent) => ({ sash, start: e.startY, current: e.currentY, alt: e.altKey }) + : (e: IBaseSashEvent) => ({ sash, start: e.startX, current: e.currentX, alt: e.altKey }); const onStart = Event.map(sash.onDidStart, sashEventMapper); const onStartDisposable = onStart(this.onSashStart, this); @@ -243,9 +336,26 @@ export class SplitView extends Disposable { const onChangeDisposable = onChange(this.onSashChange, this); const onEnd = Event.map(sash.onDidEnd, () => firstIndex(this.sashItems, item => item.sash === sash)); const onEndDisposable = onEnd(this.onSashEnd, this); - const onDidResetDisposable = sash.onDidReset(() => this._onDidSashReset.fire(firstIndex(this.sashItems, item => item.sash === sash))); - const disposable = combinedDisposable([onStartDisposable, onChangeDisposable, onEndDisposable, onDidResetDisposable, sash]); + const onDidResetDisposable = sash.onDidReset(() => { + const index = firstIndex(this.sashItems, item => item.sash === sash); + const upIndexes = range(index, -1); + const downIndexes = range(index + 1, this.viewItems.length); + const snapBeforeIndex = this.findFirstSnapIndex(upIndexes); + const snapAfterIndex = this.findFirstSnapIndex(downIndexes); + + if (typeof snapBeforeIndex === 'number' && !this.viewItems[snapBeforeIndex].visible) { + return; + } + + if (typeof snapAfterIndex === 'number' && !this.viewItems[snapAfterIndex].visible) { + return; + } + + this._onDidSashReset.fire(index); + }); + + const disposable = combinedDisposable(onStartDisposable, onChangeDisposable, onEndDisposable, onDidResetDisposable, sash); const sashItem: ISashItem = { sash, disposable }; this.sashItems.splice(index - 1, 0, sashItem); @@ -253,13 +363,13 @@ export class SplitView extends Disposable { container.appendChild(view.element); - let highPriorityIndex: number | undefined; + let highPriorityIndexes: number[] | undefined; if (typeof size !== 'number' && size.type === 'split') { - highPriorityIndex = size.index; + highPriorityIndexes = [size.index]; } - this.relayout(index, highPriorityIndex); + this.relayout([index], highPriorityIndexes); this.state = State.Idle; if (typeof size !== 'number' && size.type === 'distribute') { @@ -280,7 +390,7 @@ export class SplitView extends Disposable { // Remove view const viewItem = this.viewItems.splice(index, 1)[0]; - viewItem.disposable.dispose(); + const view = viewItem.dispose(); // Remove sash if (this.viewItems.length >= 1) { @@ -296,7 +406,7 @@ export class SplitView extends Disposable { this.distributeViewSizes(); } - return viewItem.view; + return view; } moveView(from: number, to: number): void { @@ -327,15 +437,34 @@ export class SplitView extends Disposable { this.addView(fromView, toSize, to); } - private relayout(lowPriorityIndex?: number, highPriorityIndex?: number): void { - const contentSize = this.viewItems.reduce((r, i) => r + i.size, 0); - const lowPriorityIndexes = typeof lowPriorityIndex === 'number' ? [lowPriorityIndex] : undefined; - const highPriorityIndexes = typeof highPriorityIndex === 'number' ? [highPriorityIndex] : undefined; + isViewVisible(index: number): boolean { + if (index < 0 || index >= this.viewItems.length) { + throw new Error('Index out of bounds'); + } - this.resize(this.viewItems.length - 1, this.size - contentSize, undefined, lowPriorityIndexes, highPriorityIndexes); - this.distributeEmptySpace(); + const viewItem = this.viewItems[index]; + return viewItem.visible; + } + + setViewVisible(index: number, visible: boolean): void { + if (index < 0 || index >= this.viewItems.length) { + throw new Error('Index out of bounds'); + } + + const viewItem = this.viewItems[index]; + viewItem.visible = visible; + + this.distributeEmptySpace(index); this.layoutViews(); - this.saveProportions(); + } + + getViewCachedVisibleSize(index: number): number | undefined { + if (index < 0 || index >= this.viewItems.length) { + throw new Error('Index out of bounds'); + } + + const viewItem = this.viewItems[index]; + return viewItem.cachedVisibleSize; } layout(size: number): void { @@ -344,14 +473,14 @@ export class SplitView extends Disposable { if (!this.proportions) { const indexes = range(this.viewItems.length); - const lowPriorityIndexes = indexes.filter(i => this.viewItems[i].view.priority === LayoutPriority.Low); - const highPriorityIndexes = indexes.filter(i => this.viewItems[i].view.priority === LayoutPriority.High); + const lowPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.Low); + const highPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.High); this.resize(this.viewItems.length - 1, size - previousSize, undefined, lowPriorityIndexes, highPriorityIndexes); } else { for (let i = 0; i < this.viewItems.length; i++) { const item = this.viewItems[i]; - item.size = clamp(Math.round(this.proportions[i] * size), item.view.minimumSize, item.view.maximumSize); + item.size = clamp(Math.round(this.proportions[i] * size), item.minimumSize, item.maximumSize); } } @@ -369,10 +498,10 @@ export class SplitView extends Disposable { const index = firstIndex(this.sashItems, item => item.sash === sash); // This way, we can press Alt while we resize a sash, macOS style! - const disposable = combinedDisposable([ + const disposable = combinedDisposable( domEvent(document.body, 'keydown')(e => resetSashDragState(this.sashDragState.current, e.altKey)), domEvent(document.body, 'keyup')(() => resetSashDragState(this.sashDragState.current, false)) - ]); + ); const resetSashDragState = (start: number, alt: boolean) => { const sizes = this.viewItems.map(i => i.size); @@ -391,35 +520,71 @@ export class SplitView extends Disposable { if (isLastSash) { const viewItem = this.viewItems[index]; - minDelta = (viewItem.view.minimumSize - viewItem.size) / 2; - maxDelta = (viewItem.view.maximumSize - viewItem.size) / 2; + minDelta = (viewItem.minimumSize - viewItem.size) / 2; + maxDelta = (viewItem.maximumSize - viewItem.size) / 2; } else { const viewItem = this.viewItems[index + 1]; - minDelta = (viewItem.size - viewItem.view.maximumSize) / 2; - maxDelta = (viewItem.size - viewItem.view.minimumSize) / 2; + minDelta = (viewItem.size - viewItem.maximumSize) / 2; + maxDelta = (viewItem.size - viewItem.minimumSize) / 2; } } - this.sashDragState = { start, current: start, index, sizes, minDelta, maxDelta, alt, disposable }; + let snapBefore: ISashDragSnapState | undefined; + let snapAfter: ISashDragSnapState | undefined; + + if (!alt) { + const upIndexes = range(index, -1); + const downIndexes = range(index + 1, this.viewItems.length); + const minDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].minimumSize - sizes[i]), 0); + const maxDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].viewMaximumSize - sizes[i]), 0); + const maxDeltaDown = downIndexes.length === 0 ? Number.POSITIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].minimumSize), 0); + const minDeltaDown = downIndexes.length === 0 ? Number.NEGATIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].viewMaximumSize), 0); + const minDelta = Math.max(minDeltaUp, minDeltaDown); + const maxDelta = Math.min(maxDeltaDown, maxDeltaUp); + const snapBeforeIndex = this.findFirstSnapIndex(upIndexes); + const snapAfterIndex = this.findFirstSnapIndex(downIndexes); + + if (typeof snapBeforeIndex === 'number') { + const viewItem = this.viewItems[snapBeforeIndex]; + const halfSize = Math.floor(viewItem.viewMinimumSize / 2); + + snapBefore = { + index: snapBeforeIndex, + limitDelta: viewItem.visible ? minDelta - halfSize : minDelta + halfSize + }; + } + + if (typeof snapAfterIndex === 'number') { + const viewItem = this.viewItems[snapAfterIndex]; + const halfSize = Math.floor(viewItem.viewMinimumSize / 2); + + snapAfter = { + index: snapAfterIndex, + limitDelta: viewItem.visible ? maxDelta + halfSize : maxDelta - halfSize + }; + } + } + + this.sashDragState = { start, current: start, index, sizes, minDelta, maxDelta, alt, snapBefore, snapAfter, disposable }; }; resetSashDragState(start, alt); } private onSashChange({ current }: ISashEvent): void { - const { index, start, sizes, alt, minDelta, maxDelta } = this.sashDragState; + const { index, start, sizes, alt, minDelta, maxDelta, snapBefore, snapAfter } = this.sashDragState; this.sashDragState.current = current; const delta = current - start; - const newDelta = this.resize(index, delta, sizes, undefined, undefined, minDelta, maxDelta); + const newDelta = this.resize(index, delta, sizes, undefined, undefined, minDelta, maxDelta, snapBefore, snapAfter); if (alt) { const isLastSash = index === this.sashItems.length - 1; const newSizes = this.viewItems.map(i => i.size); const viewItemIndex = isLastSash ? index : index + 1; const viewItem = this.viewItems[viewItemIndex]; - const newMinDelta = viewItem.size - viewItem.view.maximumSize; - const newMaxDelta = viewItem.size - viewItem.view.minimumSize; + const newMinDelta = viewItem.size - viewItem.maximumSize; + const newMaxDelta = viewItem.size - viewItem.minimumSize; const resizeIndex = isLastSash ? index - 1 : index + 1; this.resize(resizeIndex, -newDelta, newSizes, undefined, undefined, newMinDelta, newMaxDelta); @@ -435,7 +600,7 @@ export class SplitView extends Disposable { this.saveProportions(); } - private onViewChange(item: IViewItem, size: number | undefined): void { + private onViewChange(item: ViewItem, size: number | undefined): void { const index = this.viewItems.indexOf(item); if (index < 0 || index >= this.viewItems.length) { @@ -443,7 +608,7 @@ export class SplitView extends Disposable { } size = typeof size === 'number' ? size : item.size; - size = clamp(size, item.view.minimumSize, item.view.maximumSize); + size = clamp(size, item.minimumSize, item.maximumSize); if (this.inverseAltBehavior && index > 0) { // In this case, we want the view to grow or shrink both sides equally @@ -453,7 +618,7 @@ export class SplitView extends Disposable { this.layoutViews(); } else { item.size = size; - this.relayout(index, undefined); + this.relayout([index], undefined); } } @@ -468,42 +633,41 @@ export class SplitView extends Disposable { return; } + const indexes = range(this.viewItems.length).filter(i => i !== index); + const lowPriorityIndexes = [...indexes.filter(i => this.viewItems[i].priority === LayoutPriority.Low), index]; + const highPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.High); + const item = this.viewItems[index]; size = Math.round(size); - size = clamp(size, item.view.minimumSize, item.view.maximumSize); - let delta = size - item.size; + size = clamp(size, item.minimumSize, Math.min(item.maximumSize, this.size)); - if (delta !== 0 && index < this.viewItems.length - 1) { - const downIndexes = range(index + 1, this.viewItems.length); - const collapseDown = downIndexes.reduce((r, i) => r + (this.viewItems[i].size - this.viewItems[i].view.minimumSize), 0); - const expandDown = downIndexes.reduce((r, i) => r + (this.viewItems[i].view.maximumSize - this.viewItems[i].size), 0); - const deltaDown = clamp(delta, -expandDown, collapseDown); + item.size = size; + this.relayout(lowPriorityIndexes, highPriorityIndexes); + this.state = State.Idle; + } - this.resize(index, deltaDown); - delta -= deltaDown; + distributeViewSizes(): void { + const flexibleViewItems: ViewItem[] = []; + let flexibleSize = 0; + + for (const item of this.viewItems) { + if (item.maximumSize - item.minimumSize > 0) { + flexibleViewItems.push(item); + flexibleSize += item.size; + } } - 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); + const size = Math.floor(flexibleSize / flexibleViewItems.length); - this.resize(index - 1, deltaUp); + for (const item of flexibleViewItems) { + item.size = clamp(size, item.minimumSize, item.maximumSize); } - this.distributeEmptySpace(); - this.layoutViews(); - this.saveProportions(); - this.state = State.Idle; - } - - distributeViewSizes(): void { - const size = Math.floor(this.size / this.viewItems.length); + const indexes = range(this.viewItems.length); + const lowPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.Low); + const highPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.High); - for (let i = 0; i < this.viewItems.length - 1; i++) { - this.resizeView(i, size); - } + this.relayout(lowPriorityIndexes, highPriorityIndexes); } getViewSize(index: number): number { @@ -514,6 +678,15 @@ export class SplitView extends Disposable { return this.viewItems[index].size; } + private relayout(lowPriorityIndexes?: number[], highPriorityIndexes?: number[]): void { + const contentSize = this.viewItems.reduce((r, i) => r + i.size, 0); + + this.resize(this.viewItems.length - 1, this.size - contentSize, undefined, lowPriorityIndexes, highPriorityIndexes); + this.distributeEmptySpace(); + this.layoutViews(); + this.saveProportions(); + } + private resize( index: number, delta: number, @@ -521,7 +694,9 @@ export class SplitView extends Disposable { lowPriorityIndexes?: number[], highPriorityIndexes?: number[], overloadMinDelta: number = Number.NEGATIVE_INFINITY, - overloadMaxDelta: number = Number.POSITIVE_INFINITY + overloadMaxDelta: number = Number.POSITIVE_INFINITY, + snapBefore?: ISashDragSnapState, + snapAfter?: ISashDragSnapState ): number { if (index < 0 || index >= this.viewItems.length) { return 0; @@ -550,18 +725,38 @@ export class SplitView extends Disposable { const downItems = downIndexes.map(i => this.viewItems[i]); const downSizes = downIndexes.map(i => sizes[i]); - const minDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].view.minimumSize - sizes[i]), 0); - const maxDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].view.maximumSize - sizes[i]), 0); - const maxDeltaDown = downIndexes.length === 0 ? Number.POSITIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].view.minimumSize), 0); - const minDeltaDown = downIndexes.length === 0 ? Number.NEGATIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].view.maximumSize), 0); + const minDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].minimumSize - sizes[i]), 0); + const maxDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].maximumSize - sizes[i]), 0); + const maxDeltaDown = downIndexes.length === 0 ? Number.POSITIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].minimumSize), 0); + const minDeltaDown = downIndexes.length === 0 ? Number.NEGATIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].maximumSize), 0); const minDelta = Math.max(minDeltaUp, minDeltaDown, overloadMinDelta); const maxDelta = Math.min(maxDeltaDown, maxDeltaUp, overloadMaxDelta); + let snapped = false; + + if (snapBefore) { + const snapView = this.viewItems[snapBefore.index]; + const visible = delta >= snapBefore.limitDelta; + snapped = visible !== snapView.visible; + snapView.visible = visible; + } + + if (!snapped && snapAfter) { + const snapView = this.viewItems[snapAfter.index]; + const visible = delta < snapAfter.limitDelta; + snapped = visible !== snapView.visible; + snapView.visible = visible; + } + + if (snapped) { + return this.resize(index, delta, sizes, lowPriorityIndexes, highPriorityIndexes, overloadMinDelta, overloadMaxDelta); + } + delta = clamp(delta, minDelta, maxDelta); for (let i = 0, deltaUp = delta; i < upItems.length; i++) { const item = upItems[i]; - const size = clamp(upSizes[i] + deltaUp, item.view.minimumSize, item.view.maximumSize); + const size = clamp(upSizes[i] + deltaUp, item.minimumSize, item.maximumSize); const viewDelta = size - upSizes[i]; deltaUp -= viewDelta; @@ -570,7 +765,7 @@ export class SplitView extends Disposable { for (let i = 0, deltaDown = delta; i < downItems.length; i++) { const item = downItems[i]; - const size = clamp(downSizes[i] - deltaDown, item.view.minimumSize, item.view.maximumSize); + const size = clamp(downSizes[i] - deltaDown, item.minimumSize, item.maximumSize); const viewDelta = size - downSizes[i]; deltaDown += viewDelta; @@ -580,13 +775,29 @@ export class SplitView extends Disposable { return delta; } - private distributeEmptySpace(): void { - let contentSize = this.viewItems.reduce((r, i) => r + i.size, 0); + private distributeEmptySpace(lowPriorityIndex?: number): void { + const contentSize = this.viewItems.reduce((r, i) => r + i.size, 0); let emptyDelta = this.size - contentSize; - for (let i = this.viewItems.length - 1; emptyDelta !== 0 && i >= 0; i--) { - const item = this.viewItems[i]; - const size = clamp(item.size + emptyDelta, item.view.minimumSize, item.view.maximumSize); + const indexes = range(this.viewItems.length - 1, -1); + const lowPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.Low); + const highPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.High); + + for (const index of highPriorityIndexes) { + pushToStart(indexes, index); + } + + for (const index of lowPriorityIndexes) { + pushToEnd(indexes, index); + } + + if (typeof lowPriorityIndex === 'number') { + pushToEnd(indexes, lowPriorityIndex); + } + + for (let i = 0; emptyDelta !== 0 && i < indexes.length; i++) { + const item = this.viewItems[indexes[i]]; + const size = clamp(item.size + emptyDelta, item.minimumSize, item.maximumSize); const viewDelta = size - item.size; emptyDelta -= viewDelta; @@ -606,31 +817,43 @@ export class SplitView extends Disposable { // Update sashes enablement let previous = false; - const collapsesDown = this.viewItems.map(i => previous = (i.size - i.view.minimumSize > 0) || previous); + const collapsesDown = this.viewItems.map(i => previous = (i.size - i.minimumSize > 0) || previous); previous = false; - const expandsDown = this.viewItems.map(i => previous = (i.view.maximumSize - i.size > 0) || previous); + const expandsDown = this.viewItems.map(i => previous = (i.maximumSize - i.size > 0) || previous); const reverseViews = [...this.viewItems].reverse(); previous = false; - const collapsesUp = reverseViews.map(i => previous = (i.size - i.view.minimumSize > 0) || previous).reverse(); + const collapsesUp = reverseViews.map(i => previous = (i.size - i.minimumSize > 0) || previous).reverse(); previous = false; - const expandsUp = reverseViews.map(i => previous = (i.view.maximumSize - i.size > 0) || previous).reverse(); + const expandsUp = reverseViews.map(i => previous = (i.maximumSize - i.size > 0) || previous).reverse(); - this.sashItems.forEach((s, i) => { - const min = !(collapsesDown[i] && expandsUp[i + 1]); - const max = !(expandsDown[i] && collapsesUp[i + 1]); + this.sashItems.forEach(({ sash }, index) => { + const min = !(collapsesDown[index] && expandsUp[index + 1]); + const max = !(expandsDown[index] && collapsesUp[index + 1]); if (min && max) { - s.sash.state = SashState.Disabled; + const upIndexes = range(index, -1); + const downIndexes = range(index + 1, this.viewItems.length); + const snapBeforeIndex = this.findFirstSnapIndex(upIndexes); + const snapAfterIndex = this.findFirstSnapIndex(downIndexes); + + if (typeof snapBeforeIndex === 'number' && !this.viewItems[snapBeforeIndex].visible) { + sash.state = SashState.Minimum; + } else if (typeof snapAfterIndex === 'number' && !this.viewItems[snapAfterIndex].visible) { + sash.state = SashState.Maximum; + } else { + sash.state = SashState.Disabled; + } } else if (min && !max) { - s.sash.state = SashState.Minimum; + sash.state = SashState.Minimum; } else if (!min && max) { - s.sash.state = SashState.Maximum; + sash.state = SashState.Maximum; } else { - s.sash.state = SashState.Enabled; + sash.state = SashState.Enabled; } + // } }); } @@ -648,10 +871,40 @@ export class SplitView extends Disposable { return 0; } + private findFirstSnapIndex(indexes: number[]): number | undefined { + // visible views first + for (const index of indexes) { + const viewItem = this.viewItems[index]; + + if (!viewItem.visible) { + continue; + } + + if (viewItem.snap) { + return index; + } + } + + // then, hidden views + for (const index of indexes) { + const viewItem = this.viewItems[index]; + + if (viewItem.visible && viewItem.maximumSize - viewItem.minimumSize > 0) { + return undefined; + } + + if (!viewItem.visible && viewItem.snap) { + return index; + } + } + + return undefined; + } + dispose(): void { super.dispose(); - this.viewItems.forEach(i => i.disposable.dispose()); + this.viewItems.forEach(i => i.dispose()); this.viewItems = []; this.sashItems.forEach(i => i.disposable.dispose()); diff --git a/src/vs/base/browser/ui/splitview/tree-collapsed-dark.svg b/src/vs/base/browser/ui/splitview/tree-collapsed-dark.svg new file mode 100644 index 000000000..c2c2298dd --- /dev/null +++ b/src/vs/base/browser/ui/splitview/tree-collapsed-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/splitview/tree-collapsed-hc.svg b/src/vs/base/browser/ui/splitview/tree-collapsed-hc.svg new file mode 100644 index 000000000..3732cbc04 --- /dev/null +++ b/src/vs/base/browser/ui/splitview/tree-collapsed-hc.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/splitview/tree-collapsed-light.svg b/src/vs/base/browser/ui/splitview/tree-collapsed-light.svg new file mode 100644 index 000000000..1952ad63f --- /dev/null +++ b/src/vs/base/browser/ui/splitview/tree-collapsed-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/splitview/tree-expanded-dark.svg b/src/vs/base/browser/ui/splitview/tree-expanded-dark.svg new file mode 100644 index 000000000..5570923e1 --- /dev/null +++ b/src/vs/base/browser/ui/splitview/tree-expanded-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/splitview/tree-expanded-hc.svg b/src/vs/base/browser/ui/splitview/tree-expanded-hc.svg new file mode 100644 index 000000000..b37000933 --- /dev/null +++ b/src/vs/base/browser/ui/splitview/tree-expanded-hc.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/splitview/tree-expanded-light.svg b/src/vs/base/browser/ui/splitview/tree-expanded-light.svg new file mode 100644 index 000000000..939ebc8b9 --- /dev/null +++ b/src/vs/base/browser/ui/splitview/tree-expanded-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/toolbar/ellipsis-dark.svg b/src/vs/base/browser/ui/toolbar/ellipsis-dark.svg new file mode 100644 index 000000000..2c52e359f --- /dev/null +++ b/src/vs/base/browser/ui/toolbar/ellipsis-dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/vs/base/browser/ui/toolbar/ellipsis-hc.svg b/src/vs/base/browser/ui/toolbar/ellipsis-hc.svg new file mode 100644 index 000000000..3d7068f6b --- /dev/null +++ b/src/vs/base/browser/ui/toolbar/ellipsis-hc.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/vs/base/browser/ui/toolbar/ellipsis-inverse.svg b/src/vs/base/browser/ui/toolbar/ellipsis-inverse.svg deleted file mode 100644 index e3337557a..000000000 --- a/src/vs/base/browser/ui/toolbar/ellipsis-inverse.svg +++ /dev/null @@ -1 +0,0 @@ -Ellipsis_bold_16x \ No newline at end of file diff --git a/src/vs/base/browser/ui/toolbar/ellipsis-light.svg b/src/vs/base/browser/ui/toolbar/ellipsis-light.svg new file mode 100644 index 000000000..883d2722c --- /dev/null +++ b/src/vs/base/browser/ui/toolbar/ellipsis-light.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/vs/base/browser/ui/toolbar/ellipsis.svg b/src/vs/base/browser/ui/toolbar/ellipsis.svg deleted file mode 100644 index e3f856233..000000000 --- a/src/vs/base/browser/ui/toolbar/ellipsis.svg +++ /dev/null @@ -1 +0,0 @@ -Ellipsis_bold_16x \ No newline at end of file diff --git a/src/vs/base/browser/ui/toolbar/toolbar.css b/src/vs/base/browser/ui/toolbar/toolbar.css index 6738aeb68..476697122 100644 --- a/src/vs/base/browser/ui/toolbar/toolbar.css +++ b/src/vs/base/browser/ui/toolbar/toolbar.css @@ -9,10 +9,13 @@ } .vs .monaco-toolbar .action-label.toolbar-toggle-more { - background-image: url('ellipsis.svg'); + background-image: url('ellipsis-light.svg'); } -.hc-black .monaco-toolbar .action-label.toolbar-toggle-more, .vs-dark .monaco-toolbar .action-label.toolbar-toggle-more { - background-image: url('ellipsis-inverse.svg'); + background-image: url('ellipsis-dark.svg'); +} + +.hc-black .monaco-toolbar .action-label.toolbar-toggle-more { + background-image: url('ellipsis-hc.svg'); } \ No newline at end of file diff --git a/src/vs/base/browser/ui/toolbar/toolbar.ts b/src/vs/base/browser/ui/toolbar/toolbar.ts index 1c144b240..4aa201e1a 100644 --- a/src/vs/base/browser/ui/toolbar/toolbar.ts +++ b/src/vs/base/browser/ui/toolbar/toolbar.ts @@ -6,10 +6,10 @@ import 'vs/css!./toolbar'; import * as nls from 'vs/nls'; import { Action, IActionRunner, IAction } from 'vs/base/common/actions'; -import { ActionBar, ActionsOrientation, IActionItemProvider } from 'vs/base/browser/ui/actionbar/actionbar'; -import { IContextMenuProvider, DropdownMenuActionItem } from 'vs/base/browser/ui/dropdown/dropdown'; +import { ActionBar, ActionsOrientation, IActionViewItemProvider } from 'vs/base/browser/ui/actionbar/actionbar'; +import { IContextMenuProvider, DropdownMenuActionViewItem } from 'vs/base/browser/ui/dropdown/dropdown'; import { ResolvedKeybinding } from 'vs/base/common/keyCodes'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview'; import { withNullAsUndefined } from 'vs/base/common/types'; @@ -17,7 +17,7 @@ export const CONTEXT = 'context.toolbar'; export interface IToolBarOptions { orientation?: ActionsOrientation; - actionItemProvider?: IActionItemProvider; + actionViewItemProvider?: IActionViewItemProvider; ariaLabel?: string; getKeyBinding?: (action: IAction) => ResolvedKeybinding | undefined; actionRunner?: IActionRunner; @@ -32,7 +32,7 @@ export class ToolBar extends Disposable { private options: IToolBarOptions; private actionBar: ActionBar; private toggleMenuAction: ToggleMenuAction; - private toggleMenuActionItem?: DropdownMenuActionItem; + private toggleMenuActionViewItem = this._register(new MutableDisposable()); private hasSecondaryActions: boolean; private lookupKeybindings: boolean; @@ -42,7 +42,7 @@ export class ToolBar extends Disposable { this.options = options; this.lookupKeybindings = typeof this.options.getKeyBinding === 'function'; - this.toggleMenuAction = this._register(new ToggleMenuAction(() => this.toggleMenuActionItem && this.toggleMenuActionItem.show(), options.toggleMenuTitle)); + this.toggleMenuAction = this._register(new ToggleMenuAction(() => this.toggleMenuActionViewItem.value && this.toggleMenuActionViewItem.value.show(), options.toggleMenuTitle)); let element = document.createElement('div'); element.className = 'monaco-toolbar'; @@ -52,33 +52,28 @@ export class ToolBar extends Disposable { orientation: options.orientation, ariaLabel: options.ariaLabel, actionRunner: options.actionRunner, - actionItemProvider: (action: Action) => { + actionViewItemProvider: (action: Action) => { // Return special action item for the toggle menu action if (action.id === ToggleMenuAction.ID) { - // Dispose old - if (this.toggleMenuActionItem) { - this.toggleMenuActionItem.dispose(); - } - // Create new - this.toggleMenuActionItem = new DropdownMenuActionItem( + this.toggleMenuActionViewItem.value = new DropdownMenuActionViewItem( action, (action).menuActions, contextMenuProvider, - this.options.actionItemProvider, + this.options.actionViewItemProvider, this.actionRunner, this.options.getKeyBinding, 'toolbar-toggle-more', this.options.anchorAlignmentProvider ); - this.toggleMenuActionItem!.setActionContext(this.actionBar.context); + this.toggleMenuActionViewItem.value.setActionContext(this.actionBar.context); - return this.toggleMenuActionItem; + return this.toggleMenuActionViewItem.value; } - return options.actionItemProvider ? options.actionItemProvider(action) : undefined; + return options.actionViewItemProvider ? options.actionViewItemProvider(action) : undefined; } })); } @@ -93,8 +88,8 @@ export class ToolBar extends Disposable { set context(context: any) { this.actionBar.context = context; - if (this.toggleMenuActionItem) { - this.toggleMenuActionItem.setActionContext(context); + if (this.toggleMenuActionViewItem.value) { + this.toggleMenuActionViewItem.value.setActionContext(context); } } @@ -114,7 +109,7 @@ export class ToolBar extends Disposable { this.actionBar.setAriaLabel(label); } - setActions(primaryActions: IAction[], secondaryActions?: IAction[]): () => void { + setActions(primaryActions: ReadonlyArray, secondaryActions?: ReadonlyArray): () => void { return () => { let primaryActionsToSet = primaryActions ? primaryActions.slice(0) : []; @@ -154,22 +149,13 @@ export class ToolBar extends Disposable { } }; } - - dispose(): void { - if (this.toggleMenuActionItem) { - this.toggleMenuActionItem.dispose(); - this.toggleMenuActionItem = undefined; - } - - super.dispose(); - } } class ToggleMenuAction extends Action { static readonly ID = 'toolbar.toggle.more'; - private _menuActions: IAction[]; + private _menuActions: ReadonlyArray; private toggleDropdownMenu: () => void; constructor(toggleDropdownMenu: () => void, title?: string) { @@ -185,11 +171,11 @@ class ToggleMenuAction extends Action { return Promise.resolve(true); } - get menuActions() { + get menuActions(): ReadonlyArray { return this._menuActions; } - set menuActions(actions: IAction[]) { + set menuActions(actions: ReadonlyArray) { this._menuActions = actions; } } \ No newline at end of file diff --git a/src/vs/base/browser/ui/tree/abstractTree.ts b/src/vs/base/browser/ui/tree/abstractTree.ts index dc8c82f4d..7624d5b1f 100644 --- a/src/vs/base/browser/ui/tree/abstractTree.ts +++ b/src/vs/base/browser/ui/tree/abstractTree.ts @@ -4,14 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/tree'; -import { IDisposable, dispose, Disposable, toDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, Disposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IListOptions, List, IListStyles, mightProducePrintableCharacter, MouseController } from 'vs/base/browser/ui/list/listWidget'; import { IListVirtualDelegate, IListRenderer, IListMouseEvent, IListEvent, IListContextMenuEvent, IListDragAndDrop, IListDragOverReaction, IKeyboardNavigationLabelProvider, IIdentityProvider } from 'vs/base/browser/ui/list/list'; -import { append, $, toggleClass, getDomNodePagePosition, removeClass, addClass, hasClass } from 'vs/base/browser/dom'; +import { append, $, toggleClass, getDomNodePagePosition, removeClass, addClass, hasClass, hasParentWithClass, createStyleSheet, clearNode } from 'vs/base/browser/dom'; import { Event, Relay, Emitter, EventBufferer } from 'vs/base/common/event'; import { StandardKeyboardEvent, IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { KeyCode } from 'vs/base/common/keyCodes'; -import { ITreeModel, ITreeNode, ITreeRenderer, ITreeEvent, ITreeMouseEvent, ITreeContextMenuEvent, ITreeFilter, ITreeNavigator, ICollapseStateChangeEvent, ITreeDragAndDrop, TreeDragOverBubble, TreeVisibility, TreeFilterResult, ITreeModelSpliceEvent } from 'vs/base/browser/ui/tree/tree'; +import { ITreeModel, ITreeNode, ITreeRenderer, ITreeEvent, ITreeMouseEvent, ITreeContextMenuEvent, ITreeFilter, ITreeNavigator, ICollapseStateChangeEvent, ITreeDragAndDrop, TreeDragOverBubble, TreeVisibility, TreeFilterResult, ITreeModelSpliceEvent, TreeMouseEventTarget } from 'vs/base/browser/ui/tree/tree'; import { ISpliceable } from 'vs/base/common/sequence'; import { IDragAndDropData, StaticDND, DragAndDropData } from 'vs/base/browser/dnd'; import { range, equals, distinctES6 } from 'vs/base/common/arrays'; @@ -25,6 +25,7 @@ import { isMacintosh } from 'vs/base/common/platform'; import { values } from 'vs/base/common/map'; import { clamp } from 'vs/base/common/numbers'; import { ScrollEvent } from 'vs/base/common/scrollable'; +import { SetMap } from 'vs/base/common/collections'; function asTreeDragAndDropData(data: IDragAndDropData): IDragAndDropData { if (data instanceof ElementsDragAndDropData) { @@ -152,7 +153,7 @@ function asListOptions(modelProvider: () => ITreeModel implements IListV interface ITreeListTemplateData { readonly container: HTMLElement; + readonly indent: HTMLElement; readonly twistie: HTMLElement; + indentGuidesDisposable: IDisposable; readonly templateData: T; } +export enum RenderIndentGuides { + None = 'none', + OnHover = 'onHover', + Always = 'always' +} + interface ITreeRendererOptions { readonly indent?: number; + readonly renderIndentGuides?: RenderIndentGuides; +} + +interface IRenderData { + templateData: ITreeListTemplateData; + height: number; +} + +interface Collection { + readonly elements: T[]; + readonly onDidChange: Event; +} + +class EventCollection implements Collection { + + private disposables = new DisposableStore(); + + get elements(): T[] { + return this._elements; + } + + constructor(readonly onDidChange: Event, private _elements: T[] = []) { + onDidChange(e => this._elements = e, null, this.disposables); + } + + dispose() { + this.disposables.dispose(); + } } class TreeRenderer implements IListRenderer, ITreeListTemplateData> { @@ -202,13 +239,20 @@ class TreeRenderer implements IListRenderer>(); - private renderedNodes = new Map, ITreeListTemplateData>(); + private renderedNodes = new Map, IRenderData>(); private indent: number = TreeRenderer.DefaultIndent; + + private _renderIndentGuides: RenderIndentGuides = RenderIndentGuides.None; + private renderedIndentGuides = new SetMap, HTMLDivElement>(); + private activeParentNodes = new Set>(); + private indentGuidesDisposable: IDisposable = Disposable.None; + private disposables: IDisposable[] = []; constructor( private renderer: ITreeRenderer, onDidChangeCollapseState: Event>, + private activeNodes: Collection>, options: ITreeRendererOptions = {} ) { this.templateId = renderer.templateId; @@ -226,39 +270,62 @@ class TreeRenderer implements IListRenderer { - templateData.twistie.style.marginLeft = `${node.depth * this.indent}px`; - }); + if (typeof options.renderIndentGuides !== 'undefined') { + const renderIndentGuides = options.renderIndentGuides; + + if (renderIndentGuides !== this._renderIndentGuides) { + this._renderIndentGuides = renderIndentGuides; + + if (renderIndentGuides) { + const disposables = new DisposableStore(); + this.activeNodes.onDidChange(this._onDidChangeActiveNodes, this, disposables); + this.indentGuidesDisposable = disposables; + + this._onDidChangeActiveNodes(this.activeNodes.elements); + } else { + this.indentGuidesDisposable.dispose(); + } + } + } } renderTemplate(container: HTMLElement): ITreeListTemplateData { const el = append(container, $('.monaco-tl-row')); + const indent = append(el, $('.monaco-tl-indent')); const twistie = append(el, $('.monaco-tl-twistie')); const contents = append(el, $('.monaco-tl-contents')); const templateData = this.renderer.renderTemplate(contents); - return { container, twistie, templateData }; + return { container, indent, twistie, indentGuidesDisposable: Disposable.None, templateData }; } - renderElement(node: ITreeNode, index: number, templateData: ITreeListTemplateData, dynamicHeightProbing?: boolean): void { - if (!dynamicHeightProbing) { - this.renderedNodes.set(node, templateData); + renderElement(node: ITreeNode, index: number, templateData: ITreeListTemplateData, height: number | undefined): void { + if (typeof height === 'number') { + this.renderedNodes.set(node, { templateData, height }); this.renderedElements.set(node.element, node); } const indent = TreeRenderer.DefaultIndent + (node.depth - 1) * this.indent; templateData.twistie.style.marginLeft = `${indent}px`; - this.update(node, templateData); + templateData.indent.style.width = `${indent + this.indent - 16}px`; - this.renderer.renderElement(node, index, templateData.templateData, dynamicHeightProbing); + this.renderTwistie(node, templateData); + + if (typeof height === 'number') { + this.renderIndentGuides(node, templateData); + } + + this.renderer.renderElement(node, index, templateData.templateData, height); } - disposeElement(node: ITreeNode, index: number, templateData: ITreeListTemplateData, dynamicHeightProbing?: boolean): void { + disposeElement(node: ITreeNode, index: number, templateData: ITreeListTemplateData, height: number | undefined): void { + templateData.indentGuidesDisposable.dispose(); + if (this.renderer.disposeElement) { - this.renderer.disposeElement(node, index, templateData.templateData, dynamicHeightProbing); + this.renderer.disposeElement(node, index, templateData.templateData, height); } - if (!dynamicHeightProbing) { + if (typeof height === 'number') { this.renderedNodes.delete(node); this.renderedElements.delete(node.element); } @@ -279,16 +346,17 @@ class TreeRenderer implements IListRenderer): void { - const templateData = this.renderedNodes.get(node); + const data = this.renderedNodes.get(node); - if (!templateData) { + if (!data) { return; } - this.update(node, templateData); + this.renderTwistie(node, data.templateData); + this.renderIndentGuides(node, data.templateData); } - private update(node: ITreeNode, templateData: ITreeListTemplateData) { + private renderTwistie(node: ITreeNode, templateData: ITreeListTemplateData) { if (this.renderer.renderTwistie) { this.renderer.renderTwistie(node.element, templateData.twistie); } @@ -303,9 +371,72 @@ class TreeRenderer implements IListRenderer, templateData: ITreeListTemplateData): void { + clearNode(templateData.indent); + templateData.indentGuidesDisposable.dispose(); + + if (this._renderIndentGuides === RenderIndentGuides.None) { + return; + } + + const disposableStore = new DisposableStore(); + let node = target; + + while (node.parent && node.parent.parent) { + const parent = node.parent; + const guide = $('.indent-guide', { style: `width: ${this.indent}px` }); + + if (this.activeParentNodes.has(parent)) { + addClass(guide, 'active'); + } + + if (templateData.indent.childElementCount === 0) { + templateData.indent.appendChild(guide); + } else { + templateData.indent.insertBefore(guide, templateData.indent.firstElementChild); + } + + this.renderedIndentGuides.add(parent, guide); + disposableStore.add(toDisposable(() => this.renderedIndentGuides.delete(parent, guide))); + + node = parent; + } + + templateData.indentGuidesDisposable = disposableStore; + } + + private _onDidChangeActiveNodes(nodes: ITreeNode[]): void { + if (this._renderIndentGuides === RenderIndentGuides.None) { + return; + } + + const set = new Set>(); + + nodes.forEach(node => { + if (node.parent) { + set.add(node.parent); + } + }); + + this.activeParentNodes.forEach(node => { + if (!set.has(node)) { + this.renderedIndentGuides.forEach(node, line => removeClass(line, 'active')); + } + }); + + set.forEach(node => { + if (!this.activeParentNodes.has(node)) { + this.renderedIndentGuides.forEach(node, line => addClass(line, 'active')); + } + }); + + this.activeParentNodes = set; + } + dispose(): void { this.renderedNodes.clear(); this.renderedElements.clear(); + this.indentGuidesDisposable.dispose(); this.disposables = dispose(this.disposables); } } @@ -722,9 +853,18 @@ function asTreeEvent(event: IListEvent>): ITreeEvent { } function asTreeMouseEvent(event: IListMouseEvent>): ITreeMouseEvent { + let target: TreeMouseEventTarget = TreeMouseEventTarget.Unknown; + + if (hasParentWithClass(event.browserEvent.target as HTMLElement, 'monaco-tl-twistie', 'monaco-tl-row')) { + target = TreeMouseEventTarget.Twistie; + } else if (hasParentWithClass(event.browserEvent.target as HTMLElement, 'monaco-tl-contents', 'monaco-tl-row')) { + target = TreeMouseEventTarget.Element; + } + return { browserEvent: event.browserEvent, - element: event.element ? event.element.element : null + element: event.element ? event.element.element : null, + target }; } @@ -789,12 +929,18 @@ class Trait { return; } + this._set(nodes, false, browserEvent); + } + + private _set(nodes: ITreeNode[], silent: boolean, browserEvent?: UIEvent): void { this.nodes = [...nodes]; this.elements = undefined; this._nodeSet = undefined; - const that = this; - this._onDidChange.fire({ get elements() { return that.get(); }, browserEvent }); + if (!silent) { + const that = this; + this._onDidChange.fire({ get elements() { return that.get(); }, browserEvent }); + } } get(): T[] { @@ -805,6 +951,10 @@ class Trait { return [...this.elements]; } + getNodes(): readonly ITreeNode[] { + return this.nodes; + } + has(node: ITreeNode): boolean { return this.nodeSet.has(node); } @@ -827,6 +977,7 @@ class Trait { insertedNodes.forEach(node => dfs(node, insertedNodesVisitor)); const nodes: ITreeNode[] = []; + let silent = true; for (const node of this.nodes) { const id = this.identityProvider.getId(node.element).toString(); @@ -839,11 +990,13 @@ class Trait { if (insertedNode) { nodes.push(insertedNode); + } else { + silent = false; } } } - this.set(nodes); + this._set(nodes, silent); } private createNodeSet(): Set> { @@ -990,6 +1143,7 @@ export abstract class AbstractTree implements IDisposable private eventBufferer = new EventBufferer(); private typeFilterController?: TypeFilterController; private focusNavigationFilter: ((node: ITreeNode) => boolean) | undefined; + private styleElement: HTMLStyleElement; protected disposables: IDisposable[] = []; get onDidScroll(): Event { return this.view.onDidScroll; } @@ -1018,7 +1172,6 @@ export abstract class AbstractTree implements IDisposable get filterOnType(): boolean { return !!this._options.filterOnType; } get onDidChangeTypeFilterPattern(): Event { return this.typeFilterController ? this.typeFilterController.onDidChangePattern : Event.None; } - // Options TODO@joao expose options only, not Optional<> get openOnSingleClick(): boolean { return typeof this._options.openOnSingleClick === 'undefined' ? true : this._options.openOnSingleClick; } get expandOnlyOnTwistieClick(): boolean | ((e: T) => boolean) { return typeof this._options.expandOnlyOnTwistieClick === 'undefined' ? false : this._options.expandOnlyOnTwistieClick; } @@ -1030,13 +1183,17 @@ export abstract class AbstractTree implements IDisposable constructor( container: HTMLElement, delegate: IListVirtualDelegate, - renderers: ITreeRenderer[], + renderers: ITreeRenderer[], private _options: IAbstractTreeOptions = {} ) { const treeDelegate = new ComposedTreeDelegate>(delegate); const onDidChangeCollapseStateRelay = new Relay>(); - this.renderers = renderers.map(r => new TreeRenderer(r, onDidChangeCollapseStateRelay.event, _options)); + const onDidChangeActiveNodes = new Relay[]>(); + const activeNodes = new EventCollection(onDidChangeActiveNodes.event); + this.disposables.push(activeNodes); + + this.renderers = renderers.map(r => new TreeRenderer(r, onDidChangeCollapseStateRelay.event, activeNodes, _options)); this.disposables.push(...this.renderers); let filter: TypeFilter | undefined; @@ -1059,6 +1216,8 @@ export abstract class AbstractTree implements IDisposable this.selection.onDidModelSplice(e); }, null, this.disposables); + onDidChangeActiveNodes.input = Event.map(Event.any(this.focus.onDidChange, this.selection.onDidChange, this.model.onDidSplice), () => [...this.focus.getNodes(), ...this.selection.getNodes()]); + if (_options.keyboardSupport !== false) { const onKeyDown = Event.chain(this.view.onKeyDown) .filter(e => !isInputElement(e.target as HTMLElement)) @@ -1074,6 +1233,9 @@ export abstract class AbstractTree implements IDisposable this.focusNavigationFilter = node => this.typeFilterController!.shouldAllowFocus(node); this.disposables.push(this.typeFilterController!); } + + this.styleElement = createStyleSheet(this.view.getHTMLElement()); + toggleClass(this.getHTMLElement(), 'always', this._options.renderIndentGuides === RenderIndentGuides.Always); } updateOptions(optionsUpdate: IAbstractTreeOptionsUpdate = {}): void { @@ -1093,6 +1255,8 @@ export abstract class AbstractTree implements IDisposable } this._onDidUpdateOptions.fire(this._options); + + toggleClass(this.getHTMLElement(), 'always', this._options.renderIndentGuides === RenderIndentGuides.Always); } get options(): IAbstractTreeOptions { @@ -1174,6 +1338,19 @@ export abstract class AbstractTree implements IDisposable } style(styles: IListStyles): void { + const suffix = `.${this.view.domId}`; + const content: string[] = []; + + if (styles.treeIndentGuidesStroke) { + content.push(`.monaco-list${suffix}:hover .monaco-tl-indent > .indent-guide, .monaco-list${suffix}.always .monaco-tl-indent > .indent-guide { border-color: ${styles.treeIndentGuidesStroke.transparent(0.4)}; }`); + content.push(`.monaco-list${suffix} .monaco-tl-indent > .indent-guide.active { border-color: ${styles.treeIndentGuidesStroke}; }`); + } + + const newStyles = content.join('\n'); + if (newStyles !== this.styleElement.innerHTML) { + this.styleElement.innerHTML = newStyles; + } + this.view.style(styles); } diff --git a/src/vs/base/browser/ui/tree/asyncDataTree.ts b/src/vs/base/browser/ui/tree/asyncDataTree.ts index 050d3f49a..86eaeb316 100644 --- a/src/vs/base/browser/ui/tree/asyncDataTree.ts +++ b/src/vs/base/browser/ui/tree/asyncDataTree.ts @@ -28,6 +28,7 @@ interface IAsyncDataTreeNode { hasChildren: boolean; stale: boolean; slow: boolean; + collapsedByDefault: boolean | undefined; } interface IAsyncDataTreeNodeRequiredProps extends Partial> { @@ -42,7 +43,8 @@ function createAsyncDataTreeNode(props: IAsyncDataTreeNodeRequiredPro children: [], loading: false, stale: true, - slow: false + slow: false, + collapsedByDefault: undefined }; } @@ -98,8 +100,8 @@ class DataTreeRenderer implements ITreeRe return { templateData }; } - renderElement(node: ITreeNode, TFilterData>, index: number, templateData: IDataTreeListTemplateData, dynamicHeightProbing?: boolean): void { - this.renderer.renderElement(new AsyncDataTreeNodeWrapper(node), index, templateData.templateData, dynamicHeightProbing); + renderElement(node: ITreeNode, TFilterData>, index: number, templateData: IDataTreeListTemplateData, height: number | undefined): void { + this.renderer.renderElement(new AsyncDataTreeNodeWrapper(node), index, templateData.templateData, height); } renderTwistie(element: IAsyncDataTreeNode, twistieElement: HTMLElement): boolean { @@ -107,9 +109,9 @@ class DataTreeRenderer implements ITreeRe return false; } - disposeElement(node: ITreeNode, TFilterData>, index: number, templateData: IDataTreeListTemplateData, dynamicHeightProbing?: boolean): void { + disposeElement(node: ITreeNode, TFilterData>, index: number, templateData: IDataTreeListTemplateData, height: number | undefined): void { if (this.renderer.disposeElement) { - this.renderer.disposeElement(new AsyncDataTreeNodeWrapper(node), index, templateData.templateData, dynamicHeightProbing); + this.renderer.disposeElement(new AsyncDataTreeNodeWrapper(node), index, templateData.templateData, height); } } @@ -133,7 +135,8 @@ function asTreeEvent(e: ITreeEvent>): I function asTreeMouseEvent(e: ITreeMouseEvent>): ITreeMouseEvent { return { browserEvent: e.browserEvent, - element: e.element && e.element.element as T + element: e.element && e.element.element as T, + target: e.target }; } @@ -224,6 +227,7 @@ function asObjectTreeOptions(options?: IAsyncDataTreeOpt } }, keyboardNavigationLabelProvider: options.keyboardNavigationLabelProvider && { + ...options.keyboardNavigationLabelProvider, getKeyboardNavigationLabel(e) { return options.keyboardNavigationLabelProvider!.getKeyboardNavigationLabel(e.element as T); } @@ -234,17 +238,21 @@ function asObjectTreeOptions(options?: IAsyncDataTreeOpt e => (options.expandOnlyOnTwistieClick as ((e: T) => boolean))(e.element as T) ) ), - ariaSetProvider: undefined + ariaProvider: undefined }; } function asTreeElement(node: IAsyncDataTreeNode, viewStateContext?: IAsyncDataTreeViewStateContext): ITreeElement> { let collapsed: boolean | undefined; - if (viewStateContext && viewStateContext.viewState.expanded && node.id) { - collapsed = viewStateContext.viewState.expanded.indexOf(node.id) === -1; + if (viewStateContext && viewStateContext.viewState.expanded && node.id && viewStateContext.viewState.expanded.indexOf(node.id) > -1) { + collapsed = false; + } else { + collapsed = node.collapsedByDefault; } + node.collapsedByDefault = undefined; + return { element: node, children: node.hasChildren ? Iterator.map(Iterator.fromArray(node.children), child => asTreeElement(child, viewStateContext)) : [], @@ -255,10 +263,11 @@ function asTreeElement(node: IAsyncDataTreeNode, viewState export interface IAsyncDataTreeOptionsUpdate extends IAbstractTreeOptionsUpdate { } -export interface IAsyncDataTreeOptions extends IAsyncDataTreeOptionsUpdate, IAbstractTreeOptions { - identityProvider?: IIdentityProvider; - sorter?: ITreeSorter; - autoExpandSingleChildren?: boolean; +export interface IAsyncDataTreeOptions extends IAsyncDataTreeOptionsUpdate, Pick, Exclude, 'collapseByDefault'>> { + readonly collapseByDefault?: { (e: T): boolean; }; + readonly identityProvider?: IIdentityProvider; + readonly sorter?: ITreeSorter; + readonly autoExpandSingleChildren?: boolean; } export interface IAsyncDataTreeViewState { @@ -285,6 +294,7 @@ export class AsyncDataTree implements IDisposable private readonly root: IAsyncDataTreeNode; private readonly nodes = new Map>(); private readonly sorter?: ITreeSorter; + private readonly collapseByDefault?: { (e: T): boolean; }; private readonly subTreeRefreshPromises = new Map, Promise>(); private readonly refreshPromises = new Map, CancelablePromise>(); @@ -310,23 +320,34 @@ export class AsyncDataTree implements IDisposable get onDidFocus(): Event { return this.tree.onDidFocus; } get onDidBlur(): Event { return this.tree.onDidBlur; } + get onDidChangeCollapseState(): Event | null, TFilterData>> { return this.tree.onDidChangeCollapseState; } + get onDidUpdateOptions(): Event { return this.tree.onDidUpdateOptions; } get filterOnType(): boolean { return this.tree.filterOnType; } get openOnSingleClick(): boolean { return this.tree.openOnSingleClick; } + get expandOnlyOnTwistieClick(): boolean | ((e: T) => boolean) { + if (typeof this.tree.expandOnlyOnTwistieClick === 'boolean') { + return this.tree.expandOnlyOnTwistieClick; + } + + const fn = this.tree.expandOnlyOnTwistieClick; + return element => fn(this.nodes.get((element === this.root.element ? null : element) as T) || null); + } get onDidDispose(): Event { return this.tree.onDidDispose; } constructor( container: HTMLElement, delegate: IListVirtualDelegate, - renderers: ITreeRenderer[], + renderers: ITreeRenderer[], private dataSource: IAsyncDataSource, options: IAsyncDataTreeOptions = {} ) { this.identityProvider = options.identityProvider; this.autoExpandSingleChildren = typeof options.autoExpandSingleChildren === 'undefined' ? false : options.autoExpandSingleChildren; this.sorter = options.sorter; + this.collapseByDefault = options.collapseByDefault; const objectTreeDelegate = new ComposedTreeDelegate>(delegate); const objectTreeRenderers = renderers.map(r => new DataTreeRenderer(r, this._onDidChangeNodeSlowState.event)); @@ -581,9 +602,9 @@ export class AsyncDataTree implements IDisposable return nodes.map(n => n!.element as T); } - open(elements: T[]): void { + open(elements: T[], browserEvent?: UIEvent): void { const nodes = elements.map(e => this.getDataNode(e)); - this.tree.open(nodes); + this.tree.open(nodes, browserEvent); } reveal(element: T, relativeTop?: number): void { @@ -762,12 +783,17 @@ export class AsyncDataTree implements IDisposable const childrenToRefresh: IAsyncDataTreeNode[] = []; const children = childrenElements.map>(element => { + const hasChildren = !!this.dataSource.hasChildren(element); + if (!this.identityProvider) { - return createAsyncDataTreeNode({ - element, - parent: node, - hasChildren: !!this.dataSource.hasChildren(element) - }); + const asyncDataTreeNode = createAsyncDataTreeNode({ element, parent: node, hasChildren }); + + if (hasChildren && this.collapseByDefault && !this.collapseByDefault(element)) { + asyncDataTreeNode.collapsedByDefault = false; + childrenToRefresh.push(asyncDataTreeNode); + } + + return asyncDataTreeNode; } const id = this.identityProvider.getId(element).toString(); @@ -781,7 +807,7 @@ export class AsyncDataTree implements IDisposable this.nodes.set(element, asyncDataTreeNode); asyncDataTreeNode.element = element; - asyncDataTreeNode.hasChildren = !!this.dataSource.hasChildren(element); + asyncDataTreeNode.hasChildren = hasChildren; if (recursive) { if (childNode.collapsed) { @@ -789,17 +815,15 @@ export class AsyncDataTree implements IDisposable } else { childrenToRefresh.push(asyncDataTreeNode); } + } else if (hasChildren && this.collapseByDefault && !this.collapseByDefault(element)) { + asyncDataTreeNode.collapsedByDefault = false; + childrenToRefresh.push(asyncDataTreeNode); } return asyncDataTreeNode; } - const childAsyncDataTreeNode = createAsyncDataTreeNode({ - element, - parent: node, - id, - hasChildren: !!this.dataSource.hasChildren(element) - }); + const childAsyncDataTreeNode = createAsyncDataTreeNode({ element, parent: node, id, hasChildren }); if (viewStateContext && viewStateContext.viewState.focus && viewStateContext.viewState.focus.indexOf(id) > -1) { viewStateContext.focus.push(childAsyncDataTreeNode); @@ -811,6 +835,9 @@ export class AsyncDataTree implements IDisposable if (viewStateContext && viewStateContext.viewState.expanded && viewStateContext.viewState.expanded.indexOf(id) > -1) { childrenToRefresh.push(childAsyncDataTreeNode); + } else if (hasChildren && this.collapseByDefault && !this.collapseByDefault(element)) { + childAsyncDataTreeNode.collapsedByDefault = false; + childrenToRefresh.push(childAsyncDataTreeNode); } return childAsyncDataTreeNode; diff --git a/src/vs/base/browser/ui/tree/compressedObjectTree.ts b/src/vs/base/browser/ui/tree/compressedObjectTree.ts new file mode 100644 index 000000000..5d1b80462 --- /dev/null +++ b/src/vs/base/browser/ui/tree/compressedObjectTree.ts @@ -0,0 +1,56 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Iterator, ISequence } from 'vs/base/common/iterator'; +import { AbstractTree, IAbstractTreeOptions } from 'vs/base/browser/ui/tree/abstractTree'; +import { ISpliceable } from 'vs/base/common/sequence'; +import { ITreeNode, ITreeModel, ITreeElement, ITreeRenderer, ITreeSorter, ICollapseStateChangeEvent } from 'vs/base/browser/ui/tree/tree'; +import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; +import { Event } from 'vs/base/common/event'; +import { CompressedTreeModel, ICompressedTreeNode } from 'vs/base/browser/ui/tree/compressedObjectTreeModel'; + +export interface IObjectTreeOptions extends IAbstractTreeOptions { + sorter?: ITreeSorter; +} + +export class CompressedObjectTree, TFilterData = void> extends AbstractTree | null, TFilterData, T | null> { + + protected model: CompressedTreeModel; + + get onDidChangeCollapseState(): Event | null, TFilterData>> { return this.model.onDidChangeCollapseState; } + + constructor( + container: HTMLElement, + delegate: IListVirtualDelegate>, + renderers: ITreeRenderer, TFilterData, any>[], + options: IObjectTreeOptions, TFilterData> = {} + ) { + super(container, delegate, renderers, options); + } + + setChildren( + element: T | null, + children?: ISequence> + ): Iterator> { + return this.model.setChildren(element, children); + } + + rerender(element?: T): void { + if (element === undefined) { + this.view.rerender(); + return; + } + + this.model.rerender(element); + } + + resort(element: T, recursive = true): void { + this.model.resort(element, recursive); + } + + protected createModel(view: ISpliceable, TFilterData>>, options: IObjectTreeOptions, TFilterData>): ITreeModel | null, TFilterData, T | null> { + return new CompressedTreeModel(view, options); + } +} diff --git a/src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts b/src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts new file mode 100644 index 000000000..339dfdbbe --- /dev/null +++ b/src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts @@ -0,0 +1,418 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ISpliceable } from 'vs/base/common/sequence'; +import { Iterator, ISequence } from 'vs/base/common/iterator'; +import { Event } from 'vs/base/common/event'; +import { ITreeModel, ITreeNode, ITreeElement, ICollapseStateChangeEvent, ITreeModelSpliceEvent } from 'vs/base/browser/ui/tree/tree'; +import { IObjectTreeModelOptions, ObjectTreeModel, IObjectTreeModel } from 'vs/base/browser/ui/tree/objectTreeModel'; + +export interface ICompressedTreeElement extends ITreeElement { + readonly children?: Iterator> | ICompressedTreeElement[]; + readonly incompressible?: boolean; +} + +export interface ICompressedTreeNode { + readonly elements: T[]; + readonly incompressible: boolean; +} + +export function compress(element: ICompressedTreeElement): ITreeElement> { + const elements = [element.element]; + const incompressible = element.incompressible || false; + + let childrenIterator: Iterator>; + let children: ITreeElement[]; + + while (true) { + childrenIterator = Iterator.from(element.children); + children = Iterator.collect(childrenIterator, 2); + + if (children.length !== 1) { + break; + } + + element = children[0]; + + if (element.incompressible) { + break; + } + + elements.push(element.element); + } + + return { + element: { elements, incompressible }, + children: Iterator.map(Iterator.concat(Iterator.fromArray(children), childrenIterator), compress) + }; +} + +export function _decompress(element: ITreeElement>, index = 0): ICompressedTreeElement { + let children: Iterator>; + + if (index < element.element.elements.length - 1) { + children = Iterator.single(_decompress(element, index + 1)); + } else { + children = Iterator.map(Iterator.from(element.children), el => _decompress(el, 0)); + } + + if (index === 0 && element.element.incompressible) { + return { element: element.element.elements[index], children, incompressible: true }; + } + + return { element: element.element.elements[index], children }; +} + +export function decompress(element: ITreeElement>): ICompressedTreeElement { + return _decompress(element, 0); +} + +export function splice(treeElement: ICompressedTreeElement, element: T, children: Iterator>): ICompressedTreeElement { + if (treeElement.element === element) { + return { element, children }; + } + + return { + ...treeElement, + children: Iterator.map(Iterator.from(treeElement.children), e => splice(e, element, children)) + }; +} + +export interface ICompressedTreeModelOptions extends IObjectTreeModelOptions, TFilterData> { } + +export class CompressedTreeModel, TFilterData extends NonNullable = void> implements ITreeModel | null, TFilterData, T | null> { + + readonly rootRef = null; + + get onDidSplice(): Event | null, TFilterData>> { return this.model.onDidSplice; } + get onDidChangeCollapseState(): Event, TFilterData>> { return this.model.onDidChangeCollapseState; } + get onDidChangeRenderNodeCount(): Event, TFilterData>> { return this.model.onDidChangeRenderNodeCount; } + + private model: ObjectTreeModel, TFilterData>; + private nodes = new Map>(); + + get size(): number { return this.nodes.size; } + + constructor(list: ISpliceable, TFilterData>>, options: ICompressedTreeModelOptions = {}) { + this.model = new ObjectTreeModel(list, options); + } + + setChildren( + element: T | null, + children: ISequence> | undefined, + onDidCreateNode?: (node: ITreeNode, TFilterData>) => void, + onDidDeleteNode?: (node: ITreeNode, TFilterData>) => void + ): Iterator> { + const insertedElements = new Set(); + const _onDidCreateNode = (node: ITreeNode, TFilterData>) => { + for (const element of node.element.elements) { + insertedElements.add(element); + this.nodes.set(element, node.element); + } + + // if (this.identityProvider) { + // const id = this.identityProvider.getId(node.element).toString(); + // insertedElementIds.add(id); + // this.nodesByIdentity.set(id, node); + // } + + if (onDidCreateNode) { + onDidCreateNode(node); + } + }; + + const _onDidDeleteNode = (node: ITreeNode, TFilterData>) => { + for (const element of node.element.elements) { + if (!insertedElements.has(element)) { + this.nodes.delete(element); + } + } + + // if (this.identityProvider) { + // const id = this.identityProvider.getId(node.element).toString(); + // if (!insertedElementIds.has(id)) { + // this.nodesByIdentity.delete(id); + // } + // } + + if (onDidDeleteNode) { + onDidDeleteNode(node); + } + }; + + if (element === null) { + const compressedChildren = Iterator.map(Iterator.from(children), compress); + const result = this.model.setChildren(null, compressedChildren, _onDidCreateNode, _onDidDeleteNode); + return Iterator.map(result, decompress); + } + + const compressedNode = this.nodes.get(element); + const node = this.model.getNode(compressedNode) as ITreeNode, TFilterData>; + const parent = node.parent!; + + const decompressedElement = decompress(node); + const splicedElement = splice(decompressedElement, element, Iterator.from(children)); + const recompressedElement = compress(splicedElement); + + const parentChildren = parent.children + .map(child => child === node ? recompressedElement : child); + + this.model.setChildren(parent.element, parentChildren, _onDidCreateNode, _onDidDeleteNode); + + // TODO + return Iterator.empty(); + } + + getListIndex(location: T | null): number { + const node = this.getCompressedNode(location); + return this.model.getListIndex(node); + } + + getListRenderCount(location: T | null): number { + const node = this.getCompressedNode(location); + return this.model.getListRenderCount(node); + } + + getNode(location?: T | null | undefined): ITreeNode | null, TFilterData> { + if (typeof location === 'undefined') { + return this.model.getNode(); + } + + const node = this.getCompressedNode(location); + return this.model.getNode(node); + } + + // TODO: review this + getNodeLocation(node: ITreeNode, TFilterData>): T | null { + const compressedNode = this.model.getNodeLocation(node); + + if (compressedNode === null) { + return null; + } + + return compressedNode.elements[compressedNode.elements.length - 1]; + } + + // TODO: review this + getParentNodeLocation(location: T | null): T | null { + const compressedNode = this.getCompressedNode(location); + const parentNode = this.model.getParentNodeLocation(compressedNode); + + if (parentNode === null) { + return null; + } + + return parentNode.elements[parentNode.elements.length - 1]; + } + + getParentElement(location: T | null): ICompressedTreeNode | null { + const compressedNode = this.getCompressedNode(location); + return this.model.getParentElement(compressedNode); + } + + getFirstElementChild(location: T | null): ICompressedTreeNode | null | undefined { + const compressedNode = this.getCompressedNode(location); + return this.model.getFirstElementChild(compressedNode); + } + + getLastElementAncestor(location?: T | null | undefined): ICompressedTreeNode | null | undefined { + const compressedNode = typeof location === 'undefined' ? undefined : this.getCompressedNode(location); + return this.model.getLastElementAncestor(compressedNode); + } + + isCollapsible(location: T | null): boolean { + const compressedNode = this.getCompressedNode(location); + return this.model.isCollapsible(compressedNode); + } + + isCollapsed(location: T | null): boolean { + const compressedNode = this.getCompressedNode(location); + return this.model.isCollapsed(compressedNode); + } + + setCollapsed(location: T | null, collapsed?: boolean | undefined, recursive?: boolean | undefined): boolean { + const compressedNode = this.getCompressedNode(location); + return this.model.setCollapsed(compressedNode, collapsed, recursive); + } + + expandTo(location: T | null): void { + const compressedNode = this.getCompressedNode(location); + this.model.expandTo(compressedNode); + } + + rerender(location: T | null): void { + const compressedNode = this.getCompressedNode(location); + this.model.rerender(compressedNode); + } + + refilter(): void { + this.model.refilter(); + } + + resort(location: T | null = null, recursive = true): void { + const compressedNode = this.getCompressedNode(location); + this.model.resort(compressedNode, recursive); + } + + private getCompressedNode(element: T | null): ICompressedTreeNode | null { + if (element === null) { + return null; + } + + const node = this.nodes.get(element); + + if (!node) { + throw new Error(`Tree element not found: ${element}`); + } + + return node; + } +} + +export type ElementMapper = (elements: T[]) => T; +export const DefaultElementMapper: ElementMapper = elements => elements[elements.length - 1]; + +export type NodeMapper = (node: ITreeNode | null, TFilterData>) => ITreeNode; + +function mapNode(elementMapper: ElementMapper, node: ITreeNode | null, TFilterData>): ITreeNode { + return { + ...node, + element: node.element === null ? null : elementMapper(node.element.elements), + children: node.children.map(child => mapNode(elementMapper, child)), + parent: typeof node.parent === 'undefined' ? node.parent : mapNode(elementMapper, node.parent) + }; +} + +function createNodeMapper(elementMapper: ElementMapper): NodeMapper { + return node => mapNode(elementMapper, node); +} + +export interface ICompressedObjectTreeModelOptions extends ICompressedTreeModelOptions { + readonly elementMapper?: ElementMapper; +} + +export class CompressedObjectTreeModel, TFilterData extends NonNullable = void> implements IObjectTreeModel { + + readonly rootRef = null; + + get onDidSplice(): Event> { + return Event.map(this.model.onDidSplice, ({ insertedNodes, deletedNodes }) => ({ + insertedNodes: insertedNodes.map(this.mapNode), + deletedNodes: deletedNodes.map(this.mapNode), + })); + } + + get onDidChangeCollapseState(): Event> { + return Event.map(this.model.onDidChangeCollapseState, ({ node, deep }) => ({ + node: this.mapNode(node), + deep + })); + } + + get onDidChangeRenderNodeCount(): Event> { + return Event.map(this.model.onDidChangeRenderNodeCount, this.mapNode); + } + + private mapElement: ElementMapper; + private mapNode: NodeMapper; + private model: CompressedTreeModel; + + constructor( + list: ISpliceable, TFilterData>>, + options: ICompressedObjectTreeModelOptions = {} + ) { + this.mapElement = options.elementMapper || DefaultElementMapper; + this.mapNode = createNodeMapper(this.mapElement); + this.model = new CompressedTreeModel(list, options); + } + + setChildren( + element: T | null, + children: ISequence> | undefined + ): Iterator> { + this.model.setChildren(element, children); + + // TODO + return Iterator.empty(); + } + + getListIndex(location: T | null): number { + return this.model.getListIndex(location); + } + + getListRenderCount(location: T | null): number { + return this.model.getListRenderCount(location); + } + + getNode(location?: T | null | undefined): ITreeNode { + return this.mapNode(this.model.getNode(location)); + } + + getNodeLocation(node: ITreeNode): T | null { + return node.element; + } + + getParentNodeLocation(location: T | null): T | null { + return this.model.getParentNodeLocation(location); + } + + getParentElement(location: T | null): T | null { + const result = this.model.getParentElement(location); + + if (result === null) { + return result; + } + + return this.mapElement(result.elements); + } + + getFirstElementChild(location: T | null): T | null | undefined { + const result = this.model.getFirstElementChild(location); + + if (result === null || typeof result === 'undefined') { + return result; + } + + return this.mapElement(result.elements); + } + + getLastElementAncestor(location?: T | null | undefined): T | null | undefined { + const result = this.model.getLastElementAncestor(location); + + if (result === null || typeof result === 'undefined') { + return result; + } + + return this.mapElement(result.elements); + } + + isCollapsible(location: T | null): boolean { + return this.model.isCollapsible(location); + } + + isCollapsed(location: T | null): boolean { + return this.model.isCollapsed(location); + } + + setCollapsed(location: T | null, collapsed?: boolean | undefined, recursive?: boolean | undefined): boolean { + return this.model.setCollapsed(location, collapsed, recursive); + } + + expandTo(location: T | null): void { + return this.model.expandTo(location); + } + + rerender(location: T | null): void { + return this.model.rerender(location); + } + + refilter(): void { + return this.model.refilter(); + } + + resort(element: T | null = null, recursive = true): void { + return this.model.resort(element, recursive); + } +} \ No newline at end of file diff --git a/src/vs/base/browser/ui/tree/dataTree.ts b/src/vs/base/browser/ui/tree/dataTree.ts index d2342d7e8..9f51021a2 100644 --- a/src/vs/base/browser/ui/tree/dataTree.ts +++ b/src/vs/base/browser/ui/tree/dataTree.ts @@ -18,6 +18,7 @@ export interface IDataTreeViewState { readonly focus: string[]; readonly selection: string[]; readonly expanded: string[]; + readonly scrollTop: number; } export class DataTree extends AbstractTree { @@ -31,7 +32,7 @@ export class DataTree extends AbstractTree, - renderers: ITreeRenderer[], + renderers: ITreeRenderer[], private dataSource: IDataSource, options: IDataTreeOptions = {} ) { @@ -80,6 +81,10 @@ export class DataTree extends AbstractTree extends AbstractTree extends AbstractTree, - renderers: ITreeRenderer[], + renderers: ITreeRenderer[], private rootElement: T, options: IIndexTreeOptions = {} ) { diff --git a/src/vs/base/browser/ui/tree/media/collapsed-dark.svg b/src/vs/base/browser/ui/tree/media/collapsed-dark.svg deleted file mode 100755 index cf5c3641a..000000000 --- a/src/vs/base/browser/ui/tree/media/collapsed-dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/base/browser/ui/tree/media/collapsed-hc.svg b/src/vs/base/browser/ui/tree/media/collapsed-hc.svg deleted file mode 100644 index 145c76333..000000000 --- a/src/vs/base/browser/ui/tree/media/collapsed-hc.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/base/browser/ui/tree/media/collapsed.svg b/src/vs/base/browser/ui/tree/media/collapsed.svg deleted file mode 100755 index 3a63808c3..000000000 --- a/src/vs/base/browser/ui/tree/media/collapsed.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/base/browser/ui/tree/media/expanded-dark.svg b/src/vs/base/browser/ui/tree/media/expanded-dark.svg deleted file mode 100755 index 73d41e639..000000000 --- a/src/vs/base/browser/ui/tree/media/expanded-dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/base/browser/ui/tree/media/expanded-hc.svg b/src/vs/base/browser/ui/tree/media/expanded-hc.svg deleted file mode 100644 index d38d4abc8..000000000 --- a/src/vs/base/browser/ui/tree/media/expanded-hc.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/base/browser/ui/tree/media/expanded.svg b/src/vs/base/browser/ui/tree/media/expanded.svg deleted file mode 100755 index 75f73adbb..000000000 --- a/src/vs/base/browser/ui/tree/media/expanded.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/base/browser/ui/tree/media/tree-collapsed-dark.svg b/src/vs/base/browser/ui/tree/media/tree-collapsed-dark.svg new file mode 100644 index 000000000..c2c2298dd --- /dev/null +++ b/src/vs/base/browser/ui/tree/media/tree-collapsed-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/tree/media/tree-collapsed-hc.svg b/src/vs/base/browser/ui/tree/media/tree-collapsed-hc.svg new file mode 100644 index 000000000..3732cbc04 --- /dev/null +++ b/src/vs/base/browser/ui/tree/media/tree-collapsed-hc.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/tree/media/tree-collapsed-light.svg b/src/vs/base/browser/ui/tree/media/tree-collapsed-light.svg new file mode 100644 index 000000000..1952ad63f --- /dev/null +++ b/src/vs/base/browser/ui/tree/media/tree-collapsed-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/tree/media/tree-expanded-dark.svg b/src/vs/base/browser/ui/tree/media/tree-expanded-dark.svg new file mode 100644 index 000000000..5570923e1 --- /dev/null +++ b/src/vs/base/browser/ui/tree/media/tree-expanded-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/tree/media/tree-expanded-hc.svg b/src/vs/base/browser/ui/tree/media/tree-expanded-hc.svg new file mode 100644 index 000000000..b37000933 --- /dev/null +++ b/src/vs/base/browser/ui/tree/media/tree-expanded-hc.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/tree/media/tree-expanded-light.svg b/src/vs/base/browser/ui/tree/media/tree-expanded-light.svg new file mode 100644 index 000000000..939ebc8b9 --- /dev/null +++ b/src/vs/base/browser/ui/tree/media/tree-expanded-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/browser/ui/tree/media/tree.css b/src/vs/base/browser/ui/tree/media/tree.css index 4f86f971f..47c1e405b 100644 --- a/src/vs/base/browser/ui/tree/media/tree.css +++ b/src/vs/base/browser/ui/tree/media/tree.css @@ -7,6 +7,30 @@ display: flex; height: 100%; align-items: center; + position: relative; +} + +.monaco-tl-indent { + height: 100%; + position: absolute; + top: 0; + left: 18px; + pointer-events: none; +} + +.hide-arrows .monaco-tl-indent { + left: 12px; +} + +.monaco-tl-indent > .indent-guide { + display: inline-block; + box-sizing: border-box; + height: 100%; + border-left: 1px solid transparent; +} + +.monaco-tl-indent > .indent-guide { + transition: border-color 0.1s linear; } .monaco-tl-twistie, @@ -31,28 +55,28 @@ background-size: 16px; background-position: 3px 50%; background-repeat: no-repeat; - background-image: url("expanded.svg"); + background-image: url("tree-expanded-light.svg"); } .monaco-tl-twistie.collapsible.collapsed:not(.loading) { display: inline-block; - background-image: url("collapsed.svg"); + background-image: url("tree-collapsed-light.svg"); } .vs-dark .monaco-tl-twistie.collapsible:not(.loading) { - background-image: url("expanded-dark.svg"); + background-image: url("tree-expanded-dark.svg"); } .vs-dark .monaco-tl-twistie.collapsible.collapsed:not(.loading) { - background-image: url("collapsed-dark.svg"); + background-image: url("tree-collapsed-dark.svg"); } .hc-black .monaco-tl-twistie.collapsible:not(.loading) { - background-image: url("expanded-hc.svg"); + background-image: url("tree-expanded-hc.svg"); } .hc-black .monaco-tl-twistie.collapsible.collapsed:not(.loading) { - background-image: url("collapsed-hc.svg"); + background-image: url("tree-collapsed-hc.svg"); } .monaco-tl-twistie.loading { @@ -66,4 +90,4 @@ .hc-black .monaco-tl-twistie.loading { background-image: url("loading-hc.svg"); -} \ No newline at end of file +} diff --git a/src/vs/base/browser/ui/tree/objectTree.ts b/src/vs/base/browser/ui/tree/objectTree.ts index 1236b0657..518734629 100644 --- a/src/vs/base/browser/ui/tree/objectTree.ts +++ b/src/vs/base/browser/ui/tree/objectTree.ts @@ -6,9 +6,10 @@ import { Iterator, ISequence } from 'vs/base/common/iterator'; import { AbstractTree, IAbstractTreeOptions } from 'vs/base/browser/ui/tree/abstractTree'; import { ISpliceable } from 'vs/base/common/sequence'; -import { ITreeNode, ITreeModel, ITreeElement, ITreeRenderer, ITreeSorter } from 'vs/base/browser/ui/tree/tree'; -import { ObjectTreeModel } from 'vs/base/browser/ui/tree/objectTreeModel'; +import { ITreeNode, ITreeModel, ITreeElement, ITreeRenderer, ITreeSorter, ICollapseStateChangeEvent } from 'vs/base/browser/ui/tree/tree'; +import { ObjectTreeModel, IObjectTreeModel } from 'vs/base/browser/ui/tree/objectTreeModel'; import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; +import { Event } from 'vs/base/common/event'; export interface IObjectTreeOptions extends IAbstractTreeOptions { sorter?: ITreeSorter; @@ -16,12 +17,14 @@ export interface IObjectTreeOptions extends IAbstractTree export class ObjectTree, TFilterData = void> extends AbstractTree { - protected model: ObjectTreeModel; + protected model: IObjectTreeModel; + + get onDidChangeCollapseState(): Event> { return this.model.onDidChangeCollapseState; } constructor( container: HTMLElement, delegate: IListVirtualDelegate, - renderers: ITreeRenderer[], + renderers: ITreeRenderer[], options: IObjectTreeOptions = {} ) { super(container, delegate, renderers, options); @@ -29,11 +32,9 @@ export class ObjectTree, TFilterData = void> extends setChildren( element: T | null, - children?: ISequence>, - onDidCreateNode?: (node: ITreeNode) => void, - onDidDeleteNode?: (node: ITreeNode) => void + children?: ISequence> ): Iterator> { - return this.model.setChildren(element, children, onDidCreateNode, onDidDeleteNode); + return this.model.setChildren(element, children); } rerender(element?: T): void { diff --git a/src/vs/base/browser/ui/tree/objectTreeModel.ts b/src/vs/base/browser/ui/tree/objectTreeModel.ts index 9fc7e0089..626d1264d 100644 --- a/src/vs/base/browser/ui/tree/objectTreeModel.ts +++ b/src/vs/base/browser/ui/tree/objectTreeModel.ts @@ -8,17 +8,28 @@ import { Iterator, ISequence, getSequenceIterator } from 'vs/base/common/iterato import { IndexTreeModel, IIndexTreeModelOptions } from 'vs/base/browser/ui/tree/indexTreeModel'; import { Event } from 'vs/base/common/event'; import { ITreeModel, ITreeNode, ITreeElement, ITreeSorter, ICollapseStateChangeEvent, ITreeModelSpliceEvent } from 'vs/base/browser/ui/tree/tree'; +import { IIdentityProvider } from 'vs/base/browser/ui/list/list'; + +export type ITreeNodeCallback = (node: ITreeNode) => void; + +export interface IObjectTreeModel, TFilterData extends NonNullable = void> extends ITreeModel { + setChildren(element: T | null, children: ISequence> | undefined): Iterator>; + resort(element?: T | null, recursive?: boolean): void; +} export interface IObjectTreeModelOptions extends IIndexTreeModelOptions { readonly sorter?: ITreeSorter; + readonly identityProvider?: IIdentityProvider; } -export class ObjectTreeModel, TFilterData extends NonNullable = void> implements ITreeModel { +export class ObjectTreeModel, TFilterData extends NonNullable = void> implements IObjectTreeModel { readonly rootRef = null; private model: IndexTreeModel; private nodes = new Map>(); + private readonly nodesByIdentity = new Map>(); + private readonly identityProvider?: IIdentityProvider; private sorter?: ITreeSorter<{ element: T; }>; readonly onDidSplice: Event>; @@ -40,14 +51,16 @@ export class ObjectTreeModel, TFilterData extends Non } }; } + + this.identityProvider = options.identityProvider; } setChildren( element: T | null, children: ISequence> | undefined, - onDidCreateNode?: (node: ITreeNode) => void, - onDidDeleteNode?: (node: ITreeNode) => void - ): Iterator> { + onDidCreateNode?: ITreeNodeCallback, + onDidDeleteNode?: ITreeNodeCallback + ): Iterator> { const location = this.getElementLocation(element); return this._setChildren(location, this.preserveCollapseState(children), onDidCreateNode, onDidDeleteNode); } @@ -55,15 +68,22 @@ export class ObjectTreeModel, TFilterData extends Non private _setChildren( location: number[], children: ISequence> | undefined, - onDidCreateNode?: (node: ITreeNode) => void, - onDidDeleteNode?: (node: ITreeNode) => void - ): Iterator> { + onDidCreateNode?: ITreeNodeCallback, + onDidDeleteNode?: ITreeNodeCallback + ): Iterator> { const insertedElements = new Set(); + const insertedElementIds = new Set(); const _onDidCreateNode = (node: ITreeNode) => { insertedElements.add(node.element); this.nodes.set(node.element, node); + if (this.identityProvider) { + const id = this.identityProvider.getId(node.element).toString(); + insertedElementIds.add(id); + this.nodesByIdentity.set(id, node); + } + if (onDidCreateNode) { onDidCreateNode(node); } @@ -74,18 +94,27 @@ export class ObjectTreeModel, TFilterData extends Non this.nodes.delete(node.element); } + if (this.identityProvider) { + const id = this.identityProvider.getId(node.element).toString(); + if (!insertedElementIds.has(id)) { + this.nodesByIdentity.delete(id); + } + } + if (onDidDeleteNode) { onDidDeleteNode(node); } }; - return this.model.splice( + const result = this.model.splice( [...location, 0], Number.MAX_VALUE, children, _onDidCreateNode, _onDidDeleteNode ); + + return result as Iterator>; } private preserveCollapseState(elements: ISequence> | undefined): ISequence> { @@ -96,7 +125,12 @@ export class ObjectTreeModel, TFilterData extends Non } return Iterator.map(iterator, treeElement => { - const node = this.nodes.get(treeElement.element); + let node = this.nodes.get(treeElement.element); + + if (!node && this.identityProvider) { + const id = this.identityProvider.getId(treeElement.element).toString(); + node = this.nodesByIdentity.get(id); + } if (!node) { return { @@ -117,7 +151,7 @@ export class ObjectTreeModel, TFilterData extends Non }); } - rerender(element: T): void { + rerender(element: T | null): void { const location = this.getElementLocation(element); this.model.rerender(location); } @@ -163,32 +197,32 @@ export class ObjectTreeModel, TFilterData extends Non return this.model.getLastElementAncestor(location); } - getListIndex(element: T): number { + getListIndex(element: T | null): number { const location = this.getElementLocation(element); return this.model.getListIndex(location); } - getListRenderCount(element: T): number { + getListRenderCount(element: T | null): number { const location = this.getElementLocation(element); return this.model.getListRenderCount(location); } - isCollapsible(element: T): boolean { + isCollapsible(element: T | null): boolean { const location = this.getElementLocation(element); return this.model.isCollapsible(location); } - isCollapsed(element: T): boolean { + isCollapsed(element: T | null): boolean { const location = this.getElementLocation(element); return this.model.isCollapsed(location); } - setCollapsed(element: T, collapsed?: boolean, recursive?: boolean): boolean { + setCollapsed(element: T | null, collapsed?: boolean, recursive?: boolean): boolean { const location = this.getElementLocation(element); return this.model.setCollapsed(location, collapsed, recursive); } - expandTo(element: T): void { + expandTo(element: T | null): void { const location = this.getElementLocation(element); this.model.expandTo(location); } @@ -211,11 +245,15 @@ export class ObjectTreeModel, TFilterData extends Non return node; } - getNodeLocation(node: ITreeNode): T { + getNodeLocation(node: ITreeNode): T | null { return node.element; } - getParentNodeLocation(element: T): T | null { + getParentNodeLocation(element: T | null): T | null { + if (element === null) { + throw new Error(`Invalid getParentNodeLocation call`); + } + const node = this.nodes.get(element); if (!node) { diff --git a/src/vs/base/browser/ui/tree/tree.ts b/src/vs/base/browser/ui/tree/tree.ts index cedb6fbd4..5f9f2e14d 100644 --- a/src/vs/base/browser/ui/tree/tree.ts +++ b/src/vs/base/browser/ui/tree/tree.ts @@ -124,6 +124,7 @@ export interface ITreeModel { setCollapsed(location: TRef, collapsed?: boolean, recursive?: boolean): boolean; expandTo(location: TRef): void; + rerender(location: TRef): void; refilter(): void; } @@ -137,9 +138,16 @@ export interface ITreeEvent { browserEvent?: UIEvent; } +export enum TreeMouseEventTarget { + Unknown, + Twistie, + Element +} + export interface ITreeMouseEvent { browserEvent: MouseEvent; element: T | null; + target: TreeMouseEventTarget; } export interface ITreeContextMenuEvent { diff --git a/src/vs/base/browser/ui/tree/treeDefaults.ts b/src/vs/base/browser/ui/tree/treeDefaults.ts new file mode 100644 index 000000000..03b8665cd --- /dev/null +++ b/src/vs/base/browser/ui/tree/treeDefaults.ts @@ -0,0 +1,25 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { Action } from 'vs/base/common/actions'; +import { AsyncDataTree } from 'vs/base/browser/ui/tree/asyncDataTree'; + +export class CollapseAllAction extends Action { + + constructor(private viewer: AsyncDataTree, enabled: boolean) { + super('vs.tree.collapse', nls.localize('collapse all', "Collapse All"), 'monaco-tree-action collapse-all', enabled); + } + + public run(context?: any): Promise { + this.viewer.collapseAll(); + this.viewer.setSelection([]); + this.viewer.setFocus([]); + this.viewer.domFocus(); + this.viewer.focusFirst(); + + return Promise.resolve(); + } +} \ No newline at end of file diff --git a/src/vs/base/common/actions.ts b/src/vs/base/common/actions.ts index 2e4fbf152..b0e1b6f16 100644 --- a/src/vs/base/common/actions.ts +++ b/src/vs/base/common/actions.ts @@ -3,17 +3,27 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IDisposable, combinedDisposable, Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; import { Event, Emitter } from 'vs/base/common/event'; export interface ITelemetryData { - from?: string; - target?: string; + readonly from?: string; + readonly target?: string; [key: string]: any; } -export interface IAction extends IDisposable { +export type WorkbenchActionExecutedClassification = { + id: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + from: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; +}; + +export type WorkbenchActionExecutedEvent = { id: string; + from: string; +}; + +export interface IAction extends IDisposable { + readonly id: string; label: string; tooltip: string; class: string | undefined; @@ -25,44 +35,44 @@ export interface IAction extends IDisposable { export interface IActionRunner extends IDisposable { run(action: IAction, context?: any): Promise; - onDidRun: Event; - onDidBeforeRun: Event; + readonly onDidRun: Event; + readonly onDidBeforeRun: Event; } -export interface IActionItem { - actionRunner: IActionRunner; +export interface IActionViewItem extends IDisposable { + readonly actionRunner: IActionRunner; setActionContext(context: any): void; render(element: any /* HTMLElement */): void; isEnabled(): boolean; focus(): void; blur(): void; - dispose(): void; } export interface IActionChangeEvent { - label?: string; - tooltip?: string; - class?: string; - enabled?: boolean; - checked?: boolean; - radio?: boolean; + readonly label?: string; + readonly tooltip?: string; + readonly class?: string; + readonly enabled?: boolean; + readonly checked?: boolean; + readonly radio?: boolean; } -export class Action implements IAction { +export class Action extends Disposable implements IAction { - protected _onDidChange = new Emitter(); + protected _onDidChange = this._register(new Emitter()); readonly onDidChange: Event = this._onDidChange.event; - protected _id: string; + protected readonly _id: string; protected _label: string; protected _tooltip: string; protected _cssClass: string | undefined; protected _enabled: boolean; protected _checked: boolean; protected _radio: boolean; - protected _actionCallback?: (event?: any) => Promise; + protected readonly _actionCallback?: (event?: any) => Promise; constructor(id: string, label: string = '', cssClass: string = '', enabled: boolean = true, actionCallback?: (event?: any) => Promise) { + super(); this._id = id; this._label = label; this._cssClass = cssClass; @@ -82,7 +92,7 @@ export class Action implements IAction { this._setLabel(value); } - protected _setLabel(value: string): void { + private _setLabel(value: string): void { if (this._label !== value) { this._label = value; this._onDidChange.fire({ label: value }); @@ -171,16 +181,12 @@ export class Action implements IAction { return Promise.resolve(true); } - - dispose() { - this._onDidChange.dispose(); - } } export interface IRunEvent { - action: IAction; - result?: any; - error?: any; + readonly action: IAction; + readonly result?: any; + readonly error?: any; } export class ActionRunner extends Disposable implements IActionRunner { @@ -191,18 +197,19 @@ export class ActionRunner extends Disposable implements IActionRunner { private _onDidRun = this._register(new Emitter()); readonly onDidRun: Event = this._onDidRun.event; - run(action: IAction, context?: any): Promise { + async run(action: IAction, context?: any): Promise { if (!action.enabled) { return Promise.resolve(null); } this._onDidBeforeRun.fire({ action: action }); - return this.runAction(action, context).then((result: any) => { + try { + const result = await this.runAction(action, context); this._onDidRun.fire({ action: action, result: result }); - }, (error: any) => { + } catch (error) { this._onDidRun.fire({ action: action, error: error }); - }); + } } protected runAction(action: IAction, context?: any): Promise { @@ -216,8 +223,8 @@ export class RadioGroup extends Disposable { constructor(readonly actions: Action[]) { super(); - this._register(combinedDisposable(actions.map(action => { - return action.onDidChange(e => { + for (const action of actions) { + this._register(action.onDidChange(e => { if (e.checked && action.checked) { for (const candidate of actions) { if (candidate !== action) { @@ -225,7 +232,7 @@ export class RadioGroup extends Disposable { } } } - }); - }))); + })); + } } } diff --git a/src/vs/base/common/arrays.ts b/src/vs/base/common/arrays.ts index 8a3bb5bdb..7aa425977 100644 --- a/src/vs/base/common/arrays.ts +++ b/src/vs/base/common/arrays.ts @@ -295,7 +295,7 @@ function topStep(array: ReadonlyArray, compare: (a: T, b: T) => number, re /** * @returns a new array with all falsy values removed. The original array IS NOT modified. */ -export function coalesce(array: Array): T[] { +export function coalesce(array: ReadonlyArray): T[] { if (!array) { return array; } @@ -336,7 +336,9 @@ export function isFalsyOrEmpty(obj: any): boolean { /** * @returns True if the provided object is an array and has at least one element. */ -export function isNonEmptyArray(obj: ReadonlyArray | undefined | null): obj is Array { +export function isNonEmptyArray(obj: T[] | undefined | null): obj is T[]; +export function isNonEmptyArray(obj: readonly T[] | undefined | null): obj is readonly T[]; +export function isNonEmptyArray(obj: T[] | readonly T[] | undefined | null): obj is T[] | readonly T[] { return Array.isArray(obj) && obj.length > 0; } diff --git a/src/vs/base/common/async.ts b/src/vs/base/common/async.ts index 6cb25fa70..6906e1376 100644 --- a/src/vs/base/common/async.ts +++ b/src/vs/base/common/async.ts @@ -6,7 +6,7 @@ import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import * as errors from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; -import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; export function isThenable(obj: any): obj is Promise { @@ -50,6 +50,12 @@ export function createCancelablePromise(callback: (token: CancellationToken) }; } +export function raceCancellation(promise: Promise, token: CancellationToken): Promise; +export function raceCancellation(promise: Promise, token: CancellationToken, defaultValue: T): Promise; +export function raceCancellation(promise: Promise, token: CancellationToken, defaultValue?: T): Promise { + return Promise.race([promise, new Promise(resolve => token.onCancellationRequested(() => resolve(defaultValue)))]); +} + export function asPromise(callback: () => T | Thenable): Promise { return new Promise((resolve, reject) => { const item = callback(); @@ -409,11 +415,11 @@ export class Limiter { this._onFinished = new Emitter(); } - public get onFinished(): Event { + get onFinished(): Event { return this._onFinished.event; } - public get size(): number { + get size(): number { return this._size; // return this.runningPromises + this.outstandingPromises.length; } @@ -449,7 +455,7 @@ export class Limiter { } } - public dispose(): void { + dispose(): void { this._onFinished.dispose(); } } @@ -469,35 +475,30 @@ export class Queue extends Limiter { * by disposing them once the queue is empty. */ export class ResourceQueue { - private queues: { [path: string]: Queue }; + private queues: Map> = new Map(); - constructor() { - this.queues = Object.create(null); - } - - public queueFor(resource: URI): Queue { + queueFor(resource: URI): Queue { const key = resource.toString(); - if (!this.queues[key]) { + if (!this.queues.has(key)) { const queue = new Queue(); queue.onFinished(() => { queue.dispose(); - delete this.queues[key]; + this.queues.delete(key); }); - this.queues[key] = queue; + this.queues.set(key, queue); } - return this.queues[key]; + return this.queues.get(key)!; } } -export class TimeoutTimer extends Disposable { +export class TimeoutTimer implements IDisposable { private _token: any; constructor(); constructor(runner: () => void, timeout: number); constructor(runner?: () => void, timeout?: number) { - super(); this._token = -1; if (typeof runner === 'function' && typeof timeout === 'number') { @@ -507,7 +508,6 @@ export class TimeoutTimer extends Disposable { dispose(): void { this.cancel(); - super.dispose(); } cancel(): void { @@ -537,18 +537,16 @@ export class TimeoutTimer extends Disposable { } } -export class IntervalTimer extends Disposable { +export class IntervalTimer implements IDisposable { private _token: any; constructor() { - super(); this._token = -1; } dispose(): void { this.cancel(); - super.dispose(); } cancel(): void { @@ -767,4 +765,4 @@ export async function retry(task: ITask>, delay: number, retries: } return Promise.reject(lastError); -} \ No newline at end of file +} diff --git a/src/vs/base/common/buffer.ts b/src/vs/base/common/buffer.ts index cf34296e7..99d5e5274 100644 --- a/src/vs/base/common/buffer.ts +++ b/src/vs/base/common/buffer.ts @@ -78,7 +78,10 @@ export class VSBuffer { } slice(start?: number, end?: number): VSBuffer { - return new VSBuffer(this.buffer.slice(start, end)); + // IMPORTANT: use subarray instead of slice because TypedArray#slice + // creates shallow copy and NodeBuffer#slice doesn't. The use of subarray + // ensures the same, performant, behaviour. + return new VSBuffer(this.buffer.subarray(start!/*bad lib.d.ts*/, end)); } set(array: VSBuffer, offset?: number): void { @@ -102,7 +105,7 @@ export class VSBuffer { } } -function readUInt32BE(source: Uint8Array, offset: number): number { +export function readUInt32BE(source: Uint8Array, offset: number): number { return ( source[offset] * 2 ** 24 + source[offset + 1] * 2 ** 16 @@ -111,7 +114,7 @@ function readUInt32BE(source: Uint8Array, offset: number): number { ); } -function writeUInt32BE(destination: Uint8Array, value: number, offset: number): void { +export function writeUInt32BE(destination: Uint8Array, value: number, offset: number): void { destination[offset + 3] = value; value = value >>> 8; destination[offset + 2] = value; @@ -138,18 +141,13 @@ export interface VSBufferReadable { read(): VSBuffer | null; } -/** - * A buffer readable stream emits data to listeners. The stream - * will only start emitting when the first data listener has - * been added or the resume() method has been called. - */ -export interface VSBufferReadableStream { +export interface ReadableStream { /** * The 'data' event is emitted whenever the stream is * relinquishing ownership of a chunk of data to a consumer. */ - on(event: 'data', callback: (chunk: VSBuffer) => void): void; + on(event: 'data', callback: (chunk: T) => void): void; /** * Emitted when any error occurs. @@ -166,19 +164,34 @@ export interface VSBufferReadableStream { /** * Stops emitting any events until resume() is called. */ - pause(): void; + pause?(): void; /** * Starts emitting events again after pause() was called. */ - resume(): void; + resume?(): void; /** * Destroys the stream and stops emitting any event. */ + destroy?(): void; +} + +/** + * A readable stream that sends data via VSBuffer. + */ +export interface VSBufferReadableStream extends ReadableStream { + pause(): void; + resume(): void; destroy(): void; } +export function isVSBufferReadableStream(obj: any): obj is VSBufferReadableStream { + const candidate: VSBufferReadableStream = obj; + + return candidate && [candidate.on, candidate.pause, candidate.resume, candidate.destroy].every(fn => typeof fn === 'function'); +} + /** * Helper to fully read a VSBuffer readable into a single buffer. */ @@ -236,6 +249,19 @@ export function bufferToStream(buffer: VSBuffer): VSBufferReadableStream { return stream; } +/** + * Helper to create a VSBufferStream from a Uint8Array stream. + */ +export function toVSBufferReadableStream(stream: ReadableStream): VSBufferReadableStream { + const vsbufferStream = writeableBufferStream(); + + stream.on('data', data => vsbufferStream.write(typeof data === 'string' ? VSBuffer.fromString(data) : VSBuffer.wrap(data))); + stream.on('end', () => vsbufferStream.end()); + stream.on('error', error => vsbufferStream.error(error)); + + return vsbufferStream; +} + /** * Helper to create a VSBufferStream that can be pushed * buffers to. Will only start to emit data when a listener @@ -437,4 +463,4 @@ class VSBufferWriteableStreamImpl implements VSBufferWriteableStream { this.listeners.end.length = 0; } } -} \ No newline at end of file +} diff --git a/src/vs/base/common/cache.ts b/src/vs/base/common/cache.ts index f46d663f7..bc585927f 100644 --- a/src/vs/base/common/cache.ts +++ b/src/vs/base/common/cache.ts @@ -4,10 +4,10 @@ *--------------------------------------------------------------------------------------------*/ import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; +import { IDisposable } from 'vs/base/common/lifecycle'; -export interface CacheResult { +export interface CacheResult extends IDisposable { promise: Promise; - dispose(): void; } export class Cache { diff --git a/src/vs/base/common/collections.ts b/src/vs/base/common/collections.ts index f5c5cf540..a0f6695e8 100644 --- a/src/vs/base/common/collections.ts +++ b/src/vs/base/common/collections.ts @@ -46,9 +46,9 @@ export function size(from: IStringDictionary | INumberDictionary): numb } export function first(from: IStringDictionary | INumberDictionary): T | undefined { - for (let key in from) { + for (const key in from) { if (hasOwnProperty.call(from, key)) { - return from[key]; + return (from as any)[key]; } } return undefined; @@ -96,4 +96,44 @@ export function fromMap(original: Map): IStringDictionary { }); } return result; +} + +export class SetMap { + + private map = new Map>(); + + add(key: K, value: V): void { + let values = this.map.get(key); + + if (!values) { + values = new Set(); + this.map.set(key, values); + } + + values.add(value); + } + + delete(key: K, value: V): void { + const values = this.map.get(key); + + if (!values) { + return; + } + + values.delete(value); + + if (values.size === 0) { + this.map.delete(key); + } + } + + forEach(key: K, fn: (value: V) => void): void { + const values = this.map.get(key); + + if (!values) { + return; + } + + values.forEach(fn); + } } \ No newline at end of file diff --git a/src/vs/base/common/comparers.ts b/src/vs/base/common/comparers.ts index adf5859c7..d6dbb1784 100644 --- a/src/vs/base/common/comparers.ts +++ b/src/vs/base/common/comparers.ts @@ -7,28 +7,26 @@ import * as strings from 'vs/base/common/strings'; import { sep } from 'vs/base/common/path'; import { IdleValue } from 'vs/base/common/async'; -let intlFileNameCollator: IdleValue<{ collator: Intl.Collator, collatorIsNumeric: boolean }>; - -export function setFileNameComparer(collator: IdleValue<{ collator: Intl.Collator, collatorIsNumeric: boolean }>): void { - intlFileNameCollator = collator; -} +const intlFileNameCollator: IdleValue<{ collator: Intl.Collator, collatorIsNumeric: boolean }> = new IdleValue(() => { + const collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' }); + return { + collator: collator, + collatorIsNumeric: collator.resolvedOptions().numeric + }; +}); export function compareFileNames(one: string | null, other: string | null, caseSensitive = false): number { - if (intlFileNameCollator) { - const a = one || ''; - const b = other || ''; - const result = intlFileNameCollator.getValue().collator.compare(a, b); - - // Using the numeric option in the collator will - // make compare(`foo1`, `foo01`) === 0. We must disambiguate. - if (intlFileNameCollator.getValue().collatorIsNumeric && result === 0 && a !== b) { - return a < b ? -1 : 1; - } - - return result; + const a = one || ''; + const b = other || ''; + const result = intlFileNameCollator.getValue().collator.compare(a, b); + + // Using the numeric option in the collator will + // make compare(`foo1`, `foo01`) === 0. We must disambiguate. + if (intlFileNameCollator.getValue().collatorIsNumeric && result === 0 && a !== b) { + return a < b ? -1 : 1; } - return noIntlCompareFileNames(one, other, caseSensitive); + return result; } const FileNameMatch = /^(.*?)(\.([^.]*))?$/; @@ -54,46 +52,27 @@ export function noIntlCompareFileNames(one: string | null, other: string | null, } export function compareFileExtensions(one: string | null, other: string | null): number { - if (intlFileNameCollator) { - const [oneName, oneExtension] = extractNameAndExtension(one); - const [otherName, otherExtension] = extractNameAndExtension(other); - - let result = intlFileNameCollator.getValue().collator.compare(oneExtension, otherExtension); - - if (result === 0) { - // Using the numeric option in the collator will - // make compare(`foo1`, `foo01`) === 0. We must disambiguate. - if (intlFileNameCollator.getValue().collatorIsNumeric && oneExtension !== otherExtension) { - return oneExtension < otherExtension ? -1 : 1; - } + const [oneName, oneExtension] = extractNameAndExtension(one); + const [otherName, otherExtension] = extractNameAndExtension(other); - // Extensions are equal, compare filenames - result = intlFileNameCollator.getValue().collator.compare(oneName, otherName); + let result = intlFileNameCollator.getValue().collator.compare(oneExtension, otherExtension); - if (intlFileNameCollator.getValue().collatorIsNumeric && result === 0 && oneName !== otherName) { - return oneName < otherName ? -1 : 1; - } + if (result === 0) { + // Using the numeric option in the collator will + // make compare(`foo1`, `foo01`) === 0. We must disambiguate. + if (intlFileNameCollator.getValue().collatorIsNumeric && oneExtension !== otherExtension) { + return oneExtension < otherExtension ? -1 : 1; } - return result; - } - - return noIntlCompareFileExtensions(one, other); -} - -function noIntlCompareFileExtensions(one: string | null, other: string | null): number { - const [oneName, oneExtension] = extractNameAndExtension(one && one.toLowerCase()); - const [otherName, otherExtension] = extractNameAndExtension(other && other.toLowerCase()); - - if (oneExtension !== otherExtension) { - return oneExtension < otherExtension ? -1 : 1; - } + // Extensions are equal, compare filenames + result = intlFileNameCollator.getValue().collator.compare(oneName, otherName); - if (oneName === otherName) { - return 0; + if (intlFileNameCollator.getValue().collatorIsNumeric && result === 0 && oneName !== otherName) { + return oneName < otherName ? -1 : 1; + } } - return oneName < otherName ? -1 : 1; + return result; } function extractNameAndExtension(str?: string | null): [string, string] { diff --git a/src/vs/base/common/console.ts b/src/vs/base/common/console.ts index 2ac39e3d7..9b49ff985 100644 --- a/src/vs/base/common/console.ts +++ b/src/vs/base/common/console.ts @@ -79,7 +79,7 @@ export function getFirstFrame(arg0: IRemoteConsoleLog | string | undefined): ISt uri: URI.file(matches[1]), line: Number(matches[2]), column: Number(matches[3]) - } as IStackFrame; + }; } } @@ -131,7 +131,10 @@ export function log(entry: IRemoteConsoleLog, label: string): void { } // Log it - console[entry.severity].apply(console, consoleArgs); + if (typeof (console as any)[entry.severity] !== 'function') { + throw new Error('Unknown console method'); + } + (console as any)[entry.severity].apply(console, consoleArgs); } function color(color: string): string { diff --git a/src/vs/base/common/errorMessage.ts b/src/vs/base/common/errorMessage.ts index ddd6976f6..e3fc44bac 100644 --- a/src/vs/base/common/errorMessage.ts +++ b/src/vs/base/common/errorMessage.ts @@ -10,7 +10,7 @@ import * as arrays from 'vs/base/common/arrays'; function exceptionToErrorMessage(exception: any, verbose: boolean): string { if (exception.message) { if (verbose && (exception.stack || exception.stacktrace)) { - return nls.localize('stackTrace.format', "{0}: {1}", detectSystemErrorMessage(exception), exception.stack || exception.stacktrace); + return nls.localize('stackTrace.format', "{0}: {1}", detectSystemErrorMessage(exception), stackToString(exception.stack) || stackToString(exception.stacktrace)); } return detectSystemErrorMessage(exception); @@ -19,6 +19,14 @@ function exceptionToErrorMessage(exception: any, verbose: boolean): string { return nls.localize('error.defaultMessage', "An unknown error occurred. Please consult the log for more details."); } +function stackToString(stack: string[] | string | undefined): string | undefined { + if (Array.isArray(stack)) { + return stack.join('\n'); + } + + return stack; +} + function detectSystemErrorMessage(exception: any): string { // See https://nodejs.org/api/errors.html#errors_class_system_error diff --git a/src/vs/base/common/errorsWithActions.ts b/src/vs/base/common/errorsWithActions.ts index 6b77eb5c7..133febb84 100644 --- a/src/vs/base/common/errorsWithActions.ts +++ b/src/vs/base/common/errorsWithActions.ts @@ -6,11 +6,11 @@ import { IAction } from 'vs/base/common/actions'; export interface IErrorOptions { - actions?: IAction[]; + actions?: ReadonlyArray; } export interface IErrorWithActions { - actions?: IAction[]; + actions?: ReadonlyArray; } export function isErrorWithActions(obj: any): obj is IErrorWithActions { diff --git a/src/vs/base/common/event.ts b/src/vs/base/common/event.ts index 0ef9379e6..2a4236371 100644 --- a/src/vs/base/common/event.ts +++ b/src/vs/base/common/event.ts @@ -5,7 +5,7 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { once as onceFn } from 'vs/base/common/functional'; -import { combinedDisposable, Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, toDisposable, combinedDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { LinkedList } from 'vs/base/common/linkedList'; /** @@ -13,12 +13,11 @@ import { LinkedList } from 'vs/base/common/linkedList'; * can be subscribed. The event is the subscriber function itself. */ export interface Event { - (listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[]): IDisposable; + (listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore): IDisposable; } export namespace Event { - const _disposable = { dispose() { } }; - export const None: Event = function () { return _disposable; }; + export const None: Event = () => Disposable.None; /** * Given an event, returns another event which only fires once. @@ -50,7 +49,7 @@ export namespace Event { /** * Given an event and a `map` function, returns another event which maps each element - * throught the mapping function. + * through the mapping function. */ export function map(event: Event, map: (i: I) => O): Event { return snapshot((listener, thisArgs = null, disposables?) => event(i => listener.call(thisArgs, map(i)), null, disposables)); @@ -86,12 +85,12 @@ export namespace Event { * whenever any of the provided events emit. */ export function any(...events: Event[]): Event { - return (listener, thisArgs = null, disposables?) => combinedDisposable(events.map(event => event(e => listener.call(thisArgs, e), null, disposables))); + return (listener, thisArgs = null, disposables?) => combinedDisposable(...events.map(event => event(e => listener.call(thisArgs, e), null, disposables))); } /** * Given an event and a `merge` function, returns another event which maps each element - * and the cummulative result throught the `merge` function. Similar to `map`, but with memory. + * and the cumulative result through the `merge` function. Similar to `map`, but with memory. */ export function reduce(event: Event, merge: (last: O | undefined, event: I) => O, initial?: O): Event { let output: O | undefined = initial; @@ -272,7 +271,7 @@ export namespace Event { filter(fn: (e: T) => boolean): IChainableEvent; reduce(merge: (last: R | undefined, event: T) => R, initial?: R): IChainableEvent; latch(): IChainableEvent; - on(listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[]): IDisposable; + on(listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore): IDisposable; once(listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[]): IDisposable; } @@ -300,7 +299,7 @@ export namespace Event { return new ChainableEvent(latch(this.event)); } - on(listener: (e: T) => any, thisArgs: any, disposables: IDisposable[]) { + on(listener: (e: T) => any, thisArgs: any, disposables: IDisposable[] | DisposableStore) { return this.event(listener, thisArgs, disposables); } @@ -327,6 +326,20 @@ export namespace Event { return result.event; } + export interface DOMEventEmitter { + addEventListener(event: string | symbol, listener: Function): void; + removeEventListener(event: string | symbol, listener: Function): void; + } + + export function fromDOMEventEmitter(emitter: DOMEventEmitter, eventName: string, map: (...args: any[]) => T = id => id): Event { + const fn = (...args: any[]) => result.fire(map(...args)); + const onFirstListenerAdd = () => emitter.addEventListener(eventName, fn); + const onLastListenerRemove = () => emitter.removeEventListener(eventName, fn); + const result = new Emitter({ onFirstListenerAdd, onLastListenerRemove }); + + return result.event; + } + export function fromPromise(promise: Promise): Event { const emitter = new Emitter(); let shouldEmit = false; @@ -477,7 +490,7 @@ export class Emitter { */ get event(): Event { if (!this._event) { - this._event = (listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[]) => { + this._event = (listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore) => { if (!this._listeners) { this._listeners = new LinkedList(); } @@ -522,7 +535,9 @@ export class Emitter { } } }; - if (Array.isArray(disposables)) { + if (disposables instanceof DisposableStore) { + disposables.add(result); + } else if (Array.isArray(disposables)) { disposables.push(result); } diff --git a/src/vs/base/common/extpath.ts b/src/vs/base/common/extpath.ts index 8d664f3a6..8f47ac2cc 100644 --- a/src/vs/base/common/extpath.ts +++ b/src/vs/base/common/extpath.ts @@ -139,19 +139,22 @@ export function isUNC(path: string): boolean { } // Reference: https://en.wikipedia.org/wiki/Filename -const INVALID_FILE_CHARS = isWindows ? /[\\/:\*\?"<>\|]/g : /[\\/]/g; +const WINDOWS_INVALID_FILE_CHARS = /[\\/:\*\?"<>\|]/g; +const UNIX_INVALID_FILE_CHARS = /[\\/]/g; const WINDOWS_FORBIDDEN_NAMES = /^(con|prn|aux|clock\$|nul|lpt[0-9]|com[0-9])$/i; -export function isValidBasename(name: string | null | undefined): boolean { +export function isValidBasename(name: string | null | undefined, isWindowsOS: boolean = isWindows): boolean { + const invalidFileChars = isWindowsOS ? WINDOWS_INVALID_FILE_CHARS : UNIX_INVALID_FILE_CHARS; + if (!name || name.length === 0 || /^\s+$/.test(name)) { return false; // require a name that is not just whitespace } - INVALID_FILE_CHARS.lastIndex = 0; // the holy grail of software development - if (INVALID_FILE_CHARS.test(name)) { + invalidFileChars.lastIndex = 0; // the holy grail of software development + if (invalidFileChars.test(name)) { return false; // check for certain invalid file characters } - if (isWindows && WINDOWS_FORBIDDEN_NAMES.test(name)) { + if (isWindowsOS && WINDOWS_FORBIDDEN_NAMES.test(name)) { return false; // check for certain invalid file names } @@ -159,16 +162,16 @@ export function isValidBasename(name: string | null | undefined): boolean { return false; // check for reserved values } - if (isWindows && name[name.length - 1] === '.') { + if (isWindowsOS && name[name.length - 1] === '.') { return false; // Windows: file cannot end with a "." } - if (isWindows && name.length !== name.trim().length) { + if (isWindowsOS && name.length !== name.trim().length) { return false; // Windows: file cannot end with a whitespace } if (name.length > 255) { - return false; // most file systems do not allow files > 255 lenth + return false; // most file systems do not allow files > 255 length } return true; diff --git a/src/vs/base/common/filters.ts b/src/vs/base/common/filters.ts index 76bb974d5..d01c32668 100644 --- a/src/vs/base/common/filters.ts +++ b/src/vs/base/common/filters.ts @@ -125,7 +125,11 @@ const wordSeparators = new Set(); .forEach(s => wordSeparators.add(s.charCodeAt(0))); function isWordSeparator(code: number): boolean { - return wordSeparators.has(code); + return isWhitespace(code) || wordSeparators.has(code); +} + +function charactersMatch(codeA: number, codeB: number): boolean { + return (codeA === codeB) || (isWordSeparator(codeA) && isWordSeparator(codeB)); } function isAlphanumeric(code: number): boolean { @@ -298,7 +302,7 @@ function _matchesWords(word: string, target: string, i: number, j: number, conti return []; } else if (j === target.length) { return null; - } else if (word[i] !== target[j]) { + } else if (!charactersMatch(word.charCodeAt(i), target.charCodeAt(j))) { return null; } else { let result: IMatch[] | null = null; @@ -316,9 +320,8 @@ function _matchesWords(word: string, target: string, i: number, j: number, conti function nextWord(word: string, start: number): number { for (let i = start; i < word.length; i++) { - const c = word.charCodeAt(i); - if (isWhitespace(c) || (i > 0 && isWhitespace(word.charCodeAt(i - 1))) || - isWordSeparator(c) || (i > 0 && isWordSeparator(word.charCodeAt(i - 1)))) { + if (isWordSeparator(word.charCodeAt(i)) || + (i > 0 && isWordSeparator(word.charCodeAt(i - 1)))) { return i; } } @@ -376,6 +379,12 @@ export function anyScore(pattern: string, lowPattern: string, _patternPos: numbe score += 1; matches += 2 ** wordPos; idx = wordPos + 1; + + } else if (matches !== 0) { + // once we have started matching things + // we need to match the remaining pattern + // characters + break; } } return [score, matches, _wordPos]; @@ -405,7 +414,7 @@ export function createMatches(score: undefined | FuzzyScore): IMatch[] { return res; } -const _maxLen = 53; +const _maxLen = 128; function initTable() { const table: number[][] = []; @@ -486,7 +495,7 @@ function isUpperCaseAtPos(pos: number, word: string, wordLow: string): boolean { return word[pos] !== wordLow[pos]; } -function isPatternInWord(patternLow: string, patternPos: number, patternLen: number, wordLow: string, wordPos: number, wordLen: number): boolean { +export function isPatternInWord(patternLow: string, patternPos: number, patternLen: number, wordLow: string, wordPos: number, wordLen: number): boolean { while (patternPos < patternLen && wordPos < wordLen) { if (patternLow[patternPos] === wordLow[wordPos]) { patternPos += 1; @@ -510,7 +519,7 @@ export namespace FuzzyScore { /** * No matches and value `-100` */ - export const Default: [-100, 0, 0] = [-100, 0, 0]; + export const Default: [-100, 0, 0] = <[-100, 0, 0]>Object.freeze([-100, 0, 0]); export function isDefault(score?: FuzzyScore): score is [-100, 0, 0] { return !score || (score[0] === -100 && score[1] === 0 && score[2] === 0); diff --git a/src/vs/base/common/glob.ts b/src/vs/base/common/glob.ts index 8cc3b53ba..78fc5e97c 100644 --- a/src/vs/base/common/glob.ts +++ b/src/vs/base/common/glob.ts @@ -334,7 +334,6 @@ function wrapRelativePattern(parsedPattern: ParsedStringPattern, arg2: string | if (!extpath.isEqualOrParent(path, arg2.base)) { return null; } - return parsedPattern(paths.relative(arg2.base, path), basename); }; } @@ -458,14 +457,14 @@ export function parse(arg1: string | IExpression | IRelativePattern, options: IG if (parsedPattern === NULL) { return FALSE; } - const resultPattern = function (path: string, basename: string) { + const resultPattern: ParsedPattern & { allBasenames?: string[]; allPaths?: string[]; } = function (path: string, basename: string) { return !!parsedPattern(path, basename); }; if (parsedPattern.allBasenames) { - (resultPattern).allBasenames = parsedPattern.allBasenames; + resultPattern.allBasenames = parsedPattern.allBasenames; } if (parsedPattern.allPaths) { - (resultPattern).allPaths = parsedPattern.allPaths; + resultPattern.allPaths = parsedPattern.allPaths; } return resultPattern; } diff --git a/src/vs/base/common/htmlContent.ts b/src/vs/base/common/htmlContent.ts index 201e378e1..ac7c8ed3a 100644 --- a/src/vs/base/common/htmlContent.ts +++ b/src/vs/base/common/htmlContent.ts @@ -92,3 +92,25 @@ export function removeMarkdownEscapes(text: string): string { } return text.replace(/\\([\\`*_{}[\]()#+\-.!])/g, '$1'); } + +export function parseHrefAndDimensions(href: string): { href: string, dimensions: string[] } { + const dimensions: string[] = []; + const splitted = href.split('|').map(s => s.trim()); + href = splitted[0]; + const parameters = splitted[1]; + if (parameters) { + const heightFromParams = /height=(\d+)/.exec(parameters); + const widthFromParams = /width=(\d+)/.exec(parameters); + const height = heightFromParams ? heightFromParams[1] : ''; + const width = widthFromParams ? widthFromParams[1] : ''; + const widthIsFinite = isFinite(parseInt(width)); + const heightIsFinite = isFinite(parseInt(height)); + if (widthIsFinite) { + dimensions.push(`width="${width}"`); + } + if (heightIsFinite) { + dimensions.push(`height="${height}"`); + } + } + return { href, dimensions }; +} diff --git a/src/vs/base/common/iterator.ts b/src/vs/base/common/iterator.ts index 038bf2632..db53b8aef 100644 --- a/src/vs/base/common/iterator.ts +++ b/src/vs/base/common/iterator.ts @@ -29,6 +29,21 @@ export module Iterator { return _empty; } + export function single(value: T): Iterator { + let done = false; + + return { + next(): IteratorResult { + if (done) { + return FIN; + } + + done = true; + return { done: false, value }; + } + }; + } + export function fromArray(array: T[], index = 0, length = array.length): Iterator { return { next(): IteratorResult { @@ -86,11 +101,47 @@ export module Iterator { } } - export function collect(iterator: Iterator): T[] { + export function collect(iterator: Iterator, atMost: number = Number.POSITIVE_INFINITY): T[] { const result: T[] = []; - forEach(iterator, value => result.push(value)); + + if (atMost === 0) { + return result; + } + + let i = 0; + + for (let next = iterator.next(); !next.done; next = iterator.next()) { + result.push(next.value); + + if (++i >= atMost) { + break; + } + } + return result; } + + export function concat(...iterators: Iterator[]): Iterator { + let i = 0; + + return { + next() { + if (i >= iterators.length) { + return FIN; + } + + const iterator = iterators[i]; + const result = iterator.next(); + + if (result.done) { + i++; + return this.next(); + } + + return result; + } + }; + } } export type ISequence = Iterator | T[]; diff --git a/src/vs/base/common/json.ts b/src/vs/base/common/json.ts index b3a62ede9..da0535be4 100644 --- a/src/vs/base/common/json.ts +++ b/src/vs/base/common/json.ts @@ -374,12 +374,12 @@ export function createScanner(text: string, ignoreTrivia: boolean = false): JSON let code = text.charCodeAt(pos); // trivia: whitespace - if (isWhiteSpace(code)) { + if (isWhitespace(code)) { do { pos++; value += String.fromCharCode(code); code = text.charCodeAt(pos); - } while (isWhiteSpace(code)); + } while (isWhitespace(code)); return token = SyntaxKind.Trivia; } @@ -517,7 +517,7 @@ export function createScanner(text: string, ignoreTrivia: boolean = false): JSON } function isUnknownContentCharacter(code: CharacterCodes) { - if (isWhiteSpace(code) || isLineBreak(code)) { + if (isWhitespace(code) || isLineBreak(code)) { return false; } switch (code) { @@ -555,7 +555,7 @@ export function createScanner(text: string, ignoreTrivia: boolean = false): JSON }; } -function isWhiteSpace(ch: number): boolean { +function isWhitespace(ch: number): boolean { return ch === CharacterCodes.space || ch === CharacterCodes.tab || ch === CharacterCodes.verticalTab || ch === CharacterCodes.formFeed || ch === CharacterCodes.nonBreakingSpace || ch === CharacterCodes.ogham || ch >= CharacterCodes.enQuad && ch <= CharacterCodes.zeroWidthSpace || ch === CharacterCodes.narrowNoBreakSpace || ch === CharacterCodes.mathematicalSpace || ch === CharacterCodes.ideographicSpace || ch === CharacterCodes.byteOrderMark; diff --git a/src/vs/base/common/lifecycle.ts b/src/vs/base/common/lifecycle.ts index 512d2d122..6be438cee 100644 --- a/src/vs/base/common/lifecycle.ts +++ b/src/vs/base/common/lifecycle.ts @@ -5,6 +5,45 @@ import { once } from 'vs/base/common/functional'; +/** + * Enables logging of potentially leaked disposables. + * + * A disposable is considered leaked if it is not disposed or not registered as the child of + * another disposable. This tracking is very simple an only works for classes that either + * extend Disposable or use a DisposableStore. This means there are a lot of false positives. + */ +const TRACK_DISPOSABLES = false; + +const __is_disposable_tracked__ = '__is_disposable_tracked__'; + +function markTracked(x: T): void { + if (!TRACK_DISPOSABLES) { + return; + } + + if (x && x !== Disposable.None) { + try { + (x as any)[__is_disposable_tracked__] = true; + } catch { + // noop + } + } +} + +function trackDisposable(x: T): T { + if (!TRACK_DISPOSABLES) { + return x; + } + + const stack = new Error('Potentially leaked disposable').stack!; + setTimeout(() => { + if (!(x as any)[__is_disposable_tracked__]) { + console.log(stack); + } + }, 3000); + return x; +} + export interface IDisposable { dispose(): void; } @@ -15,56 +54,193 @@ export function isDisposable(thing: E): thing is E & IDisposab } export function dispose(disposable: T): T; -export function dispose(...disposables: Array): T[]; -export function dispose(disposables: T[]): T[]; -export function dispose(first: T | T[], ...rest: T[]): T | T[] | undefined { - if (Array.isArray(first)) { - first.forEach(d => d && d.dispose()); +export function dispose(disposable: T | undefined): T | undefined; +export function dispose(disposables: Array): Array; +export function dispose(disposables: ReadonlyArray): ReadonlyArray; +export function dispose(disposables: T | T[] | undefined): T | T[] | undefined { + if (Array.isArray(disposables)) { + disposables.forEach(d => { + if (d) { + markTracked(d); + d.dispose(); + } + }); return []; - } else if (rest.length === 0) { - if (first) { - first.dispose(); - return first; - } - return undefined; + } else if (disposables) { + markTracked(disposables); + disposables.dispose(); + return disposables; } else { - dispose(first); - dispose(rest); - return []; + return undefined; } } -export function combinedDisposable(disposables: IDisposable[]): IDisposable { - return { dispose: () => dispose(disposables) }; +export function combinedDisposable(...disposables: IDisposable[]): IDisposable { + disposables.forEach(markTracked); + return trackDisposable({ dispose: () => dispose(disposables) }); } export function toDisposable(fn: () => void): IDisposable { - return { dispose() { fn(); } }; + const self = trackDisposable({ + dispose: () => { + markTracked(self); + fn(); + } + }); + return self; +} + +export class DisposableStore implements IDisposable { + private _toDispose = new Set(); + private _isDisposed = false; + + /** + * Dispose of all registered disposables and mark this object as disposed. + * + * Any future disposables added to this object will be disposed of on `add`. + */ + public dispose(): void { + if (this._isDisposed) { + return; + } + + markTracked(this); + this._isDisposed = true; + this.clear(); + } + + /** + * Dispose of all registered disposables but do not mark this object as disposed. + */ + public clear(): void { + this._toDispose.forEach(item => item.dispose()); + this._toDispose.clear(); + } + + public add(t: T): T { + if (!t) { + return t; + } + if ((t as any as DisposableStore) === this) { + throw new Error('Cannot register a disposable on itself!'); + } + + markTracked(t); + if (this._isDisposed) { + console.warn(new Error('Registering disposable on object that has already been disposed of').stack); + t.dispose(); + } else { + this._toDispose.add(t); + } + + return t; + } } export abstract class Disposable implements IDisposable { static None = Object.freeze({ dispose() { } }); - protected _toDispose: IDisposable[] = []; - protected get toDispose(): IDisposable[] { return this._toDispose; } + private readonly _store = new DisposableStore(); - private _lifecycle_disposable_isDisposed = false; + constructor() { + trackDisposable(this); + } public dispose(): void { - this._lifecycle_disposable_isDisposed = true; - this._toDispose = dispose(this._toDispose); + markTracked(this); + + this._store.dispose(); } protected _register(t: T): T { - if (this._lifecycle_disposable_isDisposed) { - console.warn('Registering disposable on object that has already been disposed.'); - t.dispose(); - } else { - this._toDispose.push(t); + if ((t as any as Disposable) === this) { + throw new Error('Cannot register a disposable on itself!'); } + return this._store.add(t); + } +} - return t; +/** + * Manages the lifecycle of a disposable value that may be changed. + * + * This ensures that when the the disposable value is changed, the previously held disposable is disposed of. You can + * also register a `MutableDisposable` on a `Disposable` to ensure it is automatically cleaned up. + */ +export class MutableDisposable implements IDisposable { + private _value?: T; + private _isDisposed = false; + + constructor() { + trackDisposable(this); + } + + get value(): T | undefined { + return this._isDisposed ? undefined : this._value; + } + + set value(value: T | undefined) { + if (this._isDisposed || value === this._value) { + return; + } + + if (this._value) { + this._value.dispose(); + } + if (value) { + markTracked(value); + } + this._value = value; + } + + clear() { + this.value = undefined; + } + + dispose(): void { + this._isDisposed = true; + markTracked(this); + if (this._value) { + this._value.dispose(); + } + this._value = undefined; + } +} + +/** + * Wrapper class that stores a disposable that is not currently "owned" by anyone. + * + * Example use cases: + * + * - Express that a function/method will take ownership of a disposable parameter. + * - Express that a function returns a disposable that the caller must explicitly take ownership of. + */ +export class UnownedDisposable extends Disposable { + private _hasBeenAcquired = false; + private _value?: T; + + public constructor(value: T) { + super(); + this._value = value; + } + + public acquire(): T { + if (this._hasBeenAcquired) { + throw new Error('This disposable has already been acquired'); + } + this._hasBeenAcquired = true; + const value = this._value!; + this._value = undefined; + return value; + } + + public dispose() { + super.dispose(); + if (!this._hasBeenAcquired) { + this._hasBeenAcquired = true; + this._value!.dispose(); + this._value = undefined; + } } } @@ -74,22 +250,21 @@ export interface IReference extends IDisposable { export abstract class ReferenceCollection { - private references: { [key: string]: { readonly object: T; counter: number; } } = Object.create(null); - - constructor() { } + private readonly references: Map = new Map(); acquire(key: string): IReference { - let reference = this.references[key]; + let reference = this.references.get(key); if (!reference) { - reference = this.references[key] = { counter: 0, object: this.createReferencedObject(key) }; + reference = { counter: 0, object: this.createReferencedObject(key) }; + this.references.set(key, reference); } const { object } = reference; const dispose = once(() => { - if (--reference.counter === 0) { - this.destroyReferencedObject(key, reference.object); - delete this.references[key]; + if (--reference!.counter === 0) { + this.destroyReferencedObject(key, reference!.object); + this.references.delete(key); } }); diff --git a/src/vs/base/common/mime.ts b/src/vs/base/common/mime.ts index de19c7c03..d9451a64d 100644 --- a/src/vs/base/common/mime.ts +++ b/src/vs/base/common/mime.ts @@ -7,6 +7,9 @@ import { basename, posix, extname } from 'vs/base/common/path'; import { endsWith, startsWithUTF8BOM, startsWith } from 'vs/base/common/strings'; import { coalesce } from 'vs/base/common/arrays'; import { match } from 'vs/base/common/glob'; +import { URI } from 'vs/base/common/uri'; +import { Schemas } from 'vs/base/common/network'; +import { DataUri } from 'vs/base/common/resources'; export const MIME_TEXT = 'text/plain'; export const MIME_BINARY = 'application/octet-stream'; @@ -106,12 +109,28 @@ export function clearTextMimes(onlyUserConfigured?: boolean): void { /** * Given a file, return the best matching mime type for it */ -export function guessMimeTypes(path: string | null, firstLine?: string): string[] { +export function guessMimeTypes(resource: URI | null, firstLine?: string): string[] { + let path: string | undefined; + if (resource) { + switch (resource.scheme) { + case Schemas.file: + path = resource.fsPath; + break; + case Schemas.data: + const metadata = DataUri.parseMetaData(resource); + path = metadata.get(DataUri.META_DATA_LABEL); + break; + default: + path = resource.path; + } + } + if (!path) { return [MIME_UNKNOWN]; } path = path.toLowerCase(); + const filename = basename(path); // 1.) User configured mappings have highest priority @@ -197,7 +216,11 @@ function guessMimeTypeByFirstline(firstLine: string): string | null { } if (firstLine.length > 0) { - for (const association of registeredAssociations) { + + // We want to prioritize associations based on the order they are registered so that the last registered + // association wins over all other. This is for https://github.com/Microsoft/vscode/issues/20074 + for (let i = registeredAssociations.length - 1; i >= 0; i--) { + const association = registeredAssociations[i]; if (!association.firstline) { continue; } @@ -230,10 +253,11 @@ export function isUnspecific(mime: string[] | string): boolean { * 2. Otherwise, if there are other extensions, suggest the first one. * 3. Otherwise, suggest the prefix. */ -export function suggestFilename(langId: string | null, prefix: string): string { +export function suggestFilename(mode: string | undefined, prefix: string): string { const extensions = registeredAssociations - .filter(assoc => !assoc.userConfigured && assoc.extension && assoc.id === langId) + .filter(assoc => !assoc.userConfigured && assoc.extension && assoc.id === mode) .map(assoc => assoc.extension); + const extensionsWithDotFirst = coalesce(extensions) .filter(assoc => startsWith(assoc, '.')); @@ -250,52 +274,54 @@ interface MapExtToMediaMimes { // Known media mimes that we can handle const mapExtToMediaMimes: MapExtToMediaMimes = { + '.aac': 'audio/x-aac', + '.avi': 'video/x-msvideo', '.bmp': 'image/bmp', + '.flv': 'video/x-flv', '.gif': 'image/gif', - '.jpg': 'image/jpg', - '.jpeg': 'image/jpg', - '.jpe': 'image/jpg', - '.png': 'image/png', - '.tiff': 'image/tiff', - '.tif': 'image/tiff', '.ico': 'image/x-icon', - '.tga': 'image/x-tga', - '.psd': 'image/vnd.adobe.photoshop', - '.webp': 'image/webp', + '.jpe': 'image/jpg', + '.jpeg': 'image/jpg', + '.jpg': 'image/jpg', + '.m1v': 'video/mpeg', + '.m2a': 'audio/mpeg', + '.m2v': 'video/mpeg', + '.m3a': 'audio/mpeg', '.mid': 'audio/midi', '.midi': 'audio/midi', - '.mp4a': 'audio/mp4', - '.mpga': 'audio/mpeg', + '.mk3d': 'video/x-matroska', + '.mks': 'video/x-matroska', + '.mkv': 'video/x-matroska', + '.mov': 'video/quicktime', + '.movie': 'video/x-sgi-movie', '.mp2': 'audio/mpeg', '.mp2a': 'audio/mpeg', '.mp3': 'audio/mpeg', - '.m2a': 'audio/mpeg', - '.m3a': 'audio/mpeg', - '.oga': 'audio/ogg', - '.ogg': 'audio/ogg', - '.spx': 'audio/ogg', - '.aac': 'audio/x-aac', - '.wav': 'audio/x-wav', - '.wma': 'audio/x-ms-wma', '.mp4': 'video/mp4', + '.mp4a': 'audio/mp4', '.mp4v': 'video/mp4', - '.mpg4': 'video/mp4', + '.mpe': 'video/mpeg', '.mpeg': 'video/mpeg', '.mpg': 'video/mpeg', - '.mpe': 'video/mpeg', - '.m1v': 'video/mpeg', - '.m2v': 'video/mpeg', + '.mpg4': 'video/mp4', + '.mpga': 'audio/mpeg', + '.oga': 'audio/ogg', + '.ogg': 'audio/ogg', '.ogv': 'video/ogg', + '.png': 'image/png', + '.psd': 'image/vnd.adobe.photoshop', '.qt': 'video/quicktime', - '.mov': 'video/quicktime', + '.spx': 'audio/ogg', + '.svg': 'image/svg+xml', + '.tga': 'image/x-tga', + '.tif': 'image/tiff', + '.tiff': 'image/tiff', + '.wav': 'audio/x-wav', '.webm': 'video/webm', - '.mkv': 'video/x-matroska', - '.mk3d': 'video/x-matroska', - '.mks': 'video/x-matroska', + '.webp': 'image/webp', + '.wma': 'audio/x-ms-wma', '.wmv': 'video/x-ms-wmv', - '.flv': 'video/x-flv', - '.avi': 'video/x-msvideo', - '.movie': 'video/x-sgi-movie' + '.woff': 'application/font-woff', }; export function getMediaMime(path: string): string | undefined { diff --git a/src/vs/base/common/network.ts b/src/vs/base/common/network.ts index a7466e641..46d2933a0 100644 --- a/src/vs/base/common/network.ts +++ b/src/vs/base/common/network.ts @@ -46,4 +46,6 @@ export namespace Schemas { export const command: string = 'command'; export const vscodeRemote: string = 'vscode-remote'; + + export const userData: string = 'vscode-userdata'; } diff --git a/src/vs/base/common/objects.ts b/src/vs/base/common/objects.ts index 661863eb2..1475bf4a5 100644 --- a/src/vs/base/common/objects.ts +++ b/src/vs/base/common/objects.ts @@ -14,11 +14,11 @@ export function deepClone(obj: T): T { return obj as any; } const result: any = Array.isArray(obj) ? [] : {}; - Object.keys(obj).forEach((key: string) => { - if (obj[key] && typeof obj[key] === 'object') { - result[key] = deepClone(obj[key]); + Object.keys(obj).forEach((key: string) => { + if ((obj)[key] && typeof (obj)[key] === 'object') { + result[key] = deepClone((obj)[key]); } else { - result[key] = obj[key]; + result[key] = (obj)[key]; } }); return result; diff --git a/src/vs/base/common/parsers.ts b/src/vs/base/common/parsers.ts index 4ea4e9537..125b965f5 100644 --- a/src/vs/base/common/parsers.ts +++ b/src/vs/base/common/parsers.ts @@ -3,8 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as Types from 'vs/base/common/types'; - export const enum ValidationState { OK = 0, Info = 1, @@ -78,25 +76,4 @@ export abstract class Parser { public fatal(message: string): void { this._problemReporter.fatal(message); } - - protected static merge(destination: T, source: T, overwrite: boolean): void { - Object.keys(source).forEach((key: string) => { - const destValue = destination[key]; - const sourceValue = source[key]; - if (Types.isUndefined(sourceValue)) { - return; - } - if (Types.isUndefined(destValue)) { - destination[key] = sourceValue; - } else { - if (overwrite) { - if (Types.isObject(destValue) && Types.isObject(sourceValue)) { - this.merge(destValue, sourceValue, overwrite); - } else { - destination[key] = sourceValue; - } - } - } - }); - } } \ No newline at end of file diff --git a/src/vs/base/common/path.ts b/src/vs/base/common/path.ts index 029bfc016..c85323472 100644 --- a/src/vs/base/common/path.ts +++ b/src/vs/base/common/path.ts @@ -212,7 +212,7 @@ export const win32: IPath = { // absolute path, get cwd for that drive, or the process cwd if // the drive cwd is not available. We're sure the device is not // a UNC path at this points, because UNC paths are always absolute. - path = process.env['=' + resolvedDevice] || process.cwd(); + path = (process.env as any)['=' + resolvedDevice] || process.cwd(); // Verify that a cwd was found and that it actually points // to our drive. If not, default to the drive's root. diff --git a/src/vs/base/common/platform.ts b/src/vs/base/common/platform.ts index 4cba839fe..d7371552d 100644 --- a/src/vs/base/common/platform.ts +++ b/src/vs/base/common/platform.ts @@ -13,6 +13,7 @@ let _isWeb = false; let _locale: string | undefined = undefined; let _language: string = LANGUAGE_DEFAULT; let _translationsConfigFile: string | undefined = undefined; +let _userAgent: string | undefined = undefined; interface NLSConfig { locale: string; @@ -48,10 +49,10 @@ const isElectronRenderer = (typeof process !== 'undefined' && typeof process.ver // OS detection if (typeof navigator === 'object' && !isElectronRenderer) { - const userAgent = navigator.userAgent; - _isWindows = userAgent.indexOf('Windows') >= 0; - _isMacintosh = userAgent.indexOf('Macintosh') >= 0; - _isLinux = userAgent.indexOf('Linux') >= 0; + _userAgent = navigator.userAgent; + _isWindows = _userAgent.indexOf('Windows') >= 0; + _isMacintosh = _userAgent.indexOf('Macintosh') >= 0; + _isLinux = _userAgent.indexOf('Linux') >= 0; _isWeb = true; _locale = navigator.language; _language = _locale; @@ -108,6 +109,7 @@ export const isLinux = _isLinux; export const isNative = _isNative; export const isWeb = _isWeb; export const platform = _platform; +export const userAgent = _userAgent; export function isRootUser(): boolean { return _isNative && !_isWindows && (process.getuid() === 0); diff --git a/src/vs/base/common/resources.ts b/src/vs/base/common/resources.ts index 40095c3aa..8ccc95677 100644 --- a/src/vs/base/common/resources.ts +++ b/src/vs/base/common/resources.ts @@ -176,34 +176,52 @@ export function isAbsolutePath(resource: URI): boolean { /** * Returns true if the URI path has a trailing path separator */ -export function hasTrailingPathSeparator(resource: URI): boolean { +export function hasTrailingPathSeparator(resource: URI, sep: string = paths.sep): boolean { if (resource.scheme === Schemas.file) { const fsp = originalFSPath(resource); - return fsp.length > extpath.getRoot(fsp).length && fsp[fsp.length - 1] === paths.sep; + return fsp.length > extpath.getRoot(fsp).length && fsp[fsp.length - 1] === sep; } else { const p = resource.path; return p.length > 1 && p.charCodeAt(p.length - 1) === CharCode.Slash; // ignore the slash at offset 0 } } - /** - * Removes a trailing path seperator, if theres one. + * Removes a trailing path separator, if there's one. * Important: Doesn't remove the first slash, it would make the URI invalid */ -export function removeTrailingPathSeparator(resource: URI): URI { - if (hasTrailingPathSeparator(resource)) { +export function removeTrailingPathSeparator(resource: URI, sep: string = paths.sep): URI { + if (hasTrailingPathSeparator(resource, sep)) { return resource.with({ path: resource.path.substr(0, resource.path.length - 1) }); } return resource; } +/** + * Adds a trailing path separator to the URI if there isn't one already. + * For example, c:\ would be unchanged, but c:\users would become c:\users\ + */ +export function addTrailingPathSeparator(resource: URI, sep: string = paths.sep): URI { + let isRootSep: boolean = false; + if (resource.scheme === Schemas.file) { + const fsp = originalFSPath(resource); + isRootSep = ((fsp !== undefined) && (fsp.length === extpath.getRoot(fsp).length) && (fsp[fsp.length - 1] === sep)); + } else { + sep = '/'; + const p = resource.path; + isRootSep = p.length === 1 && p.charCodeAt(p.length - 1) === CharCode.Slash; + } + if (!isRootSep && !hasTrailingPathSeparator(resource, sep)) { + return resource.with({ path: resource.path + '/' }); + } + return resource; +} /** * Returns a relative path between two URIs. If the URIs don't have the same schema or authority, `undefined` is returned. * The returned relative path always uses forward slashes. */ -export function relativePath(from: URI, to: URI): string | undefined { +export function relativePath(from: URI, to: URI, ignoreCase = hasToIgnoreCase(from)): string | undefined { if (from.scheme !== to.scheme || !isEqualAuthority(from.authority, to.authority)) { return undefined; } @@ -211,7 +229,20 @@ export function relativePath(from: URI, to: URI): string | undefined { const relativePath = paths.relative(from.path, to.path); return isWindows ? extpath.toSlashes(relativePath) : relativePath; } - return paths.posix.relative(from.path || '/', to.path || '/'); + let fromPath = from.path || '/', toPath = to.path || '/'; + if (ignoreCase) { + // make casing of fromPath match toPath + let i = 0; + for (const len = Math.min(fromPath.length, toPath.length); i < len; i++) { + if (fromPath.charCodeAt(i) !== toPath.charCodeAt(i)) { + if (fromPath.charAt(i).toLowerCase() !== toPath.charAt(i).toLowerCase()) { + break; + } + } + } + fromPath = toPath.substr(0, i) + fromPath.substr(i); + } + return paths.posix.relative(fromPath, toPath); } /** diff --git a/src/vs/base/common/strings.ts b/src/vs/base/common/strings.ts index 37c57c26f..d4397d327 100644 --- a/src/vs/base/common/strings.ts +++ b/src/vs/base/common/strings.ts @@ -233,7 +233,7 @@ export function regExpLeadsToEndlessLoop(regexp: RegExp): boolean { // We check against an empty string. If the regular expression doesn't advance // (e.g. ends in an endless loop) it will match an empty string. const match = regexp.exec(''); - return !!(match && regexp.lastIndex === 0); + return !!(match && regexp.lastIndex === 0); } export function regExpContainsBackreference(regexpValue: string): boolean { diff --git a/src/vs/base/common/types.ts b/src/vs/base/common/types.ts index c3e24cc0a..56d365091 100644 --- a/src/vs/base/common/types.ts +++ b/src/vs/base/common/types.ts @@ -169,6 +169,31 @@ export function getAllPropertyNames(obj: object): string[] { return res; } +export function getAllMethodNames(obj: object): string[] { + const methods: string[] = []; + for (const prop of getAllPropertyNames(obj)) { + if (typeof (obj as any)[prop] === 'function') { + methods.push(prop); + } + } + return methods; +} + +export function createProxyObject(methodNames: string[], invoke: (method: string, args: any[]) => any): T { + const createProxyMethod = (method: string): () => any => { + return function () { + const args = Array.prototype.slice.call(arguments, 0); + return invoke(method, args); + }; + }; + + let result = {} as T; + for (const methodName of methodNames) { + (result)[methodName] = createProxyMethod(methodName); + } + return result; +} + /** * Converts null to undefined, passes all other values through. */ diff --git a/src/vs/base/common/uri.ts b/src/vs/base/common/uri.ts index ec6497ef0..966555e04 100644 --- a/src/vs/base/common/uri.ts +++ b/src/vs/base/common/uri.ts @@ -384,8 +384,8 @@ export class URI implements UriComponents { return data; } else { const result = new _URI(data); - result._fsPath = (data).fsPath; result._formatted = (data).external; + result._fsPath = (data)._sep === _pathSepMarker ? (data).fsPath : null; return result; } } @@ -401,10 +401,12 @@ export interface UriComponents { interface UriState extends UriComponents { $mid: number; - fsPath: string; external: string; + fsPath: string; + _sep: 1 | undefined; } +const _pathSepMarker = isWindows ? 1 : undefined; // tslint:disable-next-line:class-name class _URI extends URI { @@ -438,6 +440,7 @@ class _URI extends URI { // cached state if (this._fsPath) { res.fsPath = this._fsPath; + res._sep = _pathSepMarker; } if (this._formatted) { res.external = this._formatted; diff --git a/src/vs/base/common/uriIpc.ts b/src/vs/base/common/uriIpc.ts index 4cee99c11..ef2291d49 100644 --- a/src/vs/base/common/uriIpc.ts +++ b/src/vs/base/common/uriIpc.ts @@ -10,6 +10,51 @@ export interface IURITransformer { transformIncoming(uri: UriComponents): UriComponents; transformOutgoing(uri: UriComponents): UriComponents; transformOutgoingURI(uri: URI): URI; + transformOutgoingScheme(scheme: string): string; +} + +export interface UriParts { + scheme: string; + authority?: string; + path?: string; +} + +export interface IRawURITransformer { + transformIncoming(uri: UriParts): UriParts; + transformOutgoing(uri: UriParts): UriParts; + transformOutgoingScheme(scheme: string): string; +} + +function toJSON(uri: URI): UriComponents { + return uri.toJSON(); +} + +export class URITransformer implements IURITransformer { + + private readonly _uriTransformer: IRawURITransformer; + + constructor(uriTransformer: IRawURITransformer) { + this._uriTransformer = uriTransformer; + } + + public transformIncoming(uri: UriComponents): UriComponents { + const result = this._uriTransformer.transformIncoming(uri); + return (result === uri ? uri : toJSON(URI.from(result))); + } + + public transformOutgoing(uri: UriComponents): UriComponents { + const result = this._uriTransformer.transformOutgoing(uri); + return (result === uri ? uri : toJSON(URI.from(result))); + } + + public transformOutgoingURI(uri: URI): URI { + const result = this._uriTransformer.transformOutgoing(uri); + return (result === uri ? uri : URI.from(result)); + } + + public transformOutgoingScheme(scheme: string): string { + return this._uriTransformer.transformOutgoingScheme(scheme); + } } export const DefaultURITransformer: IURITransformer = new class { @@ -24,6 +69,10 @@ export const DefaultURITransformer: IURITransformer = new class { transformOutgoingURI(uri: URI): URI { return uri; } + + transformOutgoingScheme(scheme: string): string { + return scheme; + } }; function _transformOutgoingURIs(obj: any, transformer: IURITransformer, depth: number): any { diff --git a/src/vs/base/common/worker/simpleWorker.ts b/src/vs/base/common/worker/simpleWorker.ts index fa19fff26..2cc1b188c 100644 --- a/src/vs/base/common/worker/simpleWorker.ts +++ b/src/vs/base/common/worker/simpleWorker.ts @@ -4,16 +4,15 @@ *--------------------------------------------------------------------------------------------*/ import { transformErrorForSerialization } from 'vs/base/common/errors'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { isWeb } from 'vs/base/common/platform'; -import { getAllPropertyNames } from 'vs/base/common/types'; +import * as types from 'vs/base/common/types'; const INITIALIZE = '$initialize'; -export interface IWorker { +export interface IWorker extends IDisposable { getId(): number; - postMessage(message: string): void; - dispose(): void; + postMessage(message: any, transfer: Transferable[]): void; } export interface IWorkerCallback { @@ -61,7 +60,7 @@ interface IMessageReply { } interface IMessageHandler { - sendMessage(msg: string): void; + sendMessage(msg: any, transfer?: ArrayBuffer[]): void; handleMessage(method: string, args: any[]): Promise; } @@ -99,14 +98,7 @@ class SimpleWorkerProtocol { }); } - public handleMessage(serializedMessage: string): void { - let message: IMessage; - try { - message = JSON.parse(serializedMessage); - } catch (e) { - // nothing - return; - } + public handleMessage(message: IMessage): void { if (!message || !message.vsWorker) { return; } @@ -168,30 +160,47 @@ class SimpleWorkerProtocol { } private _send(msg: IRequestMessage | IReplyMessage): void { - let strMsg = JSON.stringify(msg); - // console.log('SENDING: ' + strMsg); - this._handler.sendMessage(strMsg); + let transfer: ArrayBuffer[] = []; + if (msg.req) { + const m = msg; + for (let i = 0; i < m.args.length; i++) { + if (m.args[i] instanceof ArrayBuffer) { + transfer.push(m.args[i]); + } + } + } else { + const m = msg; + if (m.res instanceof ArrayBuffer) { + transfer.push(m.res); + } + } + this._handler.sendMessage(msg, transfer); } } +export interface IWorkerClient { + getProxyObject(): Promise; + dispose(): void; +} + /** * Main thread side */ -export class SimpleWorkerClient extends Disposable { +export class SimpleWorkerClient extends Disposable implements IWorkerClient { - private _worker: IWorker; - private _onModuleLoaded: Promise; - private _protocol: SimpleWorkerProtocol; - private _lazyProxy: Promise; + private readonly _worker: IWorker; + private readonly _onModuleLoaded: Promise; + private readonly _protocol: SimpleWorkerProtocol; + private readonly _lazyProxy: Promise; - constructor(workerFactory: IWorkerFactory, moduleId: string) { + constructor(workerFactory: IWorkerFactory, moduleId: string, host: H) { super(); let lazyProxyReject: ((err: any) => void) | null = null; this._worker = this._register(workerFactory.create( 'vs/base/common/worker/simpleWorker', - (msg: string) => { + (msg: any) => { this._protocol.handleMessage(msg); }, (err: any) => { @@ -204,12 +213,19 @@ export class SimpleWorkerClient extends Disposable { )); this._protocol = new SimpleWorkerProtocol({ - sendMessage: (msg: string): void => { - this._worker.postMessage(msg); + sendMessage: (msg: any, transfer: ArrayBuffer[]): void => { + this._worker.postMessage(msg, transfer); }, handleMessage: (method: string, args: any[]): Promise => { - // Intentionally not supporting worker -> main requests - return Promise.resolve(null); + if (typeof (host as any)[method] !== 'function') { + return Promise.reject(new Error('Missing method ' + method + ' on main thread host.')); + } + + try { + return Promise.resolve((host as any)[method].apply(host, args)); + } catch (e) { + return Promise.reject(e); + } } }); this._protocol.setWorkerId(this._worker.getId()); @@ -224,41 +240,33 @@ export class SimpleWorkerClient extends Disposable { loaderConfiguration = (self).requirejs.s.contexts._.config; } + const hostMethods = types.getAllMethodNames(host); + // Send initialize message this._onModuleLoaded = this._protocol.sendMessage(INITIALIZE, [ this._worker.getId(), + JSON.parse(JSON.stringify(loaderConfiguration)), moduleId, - loaderConfiguration + hostMethods, ]); - this._lazyProxy = new Promise((resolve, reject) => { + // Create proxy to loaded code + const proxyMethodRequest = (method: string, args: any[]): Promise => { + return this._request(method, args); + }; + + this._lazyProxy = new Promise((resolve, reject) => { lazyProxyReject = reject; this._onModuleLoaded.then((availableMethods: string[]) => { - let proxy = {}; - for (const methodName of availableMethods) { - (proxy as any)[methodName] = createProxyMethod(methodName, proxyMethodRequest); - } - resolve(proxy); + resolve(types.createProxyObject(availableMethods, proxyMethodRequest)); }, (e) => { reject(e); this._onError('Worker failed to load ' + moduleId, e); }); }); - - // Create proxy to loaded code - const proxyMethodRequest = (method: string, args: any[]): Promise => { - return this._request(method, args); - }; - - const createProxyMethod = (method: string, proxyMethodRequest: (method: string, args: any[]) => Promise): () => Promise => { - return function () { - let args = Array.prototype.slice.call(arguments, 0); - return proxyMethodRequest(method, args); - }; - }; } - public getProxyObject(): Promise { + public getProxyObject(): Promise { return this._lazyProxy; } @@ -281,31 +289,37 @@ export interface IRequestHandler { [prop: string]: any; } +export interface IRequestHandlerFactory { + (host: H): IRequestHandler; +} + /** * Worker side */ -export class SimpleWorkerServer { +export class SimpleWorkerServer { + private _requestHandlerFactory: IRequestHandlerFactory | null; private _requestHandler: IRequestHandler | null; private _protocol: SimpleWorkerProtocol; - constructor(postSerializedMessage: (msg: string) => void, requestHandler: IRequestHandler | null) { - this._requestHandler = requestHandler; + constructor(postMessage: (msg: any, transfer?: Transferable[]) => void, requestHandlerFactory: IRequestHandlerFactory | null) { + this._requestHandlerFactory = requestHandlerFactory; + this._requestHandler = null; this._protocol = new SimpleWorkerProtocol({ - sendMessage: (msg: string): void => { - postSerializedMessage(msg); + sendMessage: (msg: any, transfer: ArrayBuffer[]): void => { + postMessage(msg, transfer); }, handleMessage: (method: string, args: any[]): Promise => this._handleMessage(method, args) }); } - public onmessage(msg: string): void { + public onmessage(msg: any): void { this._protocol.handleMessage(msg); } private _handleMessage(method: string, args: any[]): Promise { if (method === INITIALIZE) { - return this.initialize(args[0], args[1], args[2]); + return this.initialize(args[0], args[1], args[2], args[3]); } if (!this._requestHandler || typeof this._requestHandler[method] !== 'function') { @@ -319,18 +333,19 @@ export class SimpleWorkerServer { } } - private initialize(workerId: number, moduleId: string, loaderConfig: any): Promise { + private initialize(workerId: number, loaderConfig: any, moduleId: string, hostMethods: string[]): Promise { this._protocol.setWorkerId(workerId); - if (this._requestHandler) { + const proxyMethodRequest = (method: string, args: any[]): Promise => { + return this._protocol.sendMessage(method, args); + }; + + const hostProxy = types.createProxyObject(hostMethods, proxyMethodRequest); + + if (this._requestHandlerFactory) { // static request handler - let methods: string[] = []; - for (const prop of getAllPropertyNames(this._requestHandler)) { - if (typeof this._requestHandler[prop] === 'function') { - methods.push(prop); - } - } - return Promise.resolve(methods); + this._requestHandler = this._requestHandlerFactory(hostProxy); + return Promise.resolve(types.getAllMethodNames(this._requestHandler)); } if (loaderConfig) { @@ -351,23 +366,15 @@ export class SimpleWorkerServer { return new Promise((resolve, reject) => { // Use the global require to be sure to get the global config - (self).require([moduleId], (...result: any[]) => { - let handlerModule = result[0]; - this._requestHandler = handlerModule.create(); + (self).require([moduleId], (module: { create: IRequestHandlerFactory }) => { + this._requestHandler = module.create(hostProxy); if (!this._requestHandler) { reject(new Error(`No RequestHandler!`)); return; } - let methods: string[] = []; - for (const prop of getAllPropertyNames(this._requestHandler)) { - if (typeof this._requestHandler[prop] === 'function') { - methods.push(prop); - } - } - - resolve(methods); + resolve(types.getAllMethodNames(this._requestHandler)); }, reject); }); } @@ -376,6 +383,6 @@ export class SimpleWorkerServer { /** * Called on the worker side */ -export function create(postMessage: (msg: string) => void): SimpleWorkerServer { +export function create(postMessage: (msg: string) => void): SimpleWorkerServer { return new SimpleWorkerServer(postMessage, null); } diff --git a/src/vs/base/node/config.ts b/src/vs/base/node/config.ts index 0b5785377..4e12fd565 100644 --- a/src/vs/base/node/config.ts +++ b/src/vs/base/node/config.ts @@ -6,10 +6,11 @@ import * as fs from 'fs'; import { dirname } from 'vs/base/common/path'; import * as objects from 'vs/base/common/objects'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { Disposable } from 'vs/base/common/lifecycle'; import { Event, Emitter } from 'vs/base/common/event'; import * as json from 'vs/base/common/json'; -import { readlink, statLink } from 'vs/base/node/pfs'; +import { statLink } from 'vs/base/node/pfs'; +import { realpath } from 'vs/base/node/extpath'; import { watchFolder, watchFile } from 'vs/base/node/watcher'; export interface IConfigurationChangeEvent { @@ -40,20 +41,17 @@ export interface IConfigOptions { * - delayed processing of changes to accomodate for lots of changes * - configurable defaults */ -export class ConfigWatcher implements IConfigWatcher, IDisposable { +export class ConfigWatcher extends Disposable implements IConfigWatcher { private cache: T; private parseErrors: json.ParseError[]; private disposed: boolean; private loaded: boolean; private timeoutHandle: NodeJS.Timer | null; - private disposables: IDisposable[]; private readonly _onDidUpdateConfiguration: Emitter>; constructor(private _path: string, private options: IConfigOptions = { defaultConfig: Object.create(null), onError: error => console.error(error) }) { - this.disposables = []; - - this._onDidUpdateConfiguration = new Emitter>(); - this.disposables.push(this._onDidUpdateConfiguration); + super(); + this._onDidUpdateConfiguration = this._register(new Emitter>()); this.registerWatcher(); this.initAsync(); @@ -110,10 +108,10 @@ export class ConfigWatcher implements IConfigWatcher, IDisposable { try { this.parseErrors = []; res = this.options.parse ? this.options.parse(raw, this.parseErrors) : json.parse(raw, this.parseErrors); + return res || this.options.defaultConfig; } catch (error) { - // Ignore parsing errors - return this.options.defaultConfig; + return this.options.defaultConfig; // Ignore parsing errors } } @@ -124,13 +122,13 @@ export class ConfigWatcher implements IConfigWatcher, IDisposable { this.watch(parentFolder, true); // Check if the path is a symlink and watch its target if so - this.handleSymbolicLink().then(undefined, error => { /* ignore error */ }); + this.handleSymbolicLink().then(undefined, () => { /* ignore error */ }); } private async handleSymbolicLink(): Promise { const { stat, isSymbolicLink } = await statLink(this._path); if (isSymbolicLink && !stat.isDirectory()) { - const realPath = await readlink(this._path); + const realPath = await realpath(this._path); this.watch(realPath, false); } @@ -142,9 +140,9 @@ export class ConfigWatcher implements IConfigWatcher, IDisposable { } if (isFolder) { - this.disposables.push(watchFolder(path, (type, path) => path === this._path ? this.onConfigFileChange() : undefined, error => this.options.onError(error))); + this._register(watchFolder(path, (type, path) => path === this._path ? this.onConfigFileChange() : undefined, error => this.options.onError(error))); } else { - this.disposables.push(watchFile(path, (type, path) => this.onConfigFileChange(), error => this.options.onError(error))); + this._register(watchFile(path, () => this.onConfigFileChange(), error => this.options.onError(error))); } } @@ -186,6 +184,6 @@ export class ConfigWatcher implements IConfigWatcher, IDisposable { dispose(): void { this.disposed = true; - this.disposables = dispose(this.disposables); + super.dispose(); } } \ No newline at end of file diff --git a/src/vs/base/node/cpuUsage.sh b/src/vs/base/node/cpuUsage.sh index 3d42b36dc..8e07feffa 100755 --- a/src/vs/base/node/cpuUsage.sh +++ b/src/vs/base/node/cpuUsage.sh @@ -30,7 +30,7 @@ for PID in "$@"; do fi PROCESS_BEFORE_TIMES[$ITER]=$PROCESS_TIME_BEFORE - ((ITER++)) + ((++ITER)) done # Wait for a second @@ -60,5 +60,5 @@ for PID in "$@"; do # Parent script reads from stdout, so echo result to be read echo $CPU_USAGE - ((ITER++)) + ((++ITER)) done diff --git a/src/vs/base/node/encoding.ts b/src/vs/base/node/encoding.ts index 9b04d9f0a..8e23d0ade 100644 --- a/src/vs/base/node/encoding.ts +++ b/src/vs/base/node/encoding.ts @@ -395,7 +395,7 @@ export async function resolveTerminalEncoding(verbose?: boolean): Promise { if (stdout) { - const windowsTerminalEncodingKeys = Object.keys(windowsTerminalEncodings); + const windowsTerminalEncodingKeys = Object.keys(windowsTerminalEncodings) as Array; for (const key of windowsTerminalEncodingKeys) { if (stdout.indexOf(key) >= 0) { return resolve(windowsTerminalEncodings[key]); diff --git a/src/vs/base/node/id.ts b/src/vs/base/node/id.ts index d8f617df4..c2faa2063 100644 --- a/src/vs/base/node/id.ts +++ b/src/vs/base/node/id.ts @@ -7,11 +7,12 @@ import * as errors from 'vs/base/common/errors'; import * as uuid from 'vs/base/common/uuid'; import { networkInterfaces } from 'os'; import { TernarySearchTree } from 'vs/base/common/map'; +import { getMac } from 'vs/base/node/macAddress'; // http://www.techrepublic.com/blog/data-center/mac-address-scorecard-for-common-virtual-machine-platforms/ // VMware ESX 3, Server, Workstation, Player 00-50-56, 00-0C-29, 00-05-69 // Microsoft Hyper-V, Virtual Server, Virtual PC 00-03-FF -// Parallells Desktop, Workstation, Server, Virtuozzo 00-1C-42 +// Parallels Desktop, Workstation, Server, Virtuozzo 00-1C-42 // Virtual Iron 4 00-0F-4B // Red Hat Xen 00-16-3E // Oracle VM 00-16-3E @@ -76,35 +77,25 @@ export const virtualMachineHint: { value(): number } = new class { }; let machineId: Promise; -export function getMachineId(): Promise { - return machineId || (machineId = getMacMachineId() - .then(id => id || uuid.generateUuid())); // fallback, generate a UUID -} +export async function getMachineId(): Promise { + if (!machineId) { + machineId = (async () => { + const id = await getMacMachineId(); -function getMacMachineId(): Promise { - return new Promise(resolve => { - Promise.all([import('crypto'), import('getmac')]).then(([crypto, getmac]) => { - try { - getmac.getMac((error, macAddress) => { - if (!error) { - resolve(crypto.createHash('sha256').update(macAddress, 'utf8').digest('hex')); - } else { - resolve(undefined); - } - }); + return id || uuid.generateUuid(); // fallback, generate a UUID + })(); + } - // Timeout due to hang with reduced privileges #58392 - // TODO@sbatten: Remove this when getmac is patched - setTimeout(() => { - resolve(undefined); - }, 10000); - } catch (err) { - errors.onUnexpectedError(err); - resolve(undefined); - } - }, err => { - errors.onUnexpectedError(err); - resolve(undefined); - }); - }); + return machineId; +} + +async function getMacMachineId(): Promise { + try { + const crypto = await import('crypto'); + const macAddress = await getMac(); + return crypto.createHash('sha256').update(macAddress, 'utf8').digest('hex'); + } catch (err) { + errors.onUnexpectedError(err); + return undefined; + } } diff --git a/src/vs/base/node/macAddress.ts b/src/vs/base/node/macAddress.ts new file mode 100644 index 000000000..dd36be223 --- /dev/null +++ b/src/vs/base/node/macAddress.ts @@ -0,0 +1,69 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { exec } from 'child_process'; +import { isWindows } from 'vs/base/common/platform'; + +const cmdline = { + windows: 'getmac.exe', + unix: '/sbin/ifconfig -a || /sbin/ip link' +}; + +const invalidMacAddresses = [ + '00:00:00:00:00:00', + 'ff:ff:ff:ff:ff:ff', + 'ac:de:48:00:11:22' +]; + +function validateMacAddress(candidate: string): boolean { + let tempCandidate = candidate.replace(/\-/g, ':').toLowerCase(); + for (let invalidMacAddress of invalidMacAddresses) { + if (invalidMacAddress === tempCandidate) { + return false; + } + } + + return true; +} + +export function getMac(): Promise { + return new Promise(async (resolve, reject) => { + const timeout = setTimeout(() => reject('Unable to retrieve mac address (timeout after 10s)'), 10000); + + try { + resolve(await doGetMac()); + } catch (error) { + reject(error); + } finally { + clearTimeout(timeout); + } + }); +} + +function doGetMac(): Promise { + return new Promise((resolve, reject) => { + try { + exec(isWindows ? cmdline.windows : cmdline.unix, { timeout: 10000 }, (err, stdout, stdin) => { + if (err) { + return reject(`Unable to retrieve mac address (${err.toString()})`); + } else { + const regex = /(?:[a-f\d]{2}[:\-]){5}[a-f\d]{2}/gi; + + let match; + while ((match = regex.exec(stdout)) !== null) { + const macAddressCandidate = match[0]; + if (validateMacAddress(macAddressCandidate)) { + return resolve(macAddressCandidate); + } + } + + return reject('Unable to retrieve mac address (unexpected format)'); + } + }); + } catch (err) { + reject(err); + } + }); +} \ No newline at end of file diff --git a/src/vs/base/node/pfs.ts b/src/vs/base/node/pfs.ts index 37693ce10..1af9f028c 100644 --- a/src/vs/base/node/pfs.ts +++ b/src/vs/base/node/pfs.ts @@ -138,6 +138,20 @@ export async function readdir(path: string): Promise { return handleDirectoryChildren(await promisify(fs.readdir)(path)); } +export async function readdirWithFileTypes(path: string): Promise { + const children = await promisify(fs.readdir)(path, { withFileTypes: true }); + + // Mac: uses NFD unicode form on disk, but we want NFC + // See also https://github.com/nodejs/node/issues/2165 + if (platform.isMacintosh) { + for (const child of children) { + child.name = normalizeNFC(child.name); + } + } + + return children; +} + export function readdirSync(path: string): string[] { return handleDirectoryChildren(fs.readdirSync(path)); } @@ -213,10 +227,6 @@ export function symlink(target: string, path: string, type?: string): Promise { - return promisify(fs.readlink)(path); -} - export function truncate(path: string, len: number): Promise { return promisify(fs.truncate)(path, len); } @@ -230,7 +240,7 @@ export function readFile(path: string, encoding?: string): Promise } = Object.create(null); +const writeFilePathQueues: Map> = new Map(); export function writeFile(path: string, data: string, options?: IWriteFileOptions): Promise; export function writeFile(path: string, data: Buffer, options?: IWriteFileOptions): Promise; @@ -253,18 +263,20 @@ function toQueueKey(path: string): string { } function ensureWriteFileQueue(queueKey: string): Queue { - let writeFileQueue = writeFilePathQueue[queueKey]; - if (!writeFileQueue) { - writeFileQueue = new Queue(); - writeFilePathQueue[queueKey] = writeFileQueue; - - const onFinish = Event.once(writeFileQueue.onFinished); - onFinish(() => { - delete writeFilePathQueue[queueKey]; - writeFileQueue.dispose(); - }); + const existingWriteFileQueue = writeFilePathQueues.get(queueKey); + if (existingWriteFileQueue) { + return existingWriteFileQueue; } + const writeFileQueue = new Queue(); + writeFilePathQueues.set(queueKey, writeFileQueue); + + const onFinish = Event.once(writeFileQueue.onFinished); + onFinish(() => { + writeFilePathQueues.delete(queueKey); + writeFileQueue.dispose(); + }); + return writeFileQueue; } @@ -670,4 +682,15 @@ export async function mkdirp(path: string, mode?: number, token?: CancellationTo // Any other error return Promise.reject(error); } -} \ No newline at end of file +} + +// See https://github.com/Microsoft/vscode/issues/30180 +const WIN32_MAX_FILE_SIZE = 300 * 1024 * 1024; // 300 MB +const GENERAL_MAX_FILE_SIZE = 16 * 1024 * 1024 * 1024; // 16 GB + +// See https://github.com/v8/v8/blob/5918a23a3d571b9625e5cce246bdd5b46ff7cd8b/src/heap/heap.cc#L149 +const WIN32_MAX_HEAP_SIZE = 700 * 1024 * 1024; // 700 MB +const GENERAL_MAX_HEAP_SIZE = 700 * 2 * 1024 * 1024; // 1400 MB + +export const MAX_FILE_SIZE = process.arch === 'ia32' ? WIN32_MAX_FILE_SIZE : GENERAL_MAX_FILE_SIZE; +export const MAX_HEAP_SIZE = process.arch === 'ia32' ? WIN32_MAX_HEAP_SIZE : GENERAL_MAX_HEAP_SIZE; \ No newline at end of file diff --git a/src/vs/base/node/processes.ts b/src/vs/base/node/processes.ts index df8690d00..5bee9f9ec 100644 --- a/src/vs/base/node/processes.ts +++ b/src/vs/base/node/processes.ts @@ -5,6 +5,7 @@ import * as path from 'vs/base/common/path'; import * as fs from 'fs'; +import { promisify } from 'util'; import * as cp from 'child_process'; import * as nls from 'vs/nls'; import * as Types from 'vs/base/common/types'; @@ -404,7 +405,7 @@ export function createQueuedSender(childProcess: cp.ChildProcess): IQueuedSender } export namespace win32 { - export function findExecutable(command: string, cwd?: string, paths?: string[]): string { + export async function findExecutable(command: string, cwd?: string, paths?: string[]): Promise { // If we have an absolute path then we take it. if (path.isAbsolute(command)) { return command; @@ -435,15 +436,15 @@ export namespace win32 { } else { fullPath = path.join(cwd, pathEntry, command); } - if (fs.existsSync(fullPath)) { + if (await promisify(fs.exists)(fullPath)) { return fullPath; } let withExtension = fullPath + '.com'; - if (fs.existsSync(withExtension)) { + if (await promisify(fs.exists)(withExtension)) { return withExtension; } withExtension = fullPath + '.exe'; - if (fs.existsSync(withExtension)) { + if (await promisify(fs.exists)(withExtension)) { return withExtension; } } diff --git a/src/vs/base/node/request.ts b/src/vs/base/node/request.ts deleted file mode 100644 index ea24cdb75..000000000 --- a/src/vs/base/node/request.ts +++ /dev/null @@ -1,183 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { isBoolean, isNumber } from 'vs/base/common/types'; -import * as https from 'https'; -import * as http from 'http'; -import { Stream } from 'stream'; -import { parse as parseUrl } from 'url'; -import { createWriteStream } from 'fs'; -import { assign } from 'vs/base/common/objects'; -import { createGunzip } from 'zlib'; -import { CancellationToken } from 'vs/base/common/cancellation'; -import { canceled } from 'vs/base/common/errors'; - -export type Agent = any; - -export interface IRawRequestFunction { - (options: http.RequestOptions, callback?: (res: http.IncomingMessage) => void): http.ClientRequest; -} - -export interface IRequestOptions { - type?: string; - url?: string; - user?: string; - password?: string; - headers?: any; - timeout?: number; - data?: string | Stream; - agent?: Agent; - followRedirects?: number; - strictSSL?: boolean; - getRawRequest?(options: IRequestOptions): IRawRequestFunction; -} - -export interface IRequestContext { - // req: http.ClientRequest; - // res: http.ClientResponse; - res: { - headers: { [n: string]: string }; - statusCode?: number; - }; - stream: Stream; -} - -export interface IRequestFunction { - (options: IRequestOptions, token: CancellationToken): Promise; -} - -async function getNodeRequest(options: IRequestOptions): Promise { - const endpoint = parseUrl(options.url!); - const module = endpoint.protocol === 'https:' ? await import('https') : await import('http'); - return module.request; -} - -export function request(options: IRequestOptions, token: CancellationToken): Promise { - let req: http.ClientRequest; - - const rawRequestPromise = options.getRawRequest - ? Promise.resolve(options.getRawRequest(options)) - : Promise.resolve(getNodeRequest(options)); - - return rawRequestPromise.then(rawRequest => { - - return new Promise((c, e) => { - const endpoint = parseUrl(options.url!); - - const opts: https.RequestOptions = { - hostname: endpoint.hostname, - port: endpoint.port ? parseInt(endpoint.port) : (endpoint.protocol === 'https:' ? 443 : 80), - protocol: endpoint.protocol, - path: endpoint.path, - method: options.type || 'GET', - headers: options.headers, - agent: options.agent, - rejectUnauthorized: isBoolean(options.strictSSL) ? options.strictSSL : true - }; - - if (options.user && options.password) { - opts.auth = options.user + ':' + options.password; - } - - req = rawRequest(opts, (res: http.IncomingMessage) => { - const followRedirects: number = isNumber(options.followRedirects) ? options.followRedirects : 3; - if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && followRedirects > 0 && res.headers['location']) { - request(assign({}, options, { - url: res.headers['location'], - followRedirects: followRedirects - 1 - }), token).then(c, e); - } else { - let stream: Stream = res; - - if (res.headers['content-encoding'] === 'gzip') { - stream = stream.pipe(createGunzip()); - } - - c({ res, stream } as IRequestContext); - } - }); - - req.on('error', e); - - if (options.timeout) { - req.setTimeout(options.timeout); - } - - if (options.data) { - if (typeof options.data === 'string') { - req.write(options.data); - } else { - options.data.pipe(req); - return; - } - } - - req.end(); - - token.onCancellationRequested(() => { - req.abort(); - e(canceled()); - }); - }); - }); -} - -function isSuccess(context: IRequestContext): boolean { - return (context.res.statusCode && context.res.statusCode >= 200 && context.res.statusCode < 300) || context.res.statusCode === 1223; -} - -function hasNoContent(context: IRequestContext): boolean { - return context.res.statusCode === 204; -} - -export function download(filePath: string, context: IRequestContext): Promise { - return new Promise((c, e) => { - const out = createWriteStream(filePath); - - out.once('finish', () => c(undefined)); - context.stream.once('error', e); - context.stream.pipe(out); - }); -} - -export function asText(context: IRequestContext): Promise { - return new Promise((c, e) => { - if (!isSuccess(context)) { - return e('Server returned ' + context.res.statusCode); - } - - if (hasNoContent(context)) { - return c(null); - } - - const buffer: string[] = []; - context.stream.on('data', (d: string) => buffer.push(d)); - context.stream.on('end', () => c(buffer.join(''))); - context.stream.on('error', e); - }); -} - -export function asJson(context: IRequestContext): Promise { - return new Promise((c, e) => { - if (!isSuccess(context)) { - return e('Server returned ' + context.res.statusCode); - } - - if (hasNoContent(context)) { - return c(null); - } - - const buffer: string[] = []; - context.stream.on('data', (d: string) => buffer.push(d)); - context.stream.on('end', () => { - try { - c(JSON.parse(buffer.join(''))); - } catch (err) { - e(err); - } - }); - context.stream.on('error', e); - }); -} diff --git a/src/vs/base/node/storage.ts b/src/vs/base/node/storage.ts deleted file mode 100644 index 593163b67..000000000 --- a/src/vs/base/node/storage.ts +++ /dev/null @@ -1,780 +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 { Database, Statement } from 'vscode-sqlite3'; -import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; -import { Emitter, Event } from 'vs/base/common/event'; -import { ThrottledDelayer, timeout } from 'vs/base/common/async'; -import { isUndefinedOrNull } from 'vs/base/common/types'; -import { mapToString, setToString } from 'vs/base/common/map'; -import { basename } from 'vs/base/common/path'; -import { copy, renameIgnoreError, unlink } from 'vs/base/node/pfs'; -import { fill } from 'vs/base/common/arrays'; - -export enum StorageHint { - - // A hint to the storage that the storage - // does not exist on disk yet. This allows - // the storage library to improve startup - // time by not checking the storage for data. - STORAGE_DOES_NOT_EXIST -} - -export interface IStorageOptions { - hint?: StorageHint; -} - -export interface IUpdateRequest { - insert?: Map; - delete?: Set; -} - -export interface IStorageItemsChangeEvent { - items: Map; -} - -export interface IStorageDatabase { - - readonly onDidChangeItemsExternal: Event; - - getItems(): Promise>; - updateItems(request: IUpdateRequest): Promise; - - close(recovery?: () => Map): Promise; - - checkIntegrity(full: boolean): Promise; -} - -export interface IStorage extends IDisposable { - - readonly items: Map; - readonly size: number; - readonly onDidChangeStorage: Event; - - init(): Promise; - - get(key: string, fallbackValue: string): string; - get(key: string, fallbackValue?: string): string | undefined; - - getBoolean(key: string, fallbackValue: boolean): boolean; - getBoolean(key: string, fallbackValue?: boolean): boolean | undefined; - - getNumber(key: string, fallbackValue: number): number; - getNumber(key: string, fallbackValue?: number): number | undefined; - - set(key: string, value: string | boolean | number | undefined | null): Promise; - delete(key: string): Promise; - - close(): Promise; - - checkIntegrity(full: boolean): Promise; -} - -enum StorageState { - None, - Initialized, - Closed -} - -export class Storage extends Disposable implements IStorage { - _serviceBrand: any; - - private static readonly DEFAULT_FLUSH_DELAY = 100; - - private readonly _onDidChangeStorage: Emitter = this._register(new Emitter()); - get onDidChangeStorage(): Event { return this._onDidChangeStorage.event; } - - private state = StorageState.None; - - private cache: Map = new Map(); - - private flushDelayer: ThrottledDelayer; - - private pendingDeletes: Set = new Set(); - private pendingInserts: Map = new Map(); - - constructor( - protected database: IStorageDatabase, - private options: IStorageOptions = Object.create(null) - ) { - super(); - - this.flushDelayer = this._register(new ThrottledDelayer(Storage.DEFAULT_FLUSH_DELAY)); - - this.registerListeners(); - } - - private registerListeners(): void { - this._register(this.database.onDidChangeItemsExternal(e => this.onDidChangeItemsExternal(e))); - } - - private onDidChangeItemsExternal(e: IStorageItemsChangeEvent): void { - // items that change external require us to update our - // caches with the values. we just accept the value and - // emit an event if there is a change. - e.items.forEach((value, key) => this.accept(key, value)); - } - - private accept(key: string, value: string): void { - if (this.state === StorageState.Closed) { - return; // Return early if we are already closed - } - - let changed = false; - - // Item got removed, check for deletion - if (isUndefinedOrNull(value)) { - changed = this.cache.delete(key); - } - - // Item got updated, check for change - else { - const currentValue = this.cache.get(key); - if (currentValue !== value) { - this.cache.set(key, value); - changed = true; - } - } - - // Signal to outside listeners - if (changed) { - this._onDidChangeStorage.fire(key); - } - } - - get items(): Map { - return this.cache; - } - - get size(): number { - return this.cache.size; - } - - async init(): Promise { - if (this.state !== StorageState.None) { - return Promise.resolve(); // either closed or already initialized - } - - this.state = StorageState.Initialized; - - if (this.options.hint === StorageHint.STORAGE_DOES_NOT_EXIST) { - // return early if we know the storage file does not exist. this is a performance - // optimization to not load all items of the underlying storage if we know that - // there can be no items because the storage does not exist. - return Promise.resolve(); - } - - this.cache = await this.database.getItems(); - } - - get(key: string, fallbackValue: string): string; - get(key: string, fallbackValue?: string): string | undefined; - get(key: string, fallbackValue?: string): string | undefined { - const value = this.cache.get(key); - - if (isUndefinedOrNull(value)) { - return fallbackValue; - } - - return value; - } - - getBoolean(key: string, fallbackValue: boolean): boolean; - getBoolean(key: string, fallbackValue?: boolean): boolean | undefined; - getBoolean(key: string, fallbackValue?: boolean): boolean | undefined { - const value = this.get(key); - - if (isUndefinedOrNull(value)) { - return fallbackValue; - } - - return value === 'true'; - } - - getNumber(key: string, fallbackValue: number): number; - getNumber(key: string, fallbackValue?: number): number | undefined; - getNumber(key: string, fallbackValue?: number): number | undefined { - const value = this.get(key); - - if (isUndefinedOrNull(value)) { - return fallbackValue; - } - - return parseInt(value, 10); - } - - set(key: string, value: string | boolean | number | null | undefined): Promise { - if (this.state === StorageState.Closed) { - return Promise.resolve(); // Return early if we are already closed - } - - // We remove the key for undefined/null values - if (isUndefinedOrNull(value)) { - return this.delete(key); - } - - // Otherwise, convert to String and store - const valueStr = String(value); - - // Return early if value already set - const currentValue = this.cache.get(key); - if (currentValue === valueStr) { - return Promise.resolve(); - } - - // Update in cache and pending - this.cache.set(key, valueStr); - this.pendingInserts.set(key, valueStr); - this.pendingDeletes.delete(key); - - // Event - this._onDidChangeStorage.fire(key); - - // Accumulate work by scheduling after timeout - return this.flushDelayer.trigger(() => this.flushPending()); - } - - delete(key: string): Promise { - if (this.state === StorageState.Closed) { - return Promise.resolve(); // Return early if we are already closed - } - - // Remove from cache and add to pending - const wasDeleted = this.cache.delete(key); - if (!wasDeleted) { - return Promise.resolve(); // Return early if value already deleted - } - - if (!this.pendingDeletes.has(key)) { - this.pendingDeletes.add(key); - } - - this.pendingInserts.delete(key); - - // Event - this._onDidChangeStorage.fire(key); - - // Accumulate work by scheduling after timeout - return this.flushDelayer.trigger(() => this.flushPending()); - } - - async close(): Promise { - if (this.state === StorageState.Closed) { - return Promise.resolve(); // return if already closed - } - - // Update state - this.state = StorageState.Closed; - - // Trigger new flush to ensure data is persisted and then close - // even if there is an error flushing. We must always ensure - // the DB is closed to avoid corruption. - // - // Recovery: we pass our cache over as recovery option in case - // the DB is not healthy. - try { - await this.flushDelayer.trigger(() => this.flushPending(), 0 /* as soon as possible */); - } catch (error) { - // Ignore - } - - await this.database.close(() => this.cache); - } - - private flushPending(): Promise { - if (this.pendingInserts.size === 0 && this.pendingDeletes.size === 0) { - return Promise.resolve(); // return early if nothing to do - } - - // Get pending data - const updateRequest: IUpdateRequest = { insert: this.pendingInserts, delete: this.pendingDeletes }; - - // Reset pending data for next run - this.pendingDeletes = new Set(); - this.pendingInserts = new Map(); - - // Update in storage - return this.database.updateItems(updateRequest); - } - - checkIntegrity(full: boolean): Promise { - return this.database.checkIntegrity(full); - } -} - -interface IDatabaseConnection { - db: Database; - - isInMemory: boolean; - - isErroneous?: boolean; - lastError?: string; -} - -export interface ISQLiteStorageDatabaseOptions { - logging?: ISQLiteStorageDatabaseLoggingOptions; -} - -export interface ISQLiteStorageDatabaseLoggingOptions { - logError?: (error: string | Error) => void; - logTrace?: (msg: string) => void; -} - -export class SQLiteStorageDatabase implements IStorageDatabase { - - static IN_MEMORY_PATH = ':memory:'; - - get onDidChangeItemsExternal(): Event { return Event.None; } // since we are the only client, there can be no external changes - - private static BUSY_OPEN_TIMEOUT = 2000; // timeout in ms to retry when opening DB fails with SQLITE_BUSY - private static MAX_HOST_PARAMETERS = 256; // maximum number of parameters within a statement - - private path: string; - private name: string; - - private logger: SQLiteStorageDatabaseLogger; - - private whenConnected: Promise; - - constructor(path: string, options: ISQLiteStorageDatabaseOptions = Object.create(null)) { - this.path = path; - this.name = basename(path); - - this.logger = new SQLiteStorageDatabaseLogger(options.logging); - - this.whenConnected = this.connect(path); - } - - async getItems(): Promise> { - const connection = await this.whenConnected; - - const items = new Map(); - - const rows = await this.all(connection, 'SELECT * FROM ItemTable'); - rows.forEach(row => items.set(row.key, row.value)); - - if (this.logger.isTracing) { - this.logger.trace(`[storage ${this.name}] getItems(): ${items.size} rows`); - } - - return items; - } - - async updateItems(request: IUpdateRequest): Promise { - const connection = await this.whenConnected; - - return this.doUpdateItems(connection, request); - } - - private doUpdateItems(connection: IDatabaseConnection, request: IUpdateRequest): Promise { - let updateCount = 0; - if (request.insert) { - updateCount += request.insert.size; - } - if (request.delete) { - updateCount += request.delete.size; - } - - if (updateCount === 0) { - return Promise.resolve(); - } - - if (this.logger.isTracing) { - this.logger.trace(`[storage ${this.name}] updateItems(): insert(${request.insert ? mapToString(request.insert) : '0'}), delete(${request.delete ? setToString(request.delete) : '0'})`); - } - - return this.transaction(connection, () => { - - // INSERT - if (request.insert && request.insert.size > 0) { - const keysValuesChunks: (string[])[] = []; - keysValuesChunks.push([]); // seed with initial empty chunk - - // Split key/values into chunks of SQLiteStorageDatabase.MAX_HOST_PARAMETERS - // so that we can efficiently run the INSERT with as many HOST parameters as possible - let currentChunkIndex = 0; - request.insert.forEach((value, key) => { - let keyValueChunk = keysValuesChunks[currentChunkIndex]; - - if (keyValueChunk.length > SQLiteStorageDatabase.MAX_HOST_PARAMETERS) { - currentChunkIndex++; - keyValueChunk = []; - keysValuesChunks.push(keyValueChunk); - } - - keyValueChunk.push(key, value); - }); - - keysValuesChunks.forEach(keysValuesChunk => { - this.prepare(connection, `INSERT INTO ItemTable VALUES ${fill(keysValuesChunk.length / 2, '(?,?)').join(',')}`, stmt => stmt.run(keysValuesChunk), () => { - const keys: string[] = []; - let length = 0; - request.insert!.forEach((value, key) => { - keys.push(key); - length += value.length; - }); - - return `Keys: ${keys.join(', ')} Length: ${length}`; - }); - }); - } - - // DELETE - if (request.delete && request.delete.size) { - const keysChunks: (string[])[] = []; - keysChunks.push([]); // seed with initial empty chunk - - // Split keys into chunks of SQLiteStorageDatabase.MAX_HOST_PARAMETERS - // so that we can efficiently run the DELETE with as many HOST parameters - // as possible - let currentChunkIndex = 0; - request.delete.forEach(key => { - let keyChunk = keysChunks[currentChunkIndex]; - - if (keyChunk.length > SQLiteStorageDatabase.MAX_HOST_PARAMETERS) { - currentChunkIndex++; - keyChunk = []; - keysChunks.push(keyChunk); - } - - keyChunk.push(key); - }); - - keysChunks.forEach(keysChunk => { - this.prepare(connection, `DELETE FROM ItemTable WHERE key IN (${fill(keysChunk.length, '?').join(',')})`, stmt => stmt.run(keysChunk), () => { - const keys: string[] = []; - request.delete!.forEach(key => { - keys.push(key); - }); - - return `Keys: ${keys.join(', ')}`; - }); - }); - } - }); - } - - async close(recovery?: () => Map): Promise { - this.logger.trace(`[storage ${this.name}] close()`); - - const connection = await this.whenConnected; - - return this.doClose(connection, recovery); - } - - private doClose(connection: IDatabaseConnection, recovery?: () => Map): Promise { - return new Promise((resolve, reject) => { - connection.db.close(closeError => { - if (closeError) { - this.handleSQLiteError(connection, closeError, `[storage ${this.name}] close(): ${closeError}`); - } - - // Return early if this storage was created only in-memory - // e.g. when running tests we do not need to backup. - if (this.path === SQLiteStorageDatabase.IN_MEMORY_PATH) { - return resolve(); - } - - // If the DB closed successfully and we are not running in-memory - // and the DB did not get errors during runtime, make a backup - // of the DB so that we can use it as fallback in case the actual - // DB becomes corrupt in the future. - if (!connection.isErroneous && !connection.isInMemory) { - return this.backup().then(resolve, error => { - this.logger.error(`[storage ${this.name}] backup(): ${error}`); - - return resolve(); // ignore failing backup - }); - } - - // Recovery: if we detected errors while using the DB or we are using - // an inmemory DB (as a fallback to not being able to open the DB initially) - // and we have a recovery function provided, we recreate the DB with this - // data to recover all known data without loss if possible. - if (typeof recovery === 'function') { - - // Delete the existing DB. If the path does not exist or fails to - // be deleted, we do not try to recover anymore because we assume - // that the path is no longer writeable for us. - return unlink(this.path).then(() => { - - // Re-open the DB fresh - return this.doConnect(this.path).then(recoveryConnection => { - const closeRecoveryConnection = () => { - return this.doClose(recoveryConnection, undefined /* do not attempt to recover again */); - }; - - // Store items - return this.doUpdateItems(recoveryConnection, { insert: recovery() }).then(() => closeRecoveryConnection(), error => { - - // In case of an error updating items, still ensure to close the connection - // to prevent SQLITE_BUSY errors when the connection is restablished - closeRecoveryConnection(); - - return Promise.reject(error); - }); - }); - }).then(resolve, reject); - } - - // Finally without recovery we just reject - return reject(closeError || new Error('Database has errors or is in-memory without recovery option')); - }); - }); - } - - private backup(): Promise { - const backupPath = this.toBackupPath(this.path); - - return copy(this.path, backupPath); - } - - private toBackupPath(path: string): string { - return `${path}.backup`; - } - - async checkIntegrity(full: boolean): Promise { - this.logger.trace(`[storage ${this.name}] checkIntegrity(full: ${full})`); - - const connection = await this.whenConnected; - const row = await this.get(connection, full ? 'PRAGMA integrity_check' : 'PRAGMA quick_check'); - - const integrity = full ? row['integrity_check'] : row['quick_check']; - - if (connection.isErroneous) { - return `${integrity} (last error: ${connection.lastError})`; - } - - if (connection.isInMemory) { - return `${integrity} (in-memory!)`; - } - - return integrity; - } - - private connect(path: string, retryOnBusy: boolean = true): Promise { - this.logger.trace(`[storage ${this.name}] open(${path}, retryOnBusy: ${retryOnBusy})`); - - return this.doConnect(path).then(undefined, error => { - this.logger.error(`[storage ${this.name}] open(): Unable to open DB due to ${error}`); - - // SQLITE_BUSY should only arise if another process is locking the same DB we want - // to open at that time. This typically never happens because a DB connection is - // limited per window. However, in the event of a window reload, it may be possible - // that the previous connection was not properly closed while the new connection is - // already established. - // - // In this case we simply wait for some time and retry once to establish the connection. - // - if (error.code === 'SQLITE_BUSY' && retryOnBusy) { - return timeout(SQLiteStorageDatabase.BUSY_OPEN_TIMEOUT).then(() => this.connect(path, false /* not another retry */)); - } - - // Otherwise, best we can do is to recover from a backup if that exists, as such we - // move the DB to a different filename and try to load from backup. If that fails, - // a new empty DB is being created automatically. - // - // The final fallback is to use an in-memory DB which should only happen if the target - // folder is really not writeable for us. - // - return unlink(path) - .then(() => renameIgnoreError(this.toBackupPath(path), path)) - .then(() => this.doConnect(path)) - .then(undefined, error => { - this.logger.error(`[storage ${this.name}] open(): Unable to use backup due to ${error}`); - - // In case of any error to open the DB, use an in-memory - // DB so that we always have a valid DB to talk to. - return this.doConnect(SQLiteStorageDatabase.IN_MEMORY_PATH); - }); - }); - } - - private handleSQLiteError(connection: IDatabaseConnection, error: Error & { code?: string }, msg: string): void { - connection.isErroneous = true; - connection.lastError = msg; - - this.logger.error(msg); - } - - private doConnect(path: string): Promise { - return new Promise((resolve, reject) => { - import('vscode-sqlite3').then(sqlite3 => { - const connection: IDatabaseConnection = { - db: new (this.logger.isTracing ? sqlite3.verbose().Database : sqlite3.Database)(path, error => { - if (error) { - return connection.db ? connection.db.close(() => reject(error)) : reject(error); - } - - // The following exec() statement serves two purposes: - // - create the DB if it does not exist yet - // - validate that the DB is not corrupt (the open() call does not throw otherwise) - return this.exec(connection, [ - 'PRAGMA user_version = 1;', - 'CREATE TABLE IF NOT EXISTS ItemTable (key TEXT UNIQUE ON CONFLICT REPLACE, value BLOB)' - ].join('')).then(() => { - return resolve(connection); - }, error => { - return connection.db.close(() => reject(error)); - }); - }), - isInMemory: path === SQLiteStorageDatabase.IN_MEMORY_PATH - }; - - // Errors - connection.db.on('error', error => this.handleSQLiteError(connection, error, `[storage ${this.name}] Error (event): ${error}`)); - - // Tracing - if (this.logger.isTracing) { - connection.db.on('trace', sql => this.logger.trace(`[storage ${this.name}] Trace (event): ${sql}`)); - } - }, reject); - }); - } - - private exec(connection: IDatabaseConnection, sql: string): Promise { - return new Promise((resolve, reject) => { - connection.db.exec(sql, error => { - if (error) { - this.handleSQLiteError(connection, error, `[storage ${this.name}] exec(): ${error}`); - - return reject(error); - } - - return resolve(); - }); - }); - } - - private get(connection: IDatabaseConnection, sql: string): Promise { - return new Promise((resolve, reject) => { - connection.db.get(sql, (error, row) => { - if (error) { - this.handleSQLiteError(connection, error, `[storage ${this.name}] get(): ${error}`); - - return reject(error); - } - - return resolve(row); - }); - }); - } - - private all(connection: IDatabaseConnection, sql: string): Promise<{ key: string, value: string }[]> { - return new Promise((resolve, reject) => { - connection.db.all(sql, (error, rows) => { - if (error) { - this.handleSQLiteError(connection, error, `[storage ${this.name}] all(): ${error}`); - - return reject(error); - } - - return resolve(rows); - }); - }); - } - - private transaction(connection: IDatabaseConnection, transactions: () => void): Promise { - return new Promise((resolve, reject) => { - connection.db.serialize(() => { - connection.db.run('BEGIN TRANSACTION'); - - transactions(); - - connection.db.run('END TRANSACTION', error => { - if (error) { - this.handleSQLiteError(connection, error, `[storage ${this.name}] transaction(): ${error}`); - - return reject(error); - } - - return resolve(); - }); - }); - }); - } - - private prepare(connection: IDatabaseConnection, sql: string, runCallback: (stmt: Statement) => void, errorDetails: () => string): void { - const stmt = connection.db.prepare(sql); - - const statementErrorListener = (error: Error) => { - this.handleSQLiteError(connection, error, `[storage ${this.name}] prepare(): ${error} (${sql}). Details: ${errorDetails()}`); - }; - - stmt.on('error', statementErrorListener); - - runCallback(stmt); - - stmt.finalize(error => { - if (error) { - statementErrorListener(error); - } - - stmt.removeListener('error', statementErrorListener); - }); - } -} - -class SQLiteStorageDatabaseLogger { - private readonly logTrace: (msg: string) => void; - private readonly logError: (error: string | Error) => void; - - constructor(options?: ISQLiteStorageDatabaseLoggingOptions) { - if (options && typeof options.logTrace === 'function') { - this.logTrace = options.logTrace; - } - - if (options && typeof options.logError === 'function') { - this.logError = options.logError; - } - } - - get isTracing(): boolean { - return !!this.logTrace; - } - - trace(msg: string): void { - if (this.logTrace) { - this.logTrace(msg); - } - } - - error(error: string | Error): void { - if (this.logError) { - this.logError(error); - } - } -} - -export class InMemoryStorageDatabase implements IStorageDatabase { - - readonly onDidChangeItemsExternal = Event.None; - - private items = new Map(); - - getItems(): Promise> { - return Promise.resolve(this.items); - } - - updateItems(request: IUpdateRequest): Promise { - if (request.insert) { - request.insert.forEach((value, key) => this.items.set(key, value)); - } - - if (request.delete) { - request.delete.forEach(key => this.items.delete(key)); - } - - return Promise.resolve(); - } - - close(): Promise { - return Promise.resolve(); - } - - checkIntegrity(full: boolean): Promise { - return Promise.resolve('ok'); - } -} \ No newline at end of file diff --git a/src/vs/base/parts/ipc/common/ipc.net.ts b/src/vs/base/parts/ipc/common/ipc.net.ts index 873c0a8d6..459a5b94b 100644 --- a/src/vs/base/parts/ipc/common/ipc.net.ts +++ b/src/vs/base/parts/ipc/common/ipc.net.ts @@ -11,13 +11,12 @@ import * as platform from 'vs/base/common/platform'; declare var process: any; -export interface ISocket { +export interface ISocket extends IDisposable { onData(listener: (e: VSBuffer) => void): IDisposable; onClose(listener: () => void): IDisposable; onEnd(listener: () => void): IDisposable; write(buffer: VSBuffer): void; end(): void; - dispose(): void; } let emptyBuffer: VSBuffer | null = null; @@ -218,7 +217,7 @@ class ProtocolReader extends Disposable { // save new state => next time will read the body this._state.readHead = false; this._state.readLen = buff.readUInt32BE(9); - this._state.messageType = buff.readUInt8(0); + this._state.messageType = buff.readUInt8(0); this._state.id = buff.readUInt32BE(1); this._state.ack = buff.readUInt32BE(5); } else { @@ -407,7 +406,7 @@ export class Client extends IPCClient { /** * Will ensure no messages are lost if there are no event listeners. */ -function createBufferedEvent(source: Event): Event { +export function createBufferedEvent(source: Event): Event { let emitter: Emitter; let hasListeners = false; let isDeliveringMessages = false; @@ -514,7 +513,7 @@ class Queue { * Same as Protocol, but will actually track messages and acks. * Moreover, it will ensure no messages are lost if there are no event listeners. */ -export class PersistentProtocol { +export class PersistentProtocol implements IMessagePassingProtocol { private _isReconnecting: boolean; diff --git a/src/vs/base/parts/ipc/common/ipc.ts b/src/vs/base/parts/ipc/common/ipc.ts index 6a2ff55e2..9715105ba 100644 --- a/src/vs/base/parts/ipc/common/ipc.ts +++ b/src/vs/base/parts/ipc/common/ipc.ts @@ -23,7 +23,7 @@ export interface IChannel { } /** - * An `IServerChannel` is the couter part to `IChannel`, + * An `IServerChannel` is the counter part to `IChannel`, * on the server-side. You should implement this interface * if you'd like to handle remote promises or events. */ @@ -246,19 +246,29 @@ function deserialize(reader: IReader): any { } } +interface PendingRequest { + request: IRawPromiseRequest | IRawEventListenRequest; + timeoutTimer: any; +} + export class ChannelServer implements IChannelServer, IDisposable { private channels = new Map>(); private activeRequests = new Map(); private protocolListener: IDisposable | null; - constructor(private protocol: IMessagePassingProtocol, private ctx: TContext) { + // Requests might come in for channels which are not yet registered. + // They will timeout after `timeoutDelay`. + private pendingRequests = new Map(); + + constructor(private protocol: IMessagePassingProtocol, private ctx: TContext, private timeoutDelay: number = 1000) { this.protocolListener = this.protocol.onMessage(msg => this.onRawMessage(msg)); this.sendResponse({ type: ResponseType.Initialize }); } registerChannel(channelName: string, channel: IServerChannel): void { this.channels.set(channelName, channel); + this.flushPendingRequests(channelName); } private sendResponse(response: IRawResponse): void { @@ -309,9 +319,12 @@ export class ChannelServer implements IChannelServer; @@ -348,8 +361,10 @@ export class ChannelServer implements IChannelServer implements IChannelServer { + console.error(`Unknown channel: ${request.channelName}`); + + if (request.type === RequestType.Promise) { + this.sendResponse({ + id: request.id, + data: { name: 'Unknown channel', message: `Channel name '${request.channelName}' timed out after ${this.timeoutDelay}ms`, stack: undefined }, + type: ResponseType.PromiseError + }); + } + }, this.timeoutDelay); + + pendingRequests.push({ request, timeoutTimer: timer }); + } + + private flushPendingRequests(channelName: string): void { + const requests = this.pendingRequests.get(channelName); + + if (requests) { + for (const request of requests) { + clearTimeout(request.timeoutTimer); + + switch (request.request.type) { + case RequestType.Promise: this.onPromise(request.request); break; + case RequestType.EventListen: this.onEventListen(request.request); break; + } + } + + this.pendingRequests.delete(channelName); + } + } + public dispose(): void { if (this.protocolListener) { this.protocolListener.dispose(); @@ -464,7 +519,7 @@ export class ChannelClient implements IChannelClient, IDisposable { }; const cancellationTokenListener = cancellationToken.onCancellationRequested(cancel); - disposable = combinedDisposable([toDisposable(cancel), cancellationTokenListener]); + disposable = combinedDisposable(toDisposable(cancel), cancellationTokenListener); this.activeRequests.add(disposable); }); @@ -587,6 +642,7 @@ export interface ClientConnectionEvent { } interface Connection extends Client { + readonly channelServer: ChannelServer; readonly channelClient: ChannelClient; } @@ -625,7 +681,7 @@ export class IPCServer implements IChannelServer, I this.channels.forEach((channel, name) => channelServer.registerChannel(name, channel)); - const connection: Connection = { channelClient, ctx }; + const connection: Connection = { channelServer, channelClient, ctx }; this._connections.add(connection); this._onDidChangeConnections.fire(connection); @@ -661,6 +717,10 @@ export class IPCServer implements IChannelServer, I registerChannel(channelName: string, channel: IServerChannel): void { this.channels.set(channelName, channel); + + this._connections.forEach(connection => { + connection.channelServer.registerChannel(channelName, channel); + }); } dispose(): void { diff --git a/src/vs/base/parts/ipc/node/ipc.net.ts b/src/vs/base/parts/ipc/node/ipc.net.ts index 2dbefa2c4..11e4f516f 100644 --- a/src/vs/base/parts/ipc/node/ipc.net.ts +++ b/src/vs/base/parts/ipc/node/ipc.net.ts @@ -4,14 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import { Socket, Server as NetServer, createConnection, createServer } from 'net'; -import { Event } from 'vs/base/common/event'; +import { Event, Emitter } from 'vs/base/common/event'; import { ClientConnectionEvent, IPCServer } from 'vs/base/parts/ipc/common/ipc'; import { join } from 'vs/base/common/path'; import { tmpdir } from 'os'; import { generateUuid } from 'vs/base/common/uuid'; -import { IDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; import { VSBuffer } from 'vs/base/common/buffer'; -import { ISocket, Protocol, Client } from 'vs/base/parts/ipc/common/ipc.net'; +import { ISocket, Protocol, Client, ChunkStream } from 'vs/base/parts/ipc/common/ipc.net'; export class NodeSocket implements ISocket { public readonly socket: Socket; @@ -65,6 +65,197 @@ export class NodeSocket implements ISocket { } } +const enum Constants { + MinHeaderByteSize = 2 +} + +const enum ReadState { + PeekHeader = 1, + ReadHeader = 2, + ReadBody = 3, + Fin = 4 +} + +/** + * See https://tools.ietf.org/html/rfc6455#section-5.2 + */ +export class WebSocketNodeSocket extends Disposable implements ISocket { + + public readonly socket: NodeSocket; + private readonly _incomingData: ChunkStream; + private readonly _onData = this._register(new Emitter()); + + private readonly _state = { + state: ReadState.PeekHeader, + readLen: Constants.MinHeaderByteSize, + mask: 0 + }; + + constructor(socket: NodeSocket) { + super(); + this.socket = socket; + this._incomingData = new ChunkStream(); + this._register(this.socket.onData(data => this._acceptChunk(data))); + } + + public dispose(): void { + this.socket.dispose(); + } + + public onData(listener: (e: VSBuffer) => void): IDisposable { + return this._onData.event(listener); + } + + public onClose(listener: () => void): IDisposable { + return this.socket.onClose(listener); + } + + public onEnd(listener: () => void): IDisposable { + return this.socket.onEnd(listener); + } + + public write(buffer: VSBuffer): void { + let headerLen = Constants.MinHeaderByteSize; + if (buffer.byteLength < 126) { + headerLen += 0; + } else if (buffer.byteLength < 2 ** 16) { + headerLen += 2; + } else { + headerLen += 8; + } + const header = VSBuffer.alloc(headerLen); + + header.writeUInt8(0b10000010, 0); + if (buffer.byteLength < 126) { + header.writeUInt8(buffer.byteLength, 1); + } else if (buffer.byteLength < 2 ** 16) { + header.writeUInt8(126, 1); + let offset = 1; + header.writeUInt8((buffer.byteLength >>> 8) & 0b11111111, ++offset); + header.writeUInt8((buffer.byteLength >>> 0) & 0b11111111, ++offset); + } else { + header.writeUInt8(127, 1); + let offset = 1; + header.writeUInt8(0, ++offset); + header.writeUInt8(0, ++offset); + header.writeUInt8(0, ++offset); + header.writeUInt8(0, ++offset); + header.writeUInt8((buffer.byteLength >>> 24) & 0b11111111, ++offset); + header.writeUInt8((buffer.byteLength >>> 16) & 0b11111111, ++offset); + header.writeUInt8((buffer.byteLength >>> 8) & 0b11111111, ++offset); + header.writeUInt8((buffer.byteLength >>> 0) & 0b11111111, ++offset); + } + + this.socket.write(VSBuffer.concat([header, buffer])); + } + + public end(): void { + this.socket.end(); + } + + private _acceptChunk(data: VSBuffer): void { + if (data.byteLength === 0) { + return; + } + + this._incomingData.acceptChunk(data); + + while (this._incomingData.byteLength >= this._state.readLen) { + + if (this._state.state === ReadState.PeekHeader) { + // peek to see if we can read the entire header + const peekHeader = this._incomingData.peek(this._state.readLen); + // const firstByte = peekHeader.readUInt8(0); + // const finBit = (firstByte & 0b10000000) >>> 7; + const secondByte = peekHeader.readUInt8(1); + const hasMask = (secondByte & 0b10000000) >>> 7; + const len = (secondByte & 0b01111111); + + this._state.state = ReadState.ReadHeader; + this._state.readLen = Constants.MinHeaderByteSize + (hasMask ? 4 : 0) + (len === 126 ? 2 : 0) + (len === 127 ? 8 : 0); + this._state.mask = 0; + + } else if (this._state.state === ReadState.ReadHeader) { + // read entire header + const header = this._incomingData.read(this._state.readLen); + const secondByte = header.readUInt8(1); + const hasMask = (secondByte & 0b10000000) >>> 7; + let len = (secondByte & 0b01111111); + + let offset = 1; + if (len === 126) { + len = ( + header.readUInt8(++offset) * 2 ** 8 + + header.readUInt8(++offset) + ); + } else if (len === 127) { + len = ( + header.readUInt8(++offset) * 0 + + header.readUInt8(++offset) * 0 + + header.readUInt8(++offset) * 0 + + header.readUInt8(++offset) * 0 + + header.readUInt8(++offset) * 2 ** 24 + + header.readUInt8(++offset) * 2 ** 16 + + header.readUInt8(++offset) * 2 ** 8 + + header.readUInt8(++offset) + ); + } + + let mask = 0; + if (hasMask) { + mask = ( + header.readUInt8(++offset) * 2 ** 24 + + header.readUInt8(++offset) * 2 ** 16 + + header.readUInt8(++offset) * 2 ** 8 + + header.readUInt8(++offset) + ); + } + + this._state.state = ReadState.ReadBody; + this._state.readLen = len; + this._state.mask = mask; + + } else if (this._state.state === ReadState.ReadBody) { + // read body + + const body = this._incomingData.read(this._state.readLen); + unmask(body, this._state.mask); + + this._state.state = ReadState.PeekHeader; + this._state.readLen = Constants.MinHeaderByteSize; + this._state.mask = 0; + + this._onData.fire(body); + } + } + } +} + +function unmask(buffer: VSBuffer, mask: number): void { + if (mask === 0) { + return; + } + let cnt = buffer.byteLength >>> 2; + for (let i = 0; i < cnt; i++) { + const v = buffer.readUInt32BE(i * 4); + buffer.writeUInt32BE(v ^ mask, i * 4); + } + let offset = cnt * 4; + let bytesLeft = buffer.byteLength - offset; + const m3 = (mask >>> 24) & 0b11111111; + const m2 = (mask >>> 16) & 0b11111111; + const m1 = (mask >>> 8) & 0b11111111; + if (bytesLeft >= 1) { + buffer.writeUInt8(buffer.readUInt8(offset) ^ m3, offset); + } + if (bytesLeft >= 2) { + buffer.writeUInt8(buffer.readUInt8(offset + 1) ^ m2, offset + 1); + } + if (bytesLeft >= 3) { + buffer.writeUInt8(buffer.readUInt8(offset + 2) ^ m1, offset + 2); + } +} + export function generateRandomPipeName(): string { const randomSuffix = generateUuid(); if (process.platform === 'win32') { diff --git a/src/vs/base/parts/quickopen/browser/quickOpenModel.ts b/src/vs/base/parts/quickopen/browser/quickOpenModel.ts index 0347e161b..165db403b 100644 --- a/src/vs/base/parts/quickopen/browser/quickOpenModel.ts +++ b/src/vs/base/parts/quickopen/browser/quickOpenModel.ts @@ -36,11 +36,11 @@ let IDS = 0; export class QuickOpenItemAccessorClass implements IItemAccessor { getItemLabel(entry: QuickOpenEntry): string | null { - return entry.getLabel(); + return types.withUndefinedAsNull(entry.getLabel()); } getItemDescription(entry: QuickOpenEntry): string | null { - return entry.getDescription(); + return types.withUndefinedAsNull(entry.getDescription()); } getItemPath(entry: QuickOpenEntry): string | undefined { @@ -75,15 +75,15 @@ export class QuickOpenEntry { /** * The label of the entry to identify it from others in the list */ - getLabel(): string | null { - return null; + getLabel(): string | undefined { + return undefined; } /** * The options for the label to use for this entry */ - getLabelOptions(): IIconLabelValueOptions | null { - return null; + getLabelOptions(): IIconLabelValueOptions | undefined { + return undefined; } /** @@ -97,51 +97,51 @@ export class QuickOpenEntry { /** * Detail information about the entry that is optional and can be shown below the label */ - getDetail(): string | null { - return null; + getDetail(): string | undefined { + return undefined; } /** * The icon of the entry to identify it from others in the list */ - getIcon(): string | null { - return null; + getIcon(): string | undefined { + return undefined; } /** * A secondary description that is optional and can be shown right to the label */ - getDescription(): string | null { - return null; + getDescription(): string | undefined { + return undefined; } /** * A tooltip to show when hovering over the entry. */ - getTooltip(): string | null { - return null; + getTooltip(): string | undefined { + return undefined; } /** * A tooltip to show when hovering over the description portion of the entry. */ - getDescriptionTooltip(): string | null { - return null; + getDescriptionTooltip(): string | undefined { + return undefined; } /** * An optional keybinding to show for an entry. */ - getKeybinding(): ResolvedKeybinding | null { - return null; + getKeybinding(): ResolvedKeybinding | undefined { + return undefined; } /** * A resource for this entry. Resource URIs can be used to compare different kinds of entries and group * them together. */ - getResource(): URI | null { - return null; + getResource(): URI | undefined { + return undefined; } /** @@ -229,11 +229,11 @@ export class QuickOpenEntryGroup extends QuickOpenEntry { this.withBorder = showBorder; } - getLabel(): string | null { + getLabel(): string | undefined { return this.entry ? this.entry.getLabel() : super.getLabel(); } - getLabelOptions(): IIconLabelValueOptions | null { + getLabelOptions(): IIconLabelValueOptions | undefined { return this.entry ? this.entry.getLabelOptions() : super.getLabelOptions(); } @@ -241,19 +241,19 @@ export class QuickOpenEntryGroup extends QuickOpenEntry { return this.entry ? this.entry.getAriaLabel() : super.getAriaLabel(); } - getDetail(): string | null { + getDetail(): string | undefined { return this.entry ? this.entry.getDetail() : super.getDetail(); } - getResource(): URI | null { + getResource(): URI | undefined { return this.entry ? this.entry.getResource() : super.getResource(); } - getIcon(): string | null { + getIcon(): string | undefined { return this.entry ? this.entry.getIcon() : super.getIcon(); } - getDescription(): string | null { + getDescription(): string | undefined { return this.entry ? this.entry.getDescription() : super.getDescription(); } @@ -459,13 +459,13 @@ class Renderer implements IRenderer { // Label const options: IIconLabelValueOptions = entry.getLabelOptions() || Object.create(null); options.matches = labelHighlights || []; - options.title = types.withNullAsUndefined(entry.getTooltip()); - options.descriptionTitle = entry.getDescriptionTooltip() || types.withNullAsUndefined(entry.getDescription()); // tooltip over description because it could overflow + options.title = entry.getTooltip(); + options.descriptionTitle = entry.getDescriptionTooltip() || entry.getDescription(); // tooltip over description because it could overflow options.descriptionMatches = descriptionHighlights || []; - data.label.setLabel(types.withNullAsUndefined(entry.getLabel()), types.withNullAsUndefined(entry.getDescription()), options); + data.label.setLabel(types.withNullAsUndefined(entry.getLabel()), entry.getDescription(), options); // Meta - data.detail.set(types.withNullAsUndefined(entry.getDetail()), detailHighlights); + data.detail.set(entry.getDetail(), detailHighlights); // Keybinding data.keybinding.set(entry.getKeybinding()!); @@ -556,7 +556,7 @@ export class QuickOpenModel implements } getLabel(entry: QuickOpenEntry): string | null { - return entry.getLabel(); + return types.withUndefinedAsNull(entry.getLabel()); } getAriaLabel(entry: QuickOpenEntry): string { diff --git a/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts b/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts index 47c51b879..548cc9489 100644 --- a/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts +++ b/src/vs/base/parts/quickopen/test/common/quickOpenScorer.test.ts @@ -515,11 +515,27 @@ suite('Quick Open Scorer', () => { let query = 'vscode'; - let res = [resourceA, resourceB].sort((r1, r2) => compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache, (r1, r2, query, ResourceAccessor) => -1)); + let res = [resourceA, resourceB].sort((r1, r2) => { + return compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache, (r1, r2, query, ResourceAccessor) => { + if (r1 as any /* TS fail */ === resourceA) { + return -1; + } + + return 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)); + res = [resourceB, resourceA].sort((r1, r2) => { + return compareItemsByScore(r1, r2, query, true, ResourceAccessor, cache, (r1, r2, query, ResourceAccessor) => { + if (r1 as any /* TS fail */ === resourceB) { + return -1; + } + + return 1; + }); + }); assert.equal(res[0], resourceB); assert.equal(res[1], resourceA); }); diff --git a/src/vs/base/parts/storage/common/storage.ts b/src/vs/base/parts/storage/common/storage.ts new file mode 100644 index 000000000..03dedeca5 --- /dev/null +++ b/src/vs/base/parts/storage/common/storage.ts @@ -0,0 +1,318 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import { Emitter, Event } from 'vs/base/common/event'; +import { ThrottledDelayer } from 'vs/base/common/async'; +import { isUndefinedOrNull } from 'vs/base/common/types'; + +export enum StorageHint { + + // A hint to the storage that the storage + // does not exist on disk yet. This allows + // the storage library to improve startup + // time by not checking the storage for data. + STORAGE_DOES_NOT_EXIST +} + +export interface IStorageOptions { + hint?: StorageHint; +} + +export interface IUpdateRequest { + insert?: Map; + delete?: Set; +} + +export interface IStorageItemsChangeEvent { + items: Map; +} + +export interface IStorageDatabase { + + readonly onDidChangeItemsExternal: Event; + + getItems(): Promise>; + updateItems(request: IUpdateRequest): Promise; + + close(recovery?: () => Map): Promise; +} + +export interface IStorage extends IDisposable { + + readonly items: Map; + readonly size: number; + readonly onDidChangeStorage: Event; + + init(): Promise; + + get(key: string, fallbackValue: string): string; + get(key: string, fallbackValue?: string): string | undefined; + + getBoolean(key: string, fallbackValue: boolean): boolean; + getBoolean(key: string, fallbackValue?: boolean): boolean | undefined; + + getNumber(key: string, fallbackValue: number): number; + getNumber(key: string, fallbackValue?: number): number | undefined; + + set(key: string, value: string | boolean | number | undefined | null): Promise; + delete(key: string): Promise; + + close(): Promise; +} + +enum StorageState { + None, + Initialized, + Closed +} + +export class Storage extends Disposable implements IStorage { + + private static readonly DEFAULT_FLUSH_DELAY = 100; + + private readonly _onDidChangeStorage: Emitter = this._register(new Emitter()); + readonly onDidChangeStorage: Event = this._onDidChangeStorage.event; + + private state = StorageState.None; + + private cache: Map = new Map(); + + private flushDelayer: ThrottledDelayer; + + private pendingDeletes: Set = new Set(); + private pendingInserts: Map = new Map(); + + constructor( + protected database: IStorageDatabase, + private options: IStorageOptions = Object.create(null) + ) { + super(); + + this.flushDelayer = this._register(new ThrottledDelayer(Storage.DEFAULT_FLUSH_DELAY)); + + this.registerListeners(); + } + + private registerListeners(): void { + this._register(this.database.onDidChangeItemsExternal(e => this.onDidChangeItemsExternal(e))); + } + + private onDidChangeItemsExternal(e: IStorageItemsChangeEvent): void { + // items that change external require us to update our + // caches with the values. we just accept the value and + // emit an event if there is a change. + e.items.forEach((value, key) => this.accept(key, value)); + } + + private accept(key: string, value: string): void { + if (this.state === StorageState.Closed) { + return; // Return early if we are already closed + } + + let changed = false; + + // Item got removed, check for deletion + if (isUndefinedOrNull(value)) { + changed = this.cache.delete(key); + } + + // Item got updated, check for change + else { + const currentValue = this.cache.get(key); + if (currentValue !== value) { + this.cache.set(key, value); + changed = true; + } + } + + // Signal to outside listeners + if (changed) { + this._onDidChangeStorage.fire(key); + } + } + + get items(): Map { + return this.cache; + } + + get size(): number { + return this.cache.size; + } + + async init(): Promise { + if (this.state !== StorageState.None) { + return Promise.resolve(); // either closed or already initialized + } + + this.state = StorageState.Initialized; + + if (this.options.hint === StorageHint.STORAGE_DOES_NOT_EXIST) { + // return early if we know the storage file does not exist. this is a performance + // optimization to not load all items of the underlying storage if we know that + // there can be no items because the storage does not exist. + return Promise.resolve(); + } + + this.cache = await this.database.getItems(); + } + + get(key: string, fallbackValue: string): string; + get(key: string, fallbackValue?: string): string | undefined; + get(key: string, fallbackValue?: string): string | undefined { + const value = this.cache.get(key); + + if (isUndefinedOrNull(value)) { + return fallbackValue; + } + + return value; + } + + getBoolean(key: string, fallbackValue: boolean): boolean; + getBoolean(key: string, fallbackValue?: boolean): boolean | undefined; + getBoolean(key: string, fallbackValue?: boolean): boolean | undefined { + const value = this.get(key); + + if (isUndefinedOrNull(value)) { + return fallbackValue; + } + + return value === 'true'; + } + + getNumber(key: string, fallbackValue: number): number; + getNumber(key: string, fallbackValue?: number): number | undefined; + getNumber(key: string, fallbackValue?: number): number | undefined { + const value = this.get(key); + + if (isUndefinedOrNull(value)) { + return fallbackValue; + } + + return parseInt(value, 10); + } + + set(key: string, value: string | boolean | number | null | undefined): Promise { + if (this.state === StorageState.Closed) { + return Promise.resolve(); // Return early if we are already closed + } + + // We remove the key for undefined/null values + if (isUndefinedOrNull(value)) { + return this.delete(key); + } + + // Otherwise, convert to String and store + const valueStr = String(value); + + // Return early if value already set + const currentValue = this.cache.get(key); + if (currentValue === valueStr) { + return Promise.resolve(); + } + + // Update in cache and pending + this.cache.set(key, valueStr); + this.pendingInserts.set(key, valueStr); + this.pendingDeletes.delete(key); + + // Event + this._onDidChangeStorage.fire(key); + + // Accumulate work by scheduling after timeout + return this.flushDelayer.trigger(() => this.flushPending()); + } + + delete(key: string): Promise { + if (this.state === StorageState.Closed) { + return Promise.resolve(); // Return early if we are already closed + } + + // Remove from cache and add to pending + const wasDeleted = this.cache.delete(key); + if (!wasDeleted) { + return Promise.resolve(); // Return early if value already deleted + } + + if (!this.pendingDeletes.has(key)) { + this.pendingDeletes.add(key); + } + + this.pendingInserts.delete(key); + + // Event + this._onDidChangeStorage.fire(key); + + // Accumulate work by scheduling after timeout + return this.flushDelayer.trigger(() => this.flushPending()); + } + + async close(): Promise { + if (this.state === StorageState.Closed) { + return Promise.resolve(); // return if already closed + } + + // Update state + this.state = StorageState.Closed; + + // Trigger new flush to ensure data is persisted and then close + // even if there is an error flushing. We must always ensure + // the DB is closed to avoid corruption. + // + // Recovery: we pass our cache over as recovery option in case + // the DB is not healthy. + try { + await this.flushDelayer.trigger(() => this.flushPending(), 0 /* as soon as possible */); + } catch (error) { + // Ignore + } + + await this.database.close(() => this.cache); + } + + private flushPending(): Promise { + if (this.pendingInserts.size === 0 && this.pendingDeletes.size === 0) { + return Promise.resolve(); // return early if nothing to do + } + + // Get pending data + const updateRequest: IUpdateRequest = { insert: this.pendingInserts, delete: this.pendingDeletes }; + + // Reset pending data for next run + this.pendingDeletes = new Set(); + this.pendingInserts = new Map(); + + // Update in storage + return this.database.updateItems(updateRequest); + } +} + +export class InMemoryStorageDatabase implements IStorageDatabase { + + readonly onDidChangeItemsExternal = Event.None; + + private items = new Map(); + + getItems(): Promise> { + return Promise.resolve(this.items); + } + + updateItems(request: IUpdateRequest): Promise { + if (request.insert) { + request.insert.forEach((value, key) => this.items.set(key, value)); + } + + if (request.delete) { + request.delete.forEach(key => this.items.delete(key)); + } + + return Promise.resolve(); + } + + close(): Promise { + return Promise.resolve(); + } +} \ No newline at end of file diff --git a/src/vs/base/parts/storage/node/storage.ts b/src/vs/base/parts/storage/node/storage.ts new file mode 100644 index 000000000..6cebac12c --- /dev/null +++ b/src/vs/base/parts/storage/node/storage.ts @@ -0,0 +1,451 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Database, Statement } from 'vscode-sqlite3'; +import { Event } from 'vs/base/common/event'; +import { timeout } from 'vs/base/common/async'; +import { mapToString, setToString } from 'vs/base/common/map'; +import { basename } from 'vs/base/common/path'; +import { copy, renameIgnoreError, unlink } from 'vs/base/node/pfs'; +import { fill } from 'vs/base/common/arrays'; +import { IStorageDatabase, IStorageItemsChangeEvent, IUpdateRequest } from 'vs/base/parts/storage/common/storage'; + +interface IDatabaseConnection { + db: Database; + + isInMemory: boolean; + + isErroneous?: boolean; + lastError?: string; +} + +export interface ISQLiteStorageDatabaseOptions { + logging?: ISQLiteStorageDatabaseLoggingOptions; +} + +export interface ISQLiteStorageDatabaseLoggingOptions { + logError?: (error: string | Error) => void; + logTrace?: (msg: string) => void; +} + +export class SQLiteStorageDatabase implements IStorageDatabase { + + static IN_MEMORY_PATH = ':memory:'; + + get onDidChangeItemsExternal(): Event { return Event.None; } // since we are the only client, there can be no external changes + + private static BUSY_OPEN_TIMEOUT = 2000; // timeout in ms to retry when opening DB fails with SQLITE_BUSY + private static MAX_HOST_PARAMETERS = 256; // maximum number of parameters within a statement + + private path: string; + private name: string; + + private logger: SQLiteStorageDatabaseLogger; + + private whenConnected: Promise; + + constructor(path: string, options: ISQLiteStorageDatabaseOptions = Object.create(null)) { + this.path = path; + this.name = basename(path); + + this.logger = new SQLiteStorageDatabaseLogger(options.logging); + + this.whenConnected = this.connect(path); + } + + async getItems(): Promise> { + const connection = await this.whenConnected; + + const items = new Map(); + + const rows = await this.all(connection, 'SELECT * FROM ItemTable'); + rows.forEach(row => items.set(row.key, row.value)); + + if (this.logger.isTracing) { + this.logger.trace(`[storage ${this.name}] getItems(): ${items.size} rows`); + } + + return items; + } + + async updateItems(request: IUpdateRequest): Promise { + const connection = await this.whenConnected; + + return this.doUpdateItems(connection, request); + } + + private doUpdateItems(connection: IDatabaseConnection, request: IUpdateRequest): Promise { + if (this.logger.isTracing) { + this.logger.trace(`[storage ${this.name}] updateItems(): insert(${request.insert ? mapToString(request.insert) : '0'}), delete(${request.delete ? setToString(request.delete) : '0'})`); + } + + return this.transaction(connection, () => { + + // INSERT + if (request.insert && request.insert.size > 0) { + const keysValuesChunks: (string[])[] = []; + keysValuesChunks.push([]); // seed with initial empty chunk + + // Split key/values into chunks of SQLiteStorageDatabase.MAX_HOST_PARAMETERS + // so that we can efficiently run the INSERT with as many HOST parameters as possible + let currentChunkIndex = 0; + request.insert.forEach((value, key) => { + let keyValueChunk = keysValuesChunks[currentChunkIndex]; + + if (keyValueChunk.length > SQLiteStorageDatabase.MAX_HOST_PARAMETERS) { + currentChunkIndex++; + keyValueChunk = []; + keysValuesChunks.push(keyValueChunk); + } + + keyValueChunk.push(key, value); + }); + + keysValuesChunks.forEach(keysValuesChunk => { + this.prepare(connection, `INSERT INTO ItemTable VALUES ${fill(keysValuesChunk.length / 2, '(?,?)').join(',')}`, stmt => stmt.run(keysValuesChunk), () => { + const keys: string[] = []; + let length = 0; + request.insert!.forEach((value, key) => { + keys.push(key); + length += value.length; + }); + + return `Keys: ${keys.join(', ')} Length: ${length}`; + }); + }); + } + + // DELETE + if (request.delete && request.delete.size) { + const keysChunks: (string[])[] = []; + keysChunks.push([]); // seed with initial empty chunk + + // Split keys into chunks of SQLiteStorageDatabase.MAX_HOST_PARAMETERS + // so that we can efficiently run the DELETE with as many HOST parameters + // as possible + let currentChunkIndex = 0; + request.delete.forEach(key => { + let keyChunk = keysChunks[currentChunkIndex]; + + if (keyChunk.length > SQLiteStorageDatabase.MAX_HOST_PARAMETERS) { + currentChunkIndex++; + keyChunk = []; + keysChunks.push(keyChunk); + } + + keyChunk.push(key); + }); + + keysChunks.forEach(keysChunk => { + this.prepare(connection, `DELETE FROM ItemTable WHERE key IN (${fill(keysChunk.length, '?').join(',')})`, stmt => stmt.run(keysChunk), () => { + const keys: string[] = []; + request.delete!.forEach(key => { + keys.push(key); + }); + + return `Keys: ${keys.join(', ')}`; + }); + }); + } + }); + } + + async close(recovery?: () => Map): Promise { + this.logger.trace(`[storage ${this.name}] close()`); + + const connection = await this.whenConnected; + + return this.doClose(connection, recovery); + } + + private doClose(connection: IDatabaseConnection, recovery?: () => Map): Promise { + return new Promise((resolve, reject) => { + connection.db.close(closeError => { + if (closeError) { + this.handleSQLiteError(connection, closeError, `[storage ${this.name}] close(): ${closeError}`); + } + + // Return early if this storage was created only in-memory + // e.g. when running tests we do not need to backup. + if (this.path === SQLiteStorageDatabase.IN_MEMORY_PATH) { + return resolve(); + } + + // If the DB closed successfully and we are not running in-memory + // and the DB did not get errors during runtime, make a backup + // of the DB so that we can use it as fallback in case the actual + // DB becomes corrupt in the future. + if (!connection.isErroneous && !connection.isInMemory) { + return this.backup().then(resolve, error => { + this.logger.error(`[storage ${this.name}] backup(): ${error}`); + + return resolve(); // ignore failing backup + }); + } + + // Recovery: if we detected errors while using the DB or we are using + // an inmemory DB (as a fallback to not being able to open the DB initially) + // and we have a recovery function provided, we recreate the DB with this + // data to recover all known data without loss if possible. + if (typeof recovery === 'function') { + + // Delete the existing DB. If the path does not exist or fails to + // be deleted, we do not try to recover anymore because we assume + // that the path is no longer writeable for us. + return unlink(this.path).then(() => { + + // Re-open the DB fresh + return this.doConnect(this.path).then(recoveryConnection => { + const closeRecoveryConnection = () => { + return this.doClose(recoveryConnection, undefined /* do not attempt to recover again */); + }; + + // Store items + return this.doUpdateItems(recoveryConnection, { insert: recovery() }).then(() => closeRecoveryConnection(), error => { + + // In case of an error updating items, still ensure to close the connection + // to prevent SQLITE_BUSY errors when the connection is restablished + closeRecoveryConnection(); + + return Promise.reject(error); + }); + }); + }).then(resolve, reject); + } + + // Finally without recovery we just reject + return reject(closeError || new Error('Database has errors or is in-memory without recovery option')); + }); + }); + } + + private backup(): Promise { + const backupPath = this.toBackupPath(this.path); + + return copy(this.path, backupPath); + } + + private toBackupPath(path: string): string { + return `${path}.backup`; + } + + async checkIntegrity(full: boolean): Promise { + this.logger.trace(`[storage ${this.name}] checkIntegrity(full: ${full})`); + + const connection = await this.whenConnected; + const row = await this.get(connection, full ? 'PRAGMA integrity_check' : 'PRAGMA quick_check'); + + const integrity = full ? (row as any)['integrity_check'] : (row as any)['quick_check']; + + if (connection.isErroneous) { + return `${integrity} (last error: ${connection.lastError})`; + } + + if (connection.isInMemory) { + return `${integrity} (in-memory!)`; + } + + return integrity; + } + + private async connect(path: string, retryOnBusy: boolean = true): Promise { + this.logger.trace(`[storage ${this.name}] open(${path}, retryOnBusy: ${retryOnBusy})`); + + try { + return await this.doConnect(path); + } catch (error) { + this.logger.error(`[storage ${this.name}] open(): Unable to open DB due to ${error}`); + + // SQLITE_BUSY should only arise if another process is locking the same DB we want + // to open at that time. This typically never happens because a DB connection is + // limited per window. However, in the event of a window reload, it may be possible + // that the previous connection was not properly closed while the new connection is + // already established. + // + // In this case we simply wait for some time and retry once to establish the connection. + // + if (error.code === 'SQLITE_BUSY' && retryOnBusy) { + await timeout(SQLiteStorageDatabase.BUSY_OPEN_TIMEOUT); + + return this.connect(path, false /* not another retry */); + } + + // Otherwise, best we can do is to recover from a backup if that exists, as such we + // move the DB to a different filename and try to load from backup. If that fails, + // a new empty DB is being created automatically. + // + // The final fallback is to use an in-memory DB which should only happen if the target + // folder is really not writeable for us. + // + try { + await unlink(path); + await renameIgnoreError(this.toBackupPath(path), path); + + return await this.doConnect(path); + } catch (error) { + this.logger.error(`[storage ${this.name}] open(): Unable to use backup due to ${error}`); + + // In case of any error to open the DB, use an in-memory + // DB so that we always have a valid DB to talk to. + return this.doConnect(SQLiteStorageDatabase.IN_MEMORY_PATH); + } + } + } + + private handleSQLiteError(connection: IDatabaseConnection, error: Error & { code?: string }, msg: string): void { + connection.isErroneous = true; + connection.lastError = msg; + + this.logger.error(msg); + } + + private doConnect(path: string): Promise { + return new Promise((resolve, reject) => { + import('vscode-sqlite3').then(sqlite3 => { + const connection: IDatabaseConnection = { + db: new (this.logger.isTracing ? sqlite3.verbose().Database : sqlite3.Database)(path, error => { + if (error) { + return connection.db ? connection.db.close(() => reject(error)) : reject(error); + } + + // The following exec() statement serves two purposes: + // - create the DB if it does not exist yet + // - validate that the DB is not corrupt (the open() call does not throw otherwise) + return this.exec(connection, [ + 'PRAGMA user_version = 1;', + 'CREATE TABLE IF NOT EXISTS ItemTable (key TEXT UNIQUE ON CONFLICT REPLACE, value BLOB)' + ].join('')).then(() => { + return resolve(connection); + }, error => { + return connection.db.close(() => reject(error)); + }); + }), + isInMemory: path === SQLiteStorageDatabase.IN_MEMORY_PATH + }; + + // Errors + connection.db.on('error', error => this.handleSQLiteError(connection, error, `[storage ${this.name}] Error (event): ${error}`)); + + // Tracing + if (this.logger.isTracing) { + connection.db.on('trace', sql => this.logger.trace(`[storage ${this.name}] Trace (event): ${sql}`)); + } + }, reject); + }); + } + + private exec(connection: IDatabaseConnection, sql: string): Promise { + return new Promise((resolve, reject) => { + connection.db.exec(sql, error => { + if (error) { + this.handleSQLiteError(connection, error, `[storage ${this.name}] exec(): ${error}`); + + return reject(error); + } + + return resolve(); + }); + }); + } + + private get(connection: IDatabaseConnection, sql: string): Promise { + return new Promise((resolve, reject) => { + connection.db.get(sql, (error, row) => { + if (error) { + this.handleSQLiteError(connection, error, `[storage ${this.name}] get(): ${error}`); + + return reject(error); + } + + return resolve(row); + }); + }); + } + + private all(connection: IDatabaseConnection, sql: string): Promise<{ key: string, value: string }[]> { + return new Promise((resolve, reject) => { + connection.db.all(sql, (error, rows) => { + if (error) { + this.handleSQLiteError(connection, error, `[storage ${this.name}] all(): ${error}`); + + return reject(error); + } + + return resolve(rows); + }); + }); + } + + private transaction(connection: IDatabaseConnection, transactions: () => void): Promise { + return new Promise((resolve, reject) => { + connection.db.serialize(() => { + connection.db.run('BEGIN TRANSACTION'); + + transactions(); + + connection.db.run('END TRANSACTION', error => { + if (error) { + this.handleSQLiteError(connection, error, `[storage ${this.name}] transaction(): ${error}`); + + return reject(error); + } + + return resolve(); + }); + }); + }); + } + + private prepare(connection: IDatabaseConnection, sql: string, runCallback: (stmt: Statement) => void, errorDetails: () => string): void { + const stmt = connection.db.prepare(sql); + + const statementErrorListener = (error: Error) => { + this.handleSQLiteError(connection, error, `[storage ${this.name}] prepare(): ${error} (${sql}). Details: ${errorDetails()}`); + }; + + stmt.on('error', statementErrorListener); + + runCallback(stmt); + + stmt.finalize(error => { + if (error) { + statementErrorListener(error); + } + + stmt.removeListener('error', statementErrorListener); + }); + } +} + +class SQLiteStorageDatabaseLogger { + private readonly logTrace: (msg: string) => void; + private readonly logError: (error: string | Error) => void; + + constructor(options?: ISQLiteStorageDatabaseLoggingOptions) { + if (options && typeof options.logTrace === 'function') { + this.logTrace = options.logTrace; + } + + if (options && typeof options.logError === 'function') { + this.logError = options.logError; + } + } + + get isTracing(): boolean { + return !!this.logTrace; + } + + trace(msg: string): void { + if (this.logTrace) { + this.logTrace(msg); + } + } + + error(error: string | Error): void { + if (this.logError) { + this.logError(error); + } + } +} diff --git a/src/vs/base/parts/storage/test/node/storage.test.ts b/src/vs/base/parts/storage/test/node/storage.test.ts new file mode 100644 index 000000000..4c915ef2a --- /dev/null +++ b/src/vs/base/parts/storage/test/node/storage.test.ts @@ -0,0 +1,809 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { SQLiteStorageDatabase, ISQLiteStorageDatabaseOptions } from 'vs/base/parts/storage/node/storage'; +import { Storage, IStorageDatabase, IStorageItemsChangeEvent } from 'vs/base/parts/storage/common/storage'; +import { generateUuid } from 'vs/base/common/uuid'; +import { join } from 'vs/base/common/path'; +import { tmpdir } from 'os'; +import { equal, ok } from 'assert'; +import { mkdirp, writeFile, exists, unlink, rimraf, RimRafMode } from 'vs/base/node/pfs'; +import { timeout } from 'vs/base/common/async'; +import { Event, Emitter } from 'vs/base/common/event'; +import { isWindows } from 'vs/base/common/platform'; + +suite('Storage Library', () => { + + function uniqueStorageDir(): string { + const id = generateUuid(); + + return join(tmpdir(), 'vsctests', id, 'storage2', id); + } + + test('basics', async () => { + const storageDir = uniqueStorageDir(); + await mkdirp(storageDir); + + const storage = new Storage(new SQLiteStorageDatabase(join(storageDir, 'storage.db'))); + + await storage.init(); + + // Empty fallbacks + equal(storage.get('foo', 'bar'), 'bar'); + equal(storage.getNumber('foo', 55), 55); + equal(storage.getBoolean('foo', true), true); + + let changes = new Set(); + storage.onDidChangeStorage(key => { + changes.add(key); + }); + + // Simple updates + const set1Promise = storage.set('bar', 'foo'); + const set2Promise = storage.set('barNumber', 55); + const set3Promise = storage.set('barBoolean', true); + + equal(storage.get('bar'), 'foo'); + equal(storage.getNumber('barNumber'), 55); + equal(storage.getBoolean('barBoolean'), true); + + equal(changes.size, 3); + ok(changes.has('bar')); + ok(changes.has('barNumber')); + ok(changes.has('barBoolean')); + + let setPromiseResolved = false; + await Promise.all([set1Promise, set2Promise, set3Promise]).then(() => setPromiseResolved = true); + equal(setPromiseResolved, true); + + changes = new Set(); + + // Does not trigger events for same update values + storage.set('bar', 'foo'); + storage.set('barNumber', 55); + storage.set('barBoolean', true); + equal(changes.size, 0); + + // Simple deletes + const delete1Promise = storage.delete('bar'); + const delete2Promise = storage.delete('barNumber'); + const delete3Promise = storage.delete('barBoolean'); + + ok(!storage.get('bar')); + ok(!storage.getNumber('barNumber')); + ok(!storage.getBoolean('barBoolean')); + + equal(changes.size, 3); + ok(changes.has('bar')); + ok(changes.has('barNumber')); + ok(changes.has('barBoolean')); + + changes = new Set(); + + // Does not trigger events for same delete values + storage.delete('bar'); + storage.delete('barNumber'); + storage.delete('barBoolean'); + equal(changes.size, 0); + + let deletePromiseResolved = false; + await Promise.all([delete1Promise, delete2Promise, delete3Promise]).then(() => deletePromiseResolved = true); + equal(deletePromiseResolved, true); + + await storage.close(); + await rimraf(storageDir, RimRafMode.MOVE); + }); + + test('external changes', async () => { + const storageDir = uniqueStorageDir(); + await mkdirp(storageDir); + + class TestSQLiteStorageDatabase extends SQLiteStorageDatabase { + private _onDidChangeItemsExternal = new Emitter(); + get onDidChangeItemsExternal(): Event { return this._onDidChangeItemsExternal.event; } + + fireDidChangeItemsExternal(event: IStorageItemsChangeEvent): void { + this._onDidChangeItemsExternal.fire(event); + } + } + + const database = new TestSQLiteStorageDatabase(join(storageDir, 'storage.db')); + const storage = new Storage(database); + + let changes = new Set(); + storage.onDidChangeStorage(key => { + changes.add(key); + }); + + await storage.init(); + + await storage.set('foo', 'bar'); + ok(changes.has('foo')); + changes.clear(); + + // Nothing happens if changing to same value + const change = new Map(); + change.set('foo', 'bar'); + database.fireDidChangeItemsExternal({ items: change }); + equal(changes.size, 0); + + // Change is accepted if valid + change.set('foo', 'bar1'); + database.fireDidChangeItemsExternal({ items: change }); + ok(changes.has('foo')); + equal(storage.get('foo'), 'bar1'); + changes.clear(); + + // Delete is accepted + change.set('foo', undefined); + database.fireDidChangeItemsExternal({ items: change }); + ok(changes.has('foo')); + equal(storage.get('foo', null!), null); + changes.clear(); + + // Nothing happens if changing to same value + change.set('foo', undefined); + database.fireDidChangeItemsExternal({ items: change }); + equal(changes.size, 0); + + await storage.close(); + await rimraf(storageDir, RimRafMode.MOVE); + }); + + test('close flushes data', async () => { + const storageDir = uniqueStorageDir(); + await mkdirp(storageDir); + + let storage = new Storage(new SQLiteStorageDatabase(join(storageDir, 'storage.db'))); + await storage.init(); + + const set1Promise = storage.set('foo', 'bar'); + const set2Promise = storage.set('bar', 'foo'); + + equal(storage.get('foo'), 'bar'); + equal(storage.get('bar'), 'foo'); + + let setPromiseResolved = false; + Promise.all([set1Promise, set2Promise]).then(() => setPromiseResolved = true); + + await storage.close(); + + equal(setPromiseResolved, true); + + storage = new Storage(new SQLiteStorageDatabase(join(storageDir, 'storage.db'))); + await storage.init(); + + equal(storage.get('foo'), 'bar'); + equal(storage.get('bar'), 'foo'); + + await storage.close(); + + storage = new Storage(new SQLiteStorageDatabase(join(storageDir, 'storage.db'))); + await storage.init(); + + const delete1Promise = storage.delete('foo'); + const delete2Promise = storage.delete('bar'); + + ok(!storage.get('foo')); + ok(!storage.get('bar')); + + let deletePromiseResolved = false; + Promise.all([delete1Promise, delete2Promise]).then(() => deletePromiseResolved = true); + + await storage.close(); + + equal(deletePromiseResolved, true); + + storage = new Storage(new SQLiteStorageDatabase(join(storageDir, 'storage.db'))); + await storage.init(); + + ok(!storage.get('foo')); + ok(!storage.get('bar')); + + await storage.close(); + await rimraf(storageDir, RimRafMode.MOVE); + }); + + test('conflicting updates', async () => { + const storageDir = uniqueStorageDir(); + await mkdirp(storageDir); + + let storage = new Storage(new SQLiteStorageDatabase(join(storageDir, 'storage.db'))); + await storage.init(); + + let changes = new Set(); + storage.onDidChangeStorage(key => { + changes.add(key); + }); + + const set1Promise = storage.set('foo', 'bar1'); + const set2Promise = storage.set('foo', 'bar2'); + const set3Promise = storage.set('foo', 'bar3'); + + equal(storage.get('foo'), 'bar3'); + equal(changes.size, 1); + ok(changes.has('foo')); + + let setPromiseResolved = false; + await Promise.all([set1Promise, set2Promise, set3Promise]).then(() => setPromiseResolved = true); + ok(setPromiseResolved); + + changes = new Set(); + + const set4Promise = storage.set('bar', 'foo'); + const delete1Promise = storage.delete('bar'); + + ok(!storage.get('bar')); + + equal(changes.size, 1); + ok(changes.has('bar')); + + let setAndDeletePromiseResolved = false; + await Promise.all([set4Promise, delete1Promise]).then(() => setAndDeletePromiseResolved = true); + ok(setAndDeletePromiseResolved); + + await storage.close(); + await rimraf(storageDir, RimRafMode.MOVE); + }); + + test('corrupt DB recovers', async () => { + const storageDir = uniqueStorageDir(); + await mkdirp(storageDir); + + const storageFile = join(storageDir, 'storage.db'); + + let storage = new Storage(new SQLiteStorageDatabase(storageFile)); + await storage.init(); + + await storage.set('bar', 'foo'); + + await writeFile(storageFile, 'This is a broken DB'); + + await storage.set('foo', 'bar'); + + equal(storage.get('bar'), 'foo'); + equal(storage.get('foo'), 'bar'); + + await storage.close(); + + storage = new Storage(new SQLiteStorageDatabase(storageFile)); + await storage.init(); + + equal(storage.get('bar'), 'foo'); + equal(storage.get('foo'), 'bar'); + + await storage.close(); + await rimraf(storageDir, RimRafMode.MOVE); + }); +}); + +suite('SQLite Storage Library', () => { + + function uniqueStorageDir(): string { + const id = generateUuid(); + + return join(tmpdir(), 'vsctests', id, 'storage', id); + } + + function toSet(elements: string[]): Set { + const set = new Set(); + elements.forEach(element => set.add(element)); + + return set; + } + + async function testDBBasics(path: string, logError?: (error: Error) => void) { + let options!: ISQLiteStorageDatabaseOptions; + if (logError) { + options = { + logging: { + logError + } + }; + } + + const storage = new SQLiteStorageDatabase(path, options); + + const items = new Map(); + items.set('foo', 'bar'); + items.set('some/foo/path', 'some/bar/path'); + items.set(JSON.stringify({ foo: 'bar' }), JSON.stringify({ bar: 'foo' })); + + let storedItems = await storage.getItems(); + equal(storedItems.size, 0); + + await storage.updateItems({ insert: items }); + + storedItems = await storage.getItems(); + equal(storedItems.size, items.size); + equal(storedItems.get('foo'), 'bar'); + equal(storedItems.get('some/foo/path'), 'some/bar/path'); + equal(storedItems.get(JSON.stringify({ foo: 'bar' })), JSON.stringify({ bar: 'foo' })); + + await storage.updateItems({ delete: toSet(['foo']) }); + storedItems = await storage.getItems(); + equal(storedItems.size, items.size - 1); + ok(!storedItems.has('foo')); + equal(storedItems.get('some/foo/path'), 'some/bar/path'); + equal(storedItems.get(JSON.stringify({ foo: 'bar' })), JSON.stringify({ bar: 'foo' })); + + await storage.updateItems({ insert: items }); + storedItems = await storage.getItems(); + equal(storedItems.size, items.size); + equal(storedItems.get('foo'), 'bar'); + equal(storedItems.get('some/foo/path'), 'some/bar/path'); + equal(storedItems.get(JSON.stringify({ foo: 'bar' })), JSON.stringify({ bar: 'foo' })); + + const itemsChange = new Map(); + itemsChange.set('foo', 'otherbar'); + await storage.updateItems({ insert: itemsChange }); + + storedItems = await storage.getItems(); + equal(storedItems.get('foo'), 'otherbar'); + + await storage.updateItems({ delete: toSet(['foo', 'bar', 'some/foo/path', JSON.stringify({ foo: 'bar' })]) }); + storedItems = await storage.getItems(); + equal(storedItems.size, 0); + + await storage.updateItems({ insert: items, delete: toSet(['foo', 'some/foo/path', 'other']) }); + storedItems = await storage.getItems(); + equal(storedItems.size, 1); + equal(storedItems.get(JSON.stringify({ foo: 'bar' })), JSON.stringify({ bar: 'foo' })); + + await storage.updateItems({ delete: toSet([JSON.stringify({ foo: 'bar' })]) }); + storedItems = await storage.getItems(); + equal(storedItems.size, 0); + + let recoveryCalled = false; + await storage.close(() => { + recoveryCalled = true; + + return new Map(); + }); + + equal(recoveryCalled, false); + } + + test('basics', async () => { + const storageDir = uniqueStorageDir(); + + await mkdirp(storageDir); + + await testDBBasics(join(storageDir, 'storage.db')); + + await rimraf(storageDir, RimRafMode.MOVE); + }); + + test('basics (open multiple times)', async () => { + const storageDir = uniqueStorageDir(); + + await mkdirp(storageDir); + + await testDBBasics(join(storageDir, 'storage.db')); + await testDBBasics(join(storageDir, 'storage.db')); + + await rimraf(storageDir, RimRafMode.MOVE); + }); + + test('basics (corrupt DB falls back to empty DB)', async () => { + const storageDir = uniqueStorageDir(); + + await mkdirp(storageDir); + + const corruptDBPath = join(storageDir, 'broken.db'); + await writeFile(corruptDBPath, 'This is a broken DB'); + + let expectedError: any; + await testDBBasics(corruptDBPath, error => { + expectedError = error; + }); + + ok(expectedError); + + await rimraf(storageDir, RimRafMode.MOVE); + }); + + test('basics (corrupt DB restores from previous backup)', async () => { + const storageDir = uniqueStorageDir(); + + await mkdirp(storageDir); + + const storagePath = join(storageDir, 'storage.db'); + let storage = new SQLiteStorageDatabase(storagePath); + + const items = new Map(); + items.set('foo', 'bar'); + items.set('some/foo/path', 'some/bar/path'); + items.set(JSON.stringify({ foo: 'bar' }), JSON.stringify({ bar: 'foo' })); + + await storage.updateItems({ insert: items }); + await storage.close(); + + await writeFile(storagePath, 'This is now a broken DB'); + + storage = new SQLiteStorageDatabase(storagePath); + + const storedItems = await storage.getItems(); + equal(storedItems.size, items.size); + equal(storedItems.get('foo'), 'bar'); + equal(storedItems.get('some/foo/path'), 'some/bar/path'); + equal(storedItems.get(JSON.stringify({ foo: 'bar' })), JSON.stringify({ bar: 'foo' })); + + let recoveryCalled = false; + await storage.close(() => { + recoveryCalled = true; + + return new Map(); + }); + + equal(recoveryCalled, false); + + await rimraf(storageDir, RimRafMode.MOVE); + }); + + test('basics (corrupt DB falls back to empty DB if backup is corrupt)', async () => { + const storageDir = uniqueStorageDir(); + + await mkdirp(storageDir); + + const storagePath = join(storageDir, 'storage.db'); + let storage = new SQLiteStorageDatabase(storagePath); + + const items = new Map(); + items.set('foo', 'bar'); + items.set('some/foo/path', 'some/bar/path'); + items.set(JSON.stringify({ foo: 'bar' }), JSON.stringify({ bar: 'foo' })); + + await storage.updateItems({ insert: items }); + await storage.close(); + + await writeFile(storagePath, 'This is now a broken DB'); + await writeFile(`${storagePath}.backup`, 'This is now also a broken DB'); + + storage = new SQLiteStorageDatabase(storagePath); + + const storedItems = await storage.getItems(); + equal(storedItems.size, 0); + + await testDBBasics(storagePath); + + await rimraf(storageDir, RimRafMode.MOVE); + }); + + test('basics (DB that becomes corrupt during runtime stores all state from cache on close)', async () => { + if (isWindows) { + await Promise.resolve(); // Windows will fail to write to open DB due to locking + + return; + } + + const storageDir = uniqueStorageDir(); + + await mkdirp(storageDir); + + const storagePath = join(storageDir, 'storage.db'); + let storage = new SQLiteStorageDatabase(storagePath); + + const items = new Map(); + items.set('foo', 'bar'); + items.set('some/foo/path', 'some/bar/path'); + items.set(JSON.stringify({ foo: 'bar' }), JSON.stringify({ bar: 'foo' })); + + await storage.updateItems({ insert: items }); + await storage.close(); + + const backupPath = `${storagePath}.backup`; + equal(await exists(backupPath), true); + + storage = new SQLiteStorageDatabase(storagePath); + await storage.getItems(); + + await writeFile(storagePath, 'This is now a broken DB'); + + // we still need to trigger a check to the DB so that we get to know that + // the DB is corrupt. We have no extra code on shutdown that checks for the + // health of the DB. This is an optimization to not perform too many tasks + // on shutdown. + await storage.checkIntegrity(true).then(null, error => { } /* error is expected here but we do not want to fail */); + + await unlink(backupPath); // also test that the recovery DB is backed up properly + + let recoveryCalled = false; + await storage.close(() => { + recoveryCalled = true; + + return items; + }); + + equal(recoveryCalled, true); + equal(await exists(backupPath), true); + + storage = new SQLiteStorageDatabase(storagePath); + + const storedItems = await storage.getItems(); + equal(storedItems.size, items.size); + equal(storedItems.get('foo'), 'bar'); + equal(storedItems.get('some/foo/path'), 'some/bar/path'); + equal(storedItems.get(JSON.stringify({ foo: 'bar' })), JSON.stringify({ bar: 'foo' })); + + recoveryCalled = false; + await storage.close(() => { + recoveryCalled = true; + + return new Map(); + }); + + equal(recoveryCalled, false); + + await rimraf(storageDir, RimRafMode.MOVE); + }); + + test('real world example', async function () { + this.timeout(20000); + + const storageDir = uniqueStorageDir(); + + await mkdirp(storageDir); + + let storage = new SQLiteStorageDatabase(join(storageDir, 'storage.db')); + + const items1 = new Map(); + items1.set('colorthemedata', '{"id":"vs vscode-theme-defaults-themes-light_plus-json","label":"Light+ (default light)","settingsId":"Default Light+","selector":"vs.vscode-theme-defaults-themes-light_plus-json","themeTokenColors":[{"settings":{"foreground":"#000000ff","background":"#ffffffff"}},{"scope":["meta.embedded","source.groovy.embedded"],"settings":{"foreground":"#000000ff"}},{"scope":"emphasis","settings":{"fontStyle":"italic"}},{"scope":"strong","settings":{"fontStyle":"bold"}},{"scope":"meta.diff.header","settings":{"foreground":"#000080"}},{"scope":"comment","settings":{"foreground":"#008000"}},{"scope":"constant.language","settings":{"foreground":"#0000ff"}},{"scope":["constant.numeric"],"settings":{"foreground":"#09885a"}},{"scope":"constant.regexp","settings":{"foreground":"#811f3f"}},{"name":"css tags in selectors, xml tags","scope":"entity.name.tag","settings":{"foreground":"#800000"}},{"scope":"entity.name.selector","settings":{"foreground":"#800000"}},{"scope":"entity.other.attribute-name","settings":{"foreground":"#ff0000"}},{"scope":["entity.other.attribute-name.class.css","entity.other.attribute-name.class.mixin.css","entity.other.attribute-name.id.css","entity.other.attribute-name.parent-selector.css","entity.other.attribute-name.pseudo-class.css","entity.other.attribute-name.pseudo-element.css","source.css.less entity.other.attribute-name.id","entity.other.attribute-name.attribute.scss","entity.other.attribute-name.scss"],"settings":{"foreground":"#800000"}},{"scope":"invalid","settings":{"foreground":"#cd3131"}},{"scope":"markup.underline","settings":{"fontStyle":"underline"}},{"scope":"markup.bold","settings":{"fontStyle":"bold","foreground":"#000080"}},{"scope":"markup.heading","settings":{"fontStyle":"bold","foreground":"#800000"}},{"scope":"markup.italic","settings":{"fontStyle":"italic"}},{"scope":"markup.inserted","settings":{"foreground":"#09885a"}},{"scope":"markup.deleted","settings":{"foreground":"#a31515"}},{"scope":"markup.changed","settings":{"foreground":"#0451a5"}},{"scope":["punctuation.definition.quote.begin.markdown","punctuation.definition.list.begin.markdown"],"settings":{"foreground":"#0451a5"}},{"scope":"markup.inline.raw","settings":{"foreground":"#800000"}},{"name":"brackets of XML/HTML tags","scope":"punctuation.definition.tag","settings":{"foreground":"#800000"}},{"scope":"meta.preprocessor","settings":{"foreground":"#0000ff"}},{"scope":"meta.preprocessor.string","settings":{"foreground":"#a31515"}},{"scope":"meta.preprocessor.numeric","settings":{"foreground":"#09885a"}},{"scope":"meta.structure.dictionary.key.python","settings":{"foreground":"#0451a5"}},{"scope":"storage","settings":{"foreground":"#0000ff"}},{"scope":"storage.type","settings":{"foreground":"#0000ff"}},{"scope":"storage.modifier","settings":{"foreground":"#0000ff"}},{"scope":"string","settings":{"foreground":"#a31515"}},{"scope":["string.comment.buffered.block.pug","string.quoted.pug","string.interpolated.pug","string.unquoted.plain.in.yaml","string.unquoted.plain.out.yaml","string.unquoted.block.yaml","string.quoted.single.yaml","string.quoted.double.xml","string.quoted.single.xml","string.unquoted.cdata.xml","string.quoted.double.html","string.quoted.single.html","string.unquoted.html","string.quoted.single.handlebars","string.quoted.double.handlebars"],"settings":{"foreground":"#0000ff"}},{"scope":"string.regexp","settings":{"foreground":"#811f3f"}},{"name":"String interpolation","scope":["punctuation.definition.template-expression.begin","punctuation.definition.template-expression.end","punctuation.section.embedded"],"settings":{"foreground":"#0000ff"}},{"name":"Reset JavaScript string interpolation expression","scope":["meta.template.expression"],"settings":{"foreground":"#000000"}},{"scope":["support.constant.property-value","support.constant.font-name","support.constant.media-type","support.constant.media","constant.other.color.rgb-value","constant.other.rgb-value","support.constant.color"],"settings":{"foreground":"#0451a5"}},{"scope":["support.type.vendored.property-name","support.type.property-name","variable.css","variable.scss","variable.other.less","source.coffee.embedded"],"settings":{"foreground":"#ff0000"}},{"scope":["support.type.property-name.json"],"settings":{"foreground":"#0451a5"}},{"scope":"keyword","settings":{"foreground":"#0000ff"}},{"scope":"keyword.control","settings":{"foreground":"#0000ff"}},{"scope":"keyword.operator","settings":{"foreground":"#000000"}},{"scope":["keyword.operator.new","keyword.operator.expression","keyword.operator.cast","keyword.operator.sizeof","keyword.operator.instanceof","keyword.operator.logical.python"],"settings":{"foreground":"#0000ff"}},{"scope":"keyword.other.unit","settings":{"foreground":"#09885a"}},{"scope":["punctuation.section.embedded.begin.php","punctuation.section.embedded.end.php"],"settings":{"foreground":"#800000"}},{"scope":"support.function.git-rebase","settings":{"foreground":"#0451a5"}},{"scope":"constant.sha.git-rebase","settings":{"foreground":"#09885a"}},{"name":"coloring of the Java import and package identifiers","scope":["storage.modifier.import.java","variable.language.wildcard.java","storage.modifier.package.java"],"settings":{"foreground":"#000000"}},{"name":"this.self","scope":"variable.language","settings":{"foreground":"#0000ff"}},{"name":"Function declarations","scope":["entity.name.function","support.function","support.constant.handlebars"],"settings":{"foreground":"#795E26"}},{"name":"Types declaration and references","scope":["meta.return-type","support.class","support.type","entity.name.type","entity.name.class","storage.type.numeric.go","storage.type.byte.go","storage.type.boolean.go","storage.type.string.go","storage.type.uintptr.go","storage.type.error.go","storage.type.rune.go","storage.type.cs","storage.type.generic.cs","storage.type.modifier.cs","storage.type.variable.cs","storage.type.annotation.java","storage.type.generic.java","storage.type.java","storage.type.object.array.java","storage.type.primitive.array.java","storage.type.primitive.java","storage.type.token.java","storage.type.groovy","storage.type.annotation.groovy","storage.type.parameters.groovy","storage.type.generic.groovy","storage.type.object.array.groovy","storage.type.primitive.array.groovy","storage.type.primitive.groovy"],"settings":{"foreground":"#267f99"}},{"name":"Types declaration and references, TS grammar specific","scope":["meta.type.cast.expr","meta.type.new.expr","support.constant.math","support.constant.dom","support.constant.json","entity.other.inherited-class"],"settings":{"foreground":"#267f99"}},{"name":"Control flow keywords","scope":"keyword.control","settings":{"foreground":"#AF00DB"}},{"name":"Variable and parameter name","scope":["variable","meta.definition.variable.name","support.variable","entity.name.variable"],"settings":{"foreground":"#001080"}},{"name":"Object keys, TS grammar specific","scope":["meta.object-literal.key"],"settings":{"foreground":"#001080"}},{"name":"CSS property value","scope":["support.constant.property-value","support.constant.font-name","support.constant.media-type","support.constant.media","constant.other.color.rgb-value","constant.other.rgb-value","support.constant.color"],"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":"#ff0000"}},{"scope":"token.info-token","settings":{"foreground":"#316bcd"}},{"scope":"token.warn-token","settings":{"foreground":"#cd9731"}},{"scope":"token.error-token","settings":{"foreground":"#cd3131"}},{"scope":"token.debug-token","settings":{"foreground":"#800080"}}],"extensionData":{"extensionId":"vscode.theme-defaults","extensionPublisher":"vscode","extensionName":"theme-defaults","extensionIsBuiltin":true},"colorMap":{"editor.background":"#ffffff","editor.foreground":"#000000","editor.inactiveSelectionBackground":"#e5ebf1","editorIndentGuide.background":"#d3d3d3","editorIndentGuide.activeBackground":"#939393","editor.selectionHighlightBackground":"#add6ff4d","editorSuggestWidget.background":"#f3f3f3","activityBarBadge.background":"#007acc","sideBarTitle.foreground":"#6f6f6f","list.hoverBackground":"#e8e8e8","input.placeholderForeground":"#767676","settings.textInputBorder":"#cecece","settings.numberInputBorder":"#cecece"}}'); + items1.set('commandpalette.mru.cache', '{"usesLRU":true,"entries":[{"key":"revealFileInOS","value":3},{"key":"extension.openInGitHub","value":4},{"key":"workbench.extensions.action.openExtensionsFolder","value":11},{"key":"workbench.action.showRuntimeExtensions","value":14},{"key":"workbench.action.toggleTabsVisibility","value":15},{"key":"extension.liveServerPreview.open","value":16},{"key":"workbench.action.openIssueReporter","value":18},{"key":"workbench.action.openProcessExplorer","value":19},{"key":"workbench.action.toggleSharedProcess","value":20},{"key":"workbench.action.configureLocale","value":21},{"key":"workbench.action.appPerf","value":22},{"key":"workbench.action.reportPerformanceIssueUsingReporter","value":23},{"key":"workbench.action.openGlobalKeybindings","value":25},{"key":"workbench.action.output.toggleOutput","value":27},{"key":"extension.sayHello","value":29}]}'); + items1.set('cpp.1.lastsessiondate', 'Fri Oct 05 2018'); + items1.set('debug.actionswidgetposition', '0.6880952380952381'); + + const items2 = new Map(); + items2.set('workbench.editors.files.textfileeditor', '{"textEditorViewState":[["file:///Users/dummy/Documents/ticino-playground/play.htm",{"0":{"cursorState":[{"inSelectionMode":false,"selectionStart":{"lineNumber":6,"column":16},"position":{"lineNumber":6,"column":16}}],"viewState":{"scrollLeft":0,"firstPosition":{"lineNumber":1,"column":1},"firstPositionDeltaTop":0},"contributionsState":{"editor.contrib.folding":{},"editor.contrib.wordHighlighter":false}}}],["file:///Users/dummy/Documents/ticino-playground/nakefile.js",{"0":{"cursorState":[{"inSelectionMode":false,"selectionStart":{"lineNumber":7,"column":81},"position":{"lineNumber":7,"column":81}}],"viewState":{"scrollLeft":0,"firstPosition":{"lineNumber":1,"column":1},"firstPositionDeltaTop":20},"contributionsState":{"editor.contrib.folding":{},"editor.contrib.wordHighlighter":false}}}],["file:///Users/dummy/Desktop/vscode2/.gitattributes",{"0":{"cursorState":[{"inSelectionMode":false,"selectionStart":{"lineNumber":9,"column":12},"position":{"lineNumber":9,"column":12}}],"viewState":{"scrollLeft":0,"firstPosition":{"lineNumber":1,"column":1},"firstPositionDeltaTop":20},"contributionsState":{"editor.contrib.folding":{},"editor.contrib.wordHighlighter":false}}}],["file:///Users/dummy/Desktop/vscode2/src/vs/workbench/contrib/search/browser/openAnythingHandler.ts",{"0":{"cursorState":[{"inSelectionMode":false,"selectionStart":{"lineNumber":1,"column":1},"position":{"lineNumber":1,"column":1}}],"viewState":{"scrollLeft":0,"firstPosition":{"lineNumber":1,"column":1},"firstPositionDeltaTop":0},"contributionsState":{"editor.contrib.folding":{},"editor.contrib.wordHighlighter":false}}}]]}'); + + const items3 = new Map(); + items3.set('nps/iscandidate', 'false'); + items3.set('telemetry.instanceid', 'd52bfcd4-4be6-476b-a38f-d44c717c41d6'); + items3.set('workbench.activity.pinnedviewlets', '[{"id":"workbench.view.explorer","pinned":true,"order":0,"visible":true},{"id":"workbench.view.search","pinned":true,"order":1,"visible":true},{"id":"workbench.view.scm","pinned":true,"order":2,"visible":true},{"id":"workbench.view.debug","pinned":true,"order":3,"visible":true},{"id":"workbench.view.extensions","pinned":true,"order":4,"visible":true},{"id":"workbench.view.extension.gitlens","pinned":true,"order":7,"visible":true},{"id":"workbench.view.extension.test","pinned":false,"visible":false}]'); + items3.set('workbench.panel.height', '419'); + items3.set('very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.', 'is long'); + + let storedItems = await storage.getItems(); + equal(storedItems.size, 0); + + await Promise.all([ + await storage.updateItems({ insert: items1 }), + await storage.updateItems({ insert: items2 }), + await storage.updateItems({ insert: items3 }) + ]); + + equal(await storage.checkIntegrity(true), 'ok'); + equal(await storage.checkIntegrity(false), 'ok'); + + storedItems = await storage.getItems(); + equal(storedItems.size, items1.size + items2.size + items3.size); + + const items1Keys: string[] = []; + items1.forEach((value, key) => { + items1Keys.push(key); + equal(storedItems.get(key), value); + }); + + const items2Keys: string[] = []; + items2.forEach((value, key) => { + items2Keys.push(key); + equal(storedItems.get(key), value); + }); + + const items3Keys: string[] = []; + items3.forEach((value, key) => { + items3Keys.push(key); + equal(storedItems.get(key), value); + }); + + await Promise.all([ + await storage.updateItems({ delete: toSet(items1Keys) }), + await storage.updateItems({ delete: toSet(items2Keys) }), + await storage.updateItems({ delete: toSet(items3Keys) }) + ]); + + storedItems = await storage.getItems(); + equal(storedItems.size, 0); + + await Promise.all([ + await storage.updateItems({ insert: items1 }), + await storage.getItems(), + await storage.updateItems({ insert: items2 }), + await storage.getItems(), + await storage.updateItems({ insert: items3 }), + await storage.getItems(), + ]); + + storedItems = await storage.getItems(); + equal(storedItems.size, items1.size + items2.size + items3.size); + + await storage.close(); + + storage = new SQLiteStorageDatabase(join(storageDir, 'storage.db')); + + storedItems = await storage.getItems(); + equal(storedItems.size, items1.size + items2.size + items3.size); + + await storage.close(); + + await rimraf(storageDir, RimRafMode.MOVE); + }); + + test('very large item value', async function () { + this.timeout(20000); + + const storageDir = uniqueStorageDir(); + + await mkdirp(storageDir); + + let storage = new SQLiteStorageDatabase(join(storageDir, 'storage.db')); + + const items = new Map(); + items.set('colorthemedata', '{"id":"vs vscode-theme-defaults-themes-light_plus-json","label":"Light+ (default light)","settingsId":"Default Light+","selector":"vs.vscode-theme-defaults-themes-light_plus-json","themeTokenColors":[{"settings":{"foreground":"#000000ff","background":"#ffffffff"}},{"scope":["meta.embedded","source.groovy.embedded"],"settings":{"foreground":"#000000ff"}},{"scope":"emphasis","settings":{"fontStyle":"italic"}},{"scope":"strong","settings":{"fontStyle":"bold"}},{"scope":"meta.diff.header","settings":{"foreground":"#000080"}},{"scope":"comment","settings":{"foreground":"#008000"}},{"scope":"constant.language","settings":{"foreground":"#0000ff"}},{"scope":["constant.numeric"],"settings":{"foreground":"#09885a"}},{"scope":"constant.regexp","settings":{"foreground":"#811f3f"}},{"name":"css tags in selectors, xml tags","scope":"entity.name.tag","settings":{"foreground":"#800000"}},{"scope":"entity.name.selector","settings":{"foreground":"#800000"}},{"scope":"entity.other.attribute-name","settings":{"foreground":"#ff0000"}},{"scope":["entity.other.attribute-name.class.css","entity.other.attribute-name.class.mixin.css","entity.other.attribute-name.id.css","entity.other.attribute-name.parent-selector.css","entity.other.attribute-name.pseudo-class.css","entity.other.attribute-name.pseudo-element.css","source.css.less entity.other.attribute-name.id","entity.other.attribute-name.attribute.scss","entity.other.attribute-name.scss"],"settings":{"foreground":"#800000"}},{"scope":"invalid","settings":{"foreground":"#cd3131"}},{"scope":"markup.underline","settings":{"fontStyle":"underline"}},{"scope":"markup.bold","settings":{"fontStyle":"bold","foreground":"#000080"}},{"scope":"markup.heading","settings":{"fontStyle":"bold","foreground":"#800000"}},{"scope":"markup.italic","settings":{"fontStyle":"italic"}},{"scope":"markup.inserted","settings":{"foreground":"#09885a"}},{"scope":"markup.deleted","settings":{"foreground":"#a31515"}},{"scope":"markup.changed","settings":{"foreground":"#0451a5"}},{"scope":["punctuation.definition.quote.begin.markdown","punctuation.definition.list.begin.markdown"],"settings":{"foreground":"#0451a5"}},{"scope":"markup.inline.raw","settings":{"foreground":"#800000"}},{"name":"brackets of XML/HTML tags","scope":"punctuation.definition.tag","settings":{"foreground":"#800000"}},{"scope":"meta.preprocessor","settings":{"foreground":"#0000ff"}},{"scope":"meta.preprocessor.string","settings":{"foreground":"#a31515"}},{"scope":"meta.preprocessor.numeric","settings":{"foreground":"#09885a"}},{"scope":"meta.structure.dictionary.key.python","settings":{"foreground":"#0451a5"}},{"scope":"storage","settings":{"foreground":"#0000ff"}},{"scope":"storage.type","settings":{"foreground":"#0000ff"}},{"scope":"storage.modifier","settings":{"foreground":"#0000ff"}},{"scope":"string","settings":{"foreground":"#a31515"}},{"scope":["string.comment.buffered.block.pug","string.quoted.pug","string.interpolated.pug","string.unquoted.plain.in.yaml","string.unquoted.plain.out.yaml","string.unquoted.block.yaml","string.quoted.single.yaml","string.quoted.double.xml","string.quoted.single.xml","string.unquoted.cdata.xml","string.quoted.double.html","string.quoted.single.html","string.unquoted.html","string.quoted.single.handlebars","string.quoted.double.handlebars"],"settings":{"foreground":"#0000ff"}},{"scope":"string.regexp","settings":{"foreground":"#811f3f"}},{"name":"String interpolation","scope":["punctuation.definition.template-expression.begin","punctuation.definition.template-expression.end","punctuation.section.embedded"],"settings":{"foreground":"#0000ff"}},{"name":"Reset JavaScript string interpolation expression","scope":["meta.template.expression"],"settings":{"foreground":"#000000"}},{"scope":["support.constant.property-value","support.constant.font-name","support.constant.media-type","support.constant.media","constant.other.color.rgb-value","constant.other.rgb-value","support.constant.color"],"settings":{"foreground":"#0451a5"}},{"scope":["support.type.vendored.property-name","support.type.property-name","variable.css","variable.scss","variable.other.less","source.coffee.embedded"],"settings":{"foreground":"#ff0000"}},{"scope":["support.type.property-name.json"],"settings":{"foreground":"#0451a5"}},{"scope":"keyword","settings":{"foreground":"#0000ff"}},{"scope":"keyword.control","settings":{"foreground":"#0000ff"}},{"scope":"keyword.operator","settings":{"foreground":"#000000"}},{"scope":["keyword.operator.new","keyword.operator.expression","keyword.operator.cast","keyword.operator.sizeof","keyword.operator.instanceof","keyword.operator.logical.python"],"settings":{"foreground":"#0000ff"}},{"scope":"keyword.other.unit","settings":{"foreground":"#09885a"}},{"scope":["punctuation.section.embedded.begin.php","punctuation.section.embedded.end.php"],"settings":{"foreground":"#800000"}},{"scope":"support.function.git-rebase","settings":{"foreground":"#0451a5"}},{"scope":"constant.sha.git-rebase","settings":{"foreground":"#09885a"}},{"name":"coloring of the Java import and package identifiers","scope":["storage.modifier.import.java","variable.language.wildcard.java","storage.modifier.package.java"],"settings":{"foreground":"#000000"}},{"name":"this.self","scope":"variable.language","settings":{"foreground":"#0000ff"}},{"name":"Function declarations","scope":["entity.name.function","support.function","support.constant.handlebars"],"settings":{"foreground":"#795E26"}},{"name":"Types declaration and references","scope":["meta.return-type","support.class","support.type","entity.name.type","entity.name.class","storage.type.numeric.go","storage.type.byte.go","storage.type.boolean.go","storage.type.string.go","storage.type.uintptr.go","storage.type.error.go","storage.type.rune.go","storage.type.cs","storage.type.generic.cs","storage.type.modifier.cs","storage.type.variable.cs","storage.type.annotation.java","storage.type.generic.java","storage.type.java","storage.type.object.array.java","storage.type.primitive.array.java","storage.type.primitive.java","storage.type.token.java","storage.type.groovy","storage.type.annotation.groovy","storage.type.parameters.groovy","storage.type.generic.groovy","storage.type.object.array.groovy","storage.type.primitive.array.groovy","storage.type.primitive.groovy"],"settings":{"foreground":"#267f99"}},{"name":"Types declaration and references, TS grammar specific","scope":["meta.type.cast.expr","meta.type.new.expr","support.constant.math","support.constant.dom","support.constant.json","entity.other.inherited-class"],"settings":{"foreground":"#267f99"}},{"name":"Control flow keywords","scope":"keyword.control","settings":{"foreground":"#AF00DB"}},{"name":"Variable and parameter name","scope":["variable","meta.definition.variable.name","support.variable","entity.name.variable"],"settings":{"foreground":"#001080"}},{"name":"Object keys, TS grammar specific","scope":["meta.object-literal.key"],"settings":{"foreground":"#001080"}},{"name":"CSS property value","scope":["support.constant.property-value","support.constant.font-name","support.constant.media-type","support.constant.media","constant.other.color.rgb-value","constant.other.rgb-value","support.constant.color"],"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":"#ff0000"}},{"scope":"token.info-token","settings":{"foreground":"#316bcd"}},{"scope":"token.warn-token","settings":{"foreground":"#cd9731"}},{"scope":"token.error-token","settings":{"foreground":"#cd3131"}},{"scope":"token.debug-token","settings":{"foreground":"#800080"}}],"extensionData":{"extensionId":"vscode.theme-defaults","extensionPublisher":"vscode","extensionName":"theme-defaults","extensionIsBuiltin":true},"colorMap":{"editor.background":"#ffffff","editor.foreground":"#000000","editor.inactiveSelectionBackground":"#e5ebf1","editorIndentGuide.background":"#d3d3d3","editorIndentGuide.activeBackground":"#939393","editor.selectionHighlightBackground":"#add6ff4d","editorSuggestWidget.background":"#f3f3f3","activityBarBadge.background":"#007acc","sideBarTitle.foreground":"#6f6f6f","list.hoverBackground":"#e8e8e8","input.placeholderForeground":"#767676","settings.textInputBorder":"#cecece","settings.numberInputBorder":"#cecece"}}'); + items.set('commandpalette.mru.cache', '{"usesLRU":true,"entries":[{"key":"revealFileInOS","value":3},{"key":"extension.openInGitHub","value":4},{"key":"workbench.extensions.action.openExtensionsFolder","value":11},{"key":"workbench.action.showRuntimeExtensions","value":14},{"key":"workbench.action.toggleTabsVisibility","value":15},{"key":"extension.liveServerPreview.open","value":16},{"key":"workbench.action.openIssueReporter","value":18},{"key":"workbench.action.openProcessExplorer","value":19},{"key":"workbench.action.toggleSharedProcess","value":20},{"key":"workbench.action.configureLocale","value":21},{"key":"workbench.action.appPerf","value":22},{"key":"workbench.action.reportPerformanceIssueUsingReporter","value":23},{"key":"workbench.action.openGlobalKeybindings","value":25},{"key":"workbench.action.output.toggleOutput","value":27},{"key":"extension.sayHello","value":29}]}'); + + let uuid = generateUuid(); + let value: string[] = []; + for (let i = 0; i < 100000; i++) { + value.push(uuid); + } + items.set('super.large.string', value.join()); // 3.6MB + + await storage.updateItems({ insert: items }); + + let storedItems = await storage.getItems(); + equal(items.get('colorthemedata'), storedItems.get('colorthemedata')); + equal(items.get('commandpalette.mru.cache'), storedItems.get('commandpalette.mru.cache')); + equal(items.get('super.large.string'), storedItems.get('super.large.string')); + + uuid = generateUuid(); + value = []; + for (let i = 0; i < 100000; i++) { + value.push(uuid); + } + items.set('super.large.string', value.join()); // 3.6MB + + await storage.updateItems({ insert: items }); + + storedItems = await storage.getItems(); + equal(items.get('colorthemedata'), storedItems.get('colorthemedata')); + equal(items.get('commandpalette.mru.cache'), storedItems.get('commandpalette.mru.cache')); + equal(items.get('super.large.string'), storedItems.get('super.large.string')); + + const toDelete = new Set(); + toDelete.add('super.large.string'); + await storage.updateItems({ delete: toDelete }); + + storedItems = await storage.getItems(); + equal(items.get('colorthemedata'), storedItems.get('colorthemedata')); + equal(items.get('commandpalette.mru.cache'), storedItems.get('commandpalette.mru.cache')); + ok(!storedItems.get('super.large.string')); + + await storage.close(); + + await rimraf(storageDir, RimRafMode.MOVE); + }); + + test('multiple concurrent writes execute in sequence', async () => { + const storageDir = uniqueStorageDir(); + await mkdirp(storageDir); + + class TestStorage extends Storage { + getStorage(): IStorageDatabase { + return this.database; + } + } + + const storage = new TestStorage(new SQLiteStorageDatabase(join(storageDir, 'storage.db'))); + + await storage.init(); + + storage.set('foo', 'bar'); + storage.set('some/foo/path', 'some/bar/path'); + + await timeout(10); + + storage.set('foo1', 'bar'); + storage.set('some/foo1/path', 'some/bar/path'); + + await timeout(10); + + storage.set('foo2', 'bar'); + storage.set('some/foo2/path', 'some/bar/path'); + + await timeout(10); + + storage.delete('foo1'); + storage.delete('some/foo1/path'); + + await timeout(10); + + storage.delete('foo4'); + storage.delete('some/foo4/path'); + + await timeout(70); + + storage.set('foo3', 'bar'); + await storage.set('some/foo3/path', 'some/bar/path'); + + const items = await storage.getStorage().getItems(); + equal(items.get('foo'), 'bar'); + equal(items.get('some/foo/path'), 'some/bar/path'); + equal(items.has('foo1'), false); + equal(items.has('some/foo1/path'), false); + equal(items.get('foo2'), 'bar'); + equal(items.get('some/foo2/path'), 'some/bar/path'); + equal(items.get('foo3'), 'bar'); + equal(items.get('some/foo3/path'), 'some/bar/path'); + + await storage.close(); + + await rimraf(storageDir, RimRafMode.MOVE); + }); + + test('lots of INSERT & DELETE (below inline max)', async () => { + const storageDir = uniqueStorageDir(); + + await mkdirp(storageDir); + + const storage = new SQLiteStorageDatabase(join(storageDir, 'storage.db')); + + const items = new Map(); + const keys: Set = new Set(); + for (let i = 0; i < 200; i++) { + const uuid = generateUuid(); + const key = `key: ${uuid}`; + + items.set(key, `value: ${uuid}`); + keys.add(key); + } + + await storage.updateItems({ insert: items }); + + let storedItems = await storage.getItems(); + equal(storedItems.size, items.size); + + await storage.updateItems({ delete: keys }); + + storedItems = await storage.getItems(); + equal(storedItems.size, 0); + + await storage.close(); + + await rimraf(storageDir, RimRafMode.MOVE); + }); + + test('lots of INSERT & DELETE (above inline max)', async () => { + const storageDir = uniqueStorageDir(); + + await mkdirp(storageDir); + + const storage = new SQLiteStorageDatabase(join(storageDir, 'storage.db')); + + const items = new Map(); + const keys: Set = new Set(); + for (let i = 0; i < 400; i++) { + const uuid = generateUuid(); + const key = `key: ${uuid}`; + + items.set(key, `value: ${uuid}`); + keys.add(key); + } + + await storage.updateItems({ insert: items }); + + let storedItems = await storage.getItems(); + equal(storedItems.size, items.size); + + await storage.updateItems({ delete: keys }); + + storedItems = await storage.getItems(); + equal(storedItems.size, 0); + + await storage.close(); + + await rimraf(storageDir, RimRafMode.MOVE); + }); +}); diff --git a/src/vs/base/parts/tree/browser/CollapseAll.svg b/src/vs/base/parts/tree/browser/CollapseAll.svg deleted file mode 100644 index 7d11a30f6..000000000 --- a/src/vs/base/parts/tree/browser/CollapseAll.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/base/parts/tree/browser/CollapseAll_inverse.svg b/src/vs/base/parts/tree/browser/CollapseAll_inverse.svg deleted file mode 100644 index 46a65fff7..000000000 --- a/src/vs/base/parts/tree/browser/CollapseAll_inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/base/parts/tree/browser/collapse-all-dark.svg b/src/vs/base/parts/tree/browser/collapse-all-dark.svg new file mode 100644 index 000000000..4862c55db --- /dev/null +++ b/src/vs/base/parts/tree/browser/collapse-all-dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/vs/base/parts/tree/browser/collapse-all-hc.svg b/src/vs/base/parts/tree/browser/collapse-all-hc.svg new file mode 100644 index 000000000..05f920b29 --- /dev/null +++ b/src/vs/base/parts/tree/browser/collapse-all-hc.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/vs/base/parts/tree/browser/collapse-all-light.svg b/src/vs/base/parts/tree/browser/collapse-all-light.svg new file mode 100644 index 000000000..6359b42e6 --- /dev/null +++ b/src/vs/base/parts/tree/browser/collapse-all-light.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/vs/base/parts/tree/browser/collapsed-dark.svg b/src/vs/base/parts/tree/browser/collapsed-dark.svg deleted file mode 100755 index cf5c3641a..000000000 --- a/src/vs/base/parts/tree/browser/collapsed-dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/base/parts/tree/browser/collapsed-hc.svg b/src/vs/base/parts/tree/browser/collapsed-hc.svg deleted file mode 100644 index 145c76333..000000000 --- a/src/vs/base/parts/tree/browser/collapsed-hc.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/base/parts/tree/browser/collapsed.svg b/src/vs/base/parts/tree/browser/collapsed.svg deleted file mode 100755 index 3a63808c3..000000000 --- a/src/vs/base/parts/tree/browser/collapsed.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/base/parts/tree/browser/expanded-dark.svg b/src/vs/base/parts/tree/browser/expanded-dark.svg deleted file mode 100755 index 73d41e639..000000000 --- a/src/vs/base/parts/tree/browser/expanded-dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/base/parts/tree/browser/expanded-hc.svg b/src/vs/base/parts/tree/browser/expanded-hc.svg deleted file mode 100644 index d38d4abc8..000000000 --- a/src/vs/base/parts/tree/browser/expanded-hc.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/base/parts/tree/browser/expanded.svg b/src/vs/base/parts/tree/browser/expanded.svg deleted file mode 100755 index 75f73adbb..000000000 --- a/src/vs/base/parts/tree/browser/expanded.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/base/parts/tree/browser/tree-collapsed-dark.svg b/src/vs/base/parts/tree/browser/tree-collapsed-dark.svg new file mode 100644 index 000000000..c2c2298dd --- /dev/null +++ b/src/vs/base/parts/tree/browser/tree-collapsed-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/parts/tree/browser/tree-collapsed-hc.svg b/src/vs/base/parts/tree/browser/tree-collapsed-hc.svg new file mode 100644 index 000000000..3732cbc04 --- /dev/null +++ b/src/vs/base/parts/tree/browser/tree-collapsed-hc.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/parts/tree/browser/tree-collapsed-light.svg b/src/vs/base/parts/tree/browser/tree-collapsed-light.svg new file mode 100644 index 000000000..1952ad63f --- /dev/null +++ b/src/vs/base/parts/tree/browser/tree-collapsed-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/parts/tree/browser/tree-expanded-dark.svg b/src/vs/base/parts/tree/browser/tree-expanded-dark.svg new file mode 100644 index 000000000..d844b383e --- /dev/null +++ b/src/vs/base/parts/tree/browser/tree-expanded-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/parts/tree/browser/tree-expanded-hc.svg b/src/vs/base/parts/tree/browser/tree-expanded-hc.svg new file mode 100644 index 000000000..9faa2b2a6 --- /dev/null +++ b/src/vs/base/parts/tree/browser/tree-expanded-hc.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/parts/tree/browser/tree-expanded-light.svg b/src/vs/base/parts/tree/browser/tree-expanded-light.svg new file mode 100644 index 000000000..f09125caf --- /dev/null +++ b/src/vs/base/parts/tree/browser/tree-expanded-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/base/parts/tree/browser/tree.css b/src/vs/base/parts/tree/browser/tree.css index 6e835d22e..2a3cb47dd 100644 --- a/src/vs/base/parts/tree/browser/tree.css +++ b/src/vs/base/parts/tree/browser/tree.css @@ -66,7 +66,7 @@ content: ' '; position: absolute; display: block; - background: url('collapsed.svg') 50% 50% no-repeat; + background: url('tree-collapsed-light.svg') 50% 50% no-repeat; width: 16px; height: 100%; top: 0; @@ -74,7 +74,7 @@ } .monaco-tree .monaco-tree-rows.show-twisties > .monaco-tree-row.expanded > .content:before { - background-image: url('expanded.svg'); + background-image: url('tree-expanded-light.svg'); } .monaco-tree .monaco-tree-rows > .monaco-tree-row.has-children.loading > .content:before { @@ -88,11 +88,11 @@ } .vs-dark .monaco-tree .monaco-tree-rows.show-twisties > .monaco-tree-row.has-children > .content:before { - background-image: url('collapsed-dark.svg'); + background-image: url('tree-collapsed-dark.svg'); } .vs-dark .monaco-tree .monaco-tree-rows.show-twisties > .monaco-tree-row.expanded > .content:before { - background-image: url('expanded-dark.svg'); + background-image: url('tree-expanded-dark.svg'); } .vs-dark .monaco-tree .monaco-tree-rows > .monaco-tree-row.has-children.loading > .content:before { @@ -100,11 +100,11 @@ } .hc-black .monaco-tree .monaco-tree-rows.show-twisties > .monaco-tree-row.has-children > .content:before { - background-image: url('collapsed-hc.svg'); + background-image: url('tree-collapsed-hc.svg'); } .hc-black .monaco-tree .monaco-tree-rows.show-twisties > .monaco-tree-row.expanded > .content:before { - background-image: url('expanded-hc.svg'); + background-image: url('tree-expanded-hc.svg'); } .hc-black .monaco-tree .monaco-tree-rows > .monaco-tree-row.has-children.loading > .content:before { @@ -112,10 +112,13 @@ } .monaco-tree-action.collapse-all { - background: url('CollapseAll.svg') center center no-repeat; + background: url('collapse-all-light.svg') center center no-repeat; } -.hc-black .monaco-tree-action.collapse-all, .vs-dark .monaco-tree-action.collapse-all { - background: url('CollapseAll_inverse.svg') center center no-repeat; + background: url('collapse-all-dark.svg') center center no-repeat; +} + +.hc-black .monaco-tree-action.collapse-all { + background: url('collapse-all-hc.svg') center center no-repeat; } diff --git a/src/vs/base/parts/tree/browser/tree.ts b/src/vs/base/parts/tree/browser/tree.ts index 970e05e75..82b4015e6 100644 --- a/src/vs/base/parts/tree/browser/tree.ts +++ b/src/vs/base/parts/tree/browser/tree.ts @@ -231,7 +231,7 @@ export interface IDataSource { * * You should not attempt to "move" an element to a different * parent by keeping its ID. The idea here is to have tree location - * related IDs (eg. full file path, in the Explorer example). + * related IDs (e.g. full file path, in the Explorer example). */ getId(tree: ITree, element: any): string; @@ -576,7 +576,7 @@ export interface IActionProvider { hasActions(tree: ITree | null, element: any): boolean; /** - * Returns a promise of an array with the actions of the element that should show up in place right to the element in the tree. + * Returns an array with the actions of the element that should show up in place right to the element in the tree. */ - getActions(tree: ITree | null, element: any): IAction[] | null; + getActions(tree: ITree | null, element: any): ReadonlyArray | null; } diff --git a/src/vs/base/parts/tree/browser/treeModel.ts b/src/vs/base/parts/tree/browser/treeModel.ts index 1ddbe4cb4..54ec61756 100644 --- a/src/vs/base/parts/tree/browser/treeModel.ts +++ b/src/vs/base/parts/tree/browser/treeModel.ts @@ -159,7 +159,7 @@ export class ItemRegistry { public register(item: Item): void { Assert.ok(!this.isRegistered(item.id), 'item already registered: ' + item.id); - const disposable = combinedDisposable([ + const disposable = combinedDisposable( this._onDidRevealItem.add(item.onDidReveal), this._onExpandItem.add(item.onExpand), this._onDidExpandItem.add(item.onDidExpand), @@ -171,7 +171,7 @@ export class ItemRegistry { this._onRefreshItemChildren.add(item.onRefreshChildren), this._onDidRefreshItemChildren.add(item.onDidRefreshChildren), this._onDidDisposeItem.add(item.onDidDispose) - ]); + ); this.items[item.id] = { item, disposable }; } diff --git a/src/vs/base/parts/tree/browser/treeView.ts b/src/vs/base/parts/tree/browser/treeView.ts index 6852c0c72..2042f576d 100644 --- a/src/vs/base/parts/tree/browser/treeView.ts +++ b/src/vs/base/parts/tree/browser/treeView.ts @@ -447,13 +447,13 @@ export class TreeView extends HeightMap { private onHiddenScrollTop: number | null = null; private readonly _onDOMFocus = new Emitter(); - get onDOMFocus(): Event { return this._onDOMFocus.event; } + readonly onDOMFocus: Event = this._onDOMFocus.event; private readonly _onDOMBlur = new Emitter(); - get onDOMBlur(): Event { return this._onDOMBlur.event; } + readonly onDOMBlur: Event = this._onDOMBlur.event; private readonly _onDidScroll = new Emitter(); - get onDidScroll(): Event { return this._onDidScroll.event; } + readonly onDidScroll: Event = this._onDidScroll.event; constructor(context: _.ITreeContext, container: HTMLElement) { super(); diff --git a/src/vs/base/test/browser/comparers.test.ts b/src/vs/base/test/browser/comparers.test.ts index df74e2bbf..369f16080 100644 --- a/src/vs/base/test/browser/comparers.test.ts +++ b/src/vs/base/test/browser/comparers.test.ts @@ -3,23 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { compareFileNames, compareFileExtensions, setFileNameComparer } from 'vs/base/common/comparers'; +import { compareFileNames, compareFileExtensions } from 'vs/base/common/comparers'; import * as assert from 'assert'; -import { IdleValue } from 'vs/base/common/async'; suite('Comparers', () => { test('compareFileNames', () => { - // Setup Intl - setFileNameComparer(new IdleValue(() => { - const collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' }); - return { - collator: collator, - collatorIsNumeric: collator.resolvedOptions().numeric - }; - })); - assert(compareFileNames(null, null) === 0, 'null should be equal'); assert(compareFileNames(null, 'abc') < 0, 'null should be come before real values'); assert(compareFileNames('', '') === 0, 'empty should be equal'); @@ -35,15 +25,6 @@ suite('Comparers', () => { test('compareFileExtensions', () => { - // Setup Intl - setFileNameComparer(new IdleValue(() => { - const collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' }); - return { - collator: collator, - collatorIsNumeric: collator.resolvedOptions().numeric - }; - })); - assert(compareFileExtensions(null, null) === 0, 'null should be equal'); assert(compareFileExtensions(null, '.abc') < 0, 'null should come before real files'); assert(compareFileExtensions(null, 'abc') < 0, 'null should come before real files without extension'); @@ -66,4 +47,4 @@ suite('Comparers', () => { assert(compareFileExtensions('file2.ext2', 'file1.ext10') < 0, 'extensions with numbers should be in numerical order, not alphabetical order'); assert(compareFileExtensions('file.ext01', 'file.ext1') < 0, 'extensions with equal numbers should be in alphabetical order'); }); -}); \ No newline at end of file +}); diff --git a/src/vs/base/test/browser/hash.test.ts b/src/vs/base/test/browser/hash.test.ts deleted file mode 100644 index adbedc411..000000000 --- a/src/vs/base/test/browser/hash.test.ts +++ /dev/null @@ -1,16 +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 { createSHA1 } from 'vs/base/browser/hash'; - -suite('Hash', () => { - test('computeSHA1Hash', async () => { - assert.equal(await createSHA1(''), 'da39a3ee5e6b4b0d3255bfef95601890afd80709'); - assert.equal(await createSHA1('hello world'), '2aae6c35c94fcfb415dbe95f408b9ce91ee846ed'); - assert.equal(await createSHA1('da39a3ee5e6b4b0d3255bfef95601890afd80709'), '10a34637ad661d98ba3344717656fcc76209c2f8'); - assert.equal(await createSHA1('2aae6c35c94fcfb415dbe95f408b9ce91ee846ed'), 'd6b0d82cea4269b51572b8fab43adcee9fc3cf9a'); - assert.equal(await createSHA1('öäü_?ß()<>ÖÄÜ'), 'b64beaeff9e317b0193c8e40a2431b210388eba9'); - }); -}); \ No newline at end of file diff --git a/src/vs/base/test/browser/htmlContent.test.ts b/src/vs/base/test/browser/htmlContent.test.ts index 6035010b3..d5dec0729 100644 --- a/src/vs/base/test/browser/htmlContent.test.ts +++ b/src/vs/base/test/browser/htmlContent.test.ts @@ -5,8 +5,19 @@ import * as assert from 'assert'; import * as marked from 'vs/base/common/marked/marked'; import { renderMarkdown, renderText, renderFormattedText } from 'vs/base/browser/htmlContentRenderer'; +import { DisposableStore } from 'vs/base/common/lifecycle'; suite('HtmlContent', () => { + const store = new DisposableStore(); + + setup(() => { + store.clear(); + }); + + teardown(() => { + store.clear(); + }); + test('render simple element', () => { let result: HTMLElement = renderText('testing'); @@ -55,7 +66,7 @@ suite('HtmlContent', () => { assert.strictEqual(content, '0'); callbackCalled = true; }, - disposeables: [] + disposeables: store } }); assert.strictEqual(result.innerHTML, 'action'); @@ -74,7 +85,7 @@ suite('HtmlContent', () => { assert.strictEqual(content, '0'); callbackCalled = true; }, - disposeables: [] + disposeables: store } }); assert.strictEqual(result.innerHTML, 'action'); diff --git a/src/vs/base/test/browser/ui/grid/grid.test.ts b/src/vs/base/test/browser/ui/grid/grid.test.ts index 7385b3ca4..3c2b1b4ec 100644 --- a/src/vs/base/test/browser/ui/grid/grid.test.ts +++ b/src/vs/base/test/browser/ui/grid/grid.test.ts @@ -8,6 +8,15 @@ import { Direction, getRelativeLocation, Orientation, SerializableGrid, ISeriali import { TestView, nodesToArrays } from './util'; import { deepClone } from 'vs/base/common/objects'; +// Simple example: +// +-----+---------------+ +// | 4 | 2 | +// +-----+---------+-----+ +// | 1 | | +// +---------------+ 3 | +// | 5 | | +// +---------------+-----+ + suite('Grid', function () { let container: HTMLElement; @@ -625,12 +634,6 @@ suite('SerializableGrid', function () { assert.deepEqual(nodesToArrays(grid2.getViews()), [[view4Copy, view2Copy], [[view1Copy, view5Copy], view3Copy]]); - assert.deepEqual(view1Copy.size, [50, 50]); - assert.deepEqual(view2Copy.size, [50, 50]); - assert.deepEqual(view3Copy.size, [50, 100]); - assert.deepEqual(view4Copy.size, [50, 50]); - assert.deepEqual(view5Copy.size, [50, 50]); - grid2.layout(800, 600); assert.deepEqual(view1Copy.size, [600, 300]); @@ -798,4 +801,222 @@ suite('SerializableGrid', function () { height: 1 }); }); + + test('serialize should store visibility and previous size', function () { + const view1 = new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const grid = new SerializableGrid(view1); + container.appendChild(grid.element); + grid.layout(800, 600); + + const view2 = new TestSerializableView('view2', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view2, 200, view1, Direction.Up); + + const view3 = new TestSerializableView('view3', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view3, 200, view1, Direction.Right); + + const view4 = new TestSerializableView('view4', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view4, 200, view2, Direction.Left); + + const view5 = new TestSerializableView('view5', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view5, 100, view1, Direction.Down); + + assert.deepEqual(view1.size, [600, 300]); + assert.deepEqual(view2.size, [600, 200]); + assert.deepEqual(view3.size, [200, 400]); + assert.deepEqual(view4.size, [200, 200]); + assert.deepEqual(view5.size, [600, 100]); + + grid.setViewVisible(view5, false); + + assert.deepEqual(view1.size, [600, 400]); + assert.deepEqual(view2.size, [600, 200]); + assert.deepEqual(view3.size, [200, 400]); + assert.deepEqual(view4.size, [200, 200]); + assert.deepEqual(view5.size, [600, 0]); + + const json = grid.serialize(); + assert.deepEqual(json, { + orientation: 0, + width: 800, + height: 600, + root: { + type: 'branch', + data: [ + { + type: 'branch', + data: [ + { type: 'leaf', data: { name: 'view4' }, size: 200 }, + { type: 'leaf', data: { name: 'view2' }, size: 600 } + ], + size: 200 + }, + { + type: 'branch', + data: [ + { + type: 'branch', + data: [ + { type: 'leaf', data: { name: 'view1' }, size: 400 }, + { type: 'leaf', data: { name: 'view5' }, size: 100, visible: false } + ], + size: 600 + }, + { type: 'leaf', data: { name: 'view3' }, size: 200 } + ], + size: 400 + } + ], + size: 800 + } + }); + + grid.dispose(); + + const deserializer = new TestViewDeserializer(); + const grid2 = SerializableGrid.deserialize(json, deserializer); + + const view1Copy = deserializer.getView('view1'); + const view2Copy = deserializer.getView('view2'); + const view3Copy = deserializer.getView('view3'); + const view4Copy = deserializer.getView('view4'); + const view5Copy = deserializer.getView('view5'); + + assert.deepEqual(nodesToArrays(grid2.getViews()), [[view4Copy, view2Copy], [[view1Copy, view5Copy], view3Copy]]); + + grid2.layout(800, 600); + assert.deepEqual(view1Copy.size, [600, 400]); + assert.deepEqual(view2Copy.size, [600, 200]); + assert.deepEqual(view3Copy.size, [200, 400]); + assert.deepEqual(view4Copy.size, [200, 200]); + assert.deepEqual(view5Copy.size, [600, 0]); + + assert.deepEqual(grid2.isViewVisible(view1Copy), true); + assert.deepEqual(grid2.isViewVisible(view2Copy), true); + assert.deepEqual(grid2.isViewVisible(view3Copy), true); + assert.deepEqual(grid2.isViewVisible(view4Copy), true); + assert.deepEqual(grid2.isViewVisible(view5Copy), false); + + grid2.setViewVisible(view5Copy, true); + + assert.deepEqual(view1Copy.size, [600, 300]); + assert.deepEqual(view2Copy.size, [600, 200]); + assert.deepEqual(view3Copy.size, [200, 400]); + assert.deepEqual(view4Copy.size, [200, 200]); + assert.deepEqual(view5Copy.size, [600, 100]); + + assert.deepEqual(grid2.isViewVisible(view1Copy), true); + assert.deepEqual(grid2.isViewVisible(view2Copy), true); + assert.deepEqual(grid2.isViewVisible(view3Copy), true); + assert.deepEqual(grid2.isViewVisible(view4Copy), true); + assert.deepEqual(grid2.isViewVisible(view5Copy), true); + }); + + test('serialize should store visibility and previous size even for first leaf', function () { + const view1 = new TestSerializableView('view1', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const grid = new SerializableGrid(view1); + container.appendChild(grid.element); + grid.layout(800, 600); + + const view2 = new TestSerializableView('view2', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view2, 200, view1, Direction.Up); + + const view3 = new TestSerializableView('view3', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view3, 200, view1, Direction.Right); + + const view4 = new TestSerializableView('view4', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view4, 200, view2, Direction.Left); + + const view5 = new TestSerializableView('view5', 50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + grid.addView(view5, 100, view1, Direction.Down); + + assert.deepEqual(view1.size, [600, 300]); + assert.deepEqual(view2.size, [600, 200]); + assert.deepEqual(view3.size, [200, 400]); + assert.deepEqual(view4.size, [200, 200]); + assert.deepEqual(view5.size, [600, 100]); + + grid.setViewVisible(view4, false); + + assert.deepEqual(view1.size, [600, 300]); + assert.deepEqual(view2.size, [800, 200]); + assert.deepEqual(view3.size, [200, 400]); + assert.deepEqual(view4.size, [0, 200]); + assert.deepEqual(view5.size, [600, 100]); + + const json = grid.serialize(); + assert.deepEqual(json, { + orientation: 0, + width: 800, + height: 600, + root: { + type: 'branch', + data: [ + { + type: 'branch', + data: [ + { type: 'leaf', data: { name: 'view4' }, size: 200, visible: false }, + { type: 'leaf', data: { name: 'view2' }, size: 800 } + ], + size: 200 + }, + { + type: 'branch', + data: [ + { + type: 'branch', + data: [ + { type: 'leaf', data: { name: 'view1' }, size: 300 }, + { type: 'leaf', data: { name: 'view5' }, size: 100 } + ], + size: 600 + }, + { type: 'leaf', data: { name: 'view3' }, size: 200 } + ], + size: 400 + } + ], + size: 800 + } + }); + + grid.dispose(); + + const deserializer = new TestViewDeserializer(); + const grid2 = SerializableGrid.deserialize(json, deserializer); + + const view1Copy = deserializer.getView('view1'); + const view2Copy = deserializer.getView('view2'); + const view3Copy = deserializer.getView('view3'); + const view4Copy = deserializer.getView('view4'); + const view5Copy = deserializer.getView('view5'); + + assert.deepEqual(nodesToArrays(grid2.getViews()), [[view4Copy, view2Copy], [[view1Copy, view5Copy], view3Copy]]); + + grid2.layout(800, 600); + assert.deepEqual(view1Copy.size, [600, 300]); + assert.deepEqual(view2Copy.size, [800, 200]); + assert.deepEqual(view3Copy.size, [200, 400]); + assert.deepEqual(view4Copy.size, [0, 200]); + assert.deepEqual(view5Copy.size, [600, 100]); + + assert.deepEqual(grid2.isViewVisible(view1Copy), true); + assert.deepEqual(grid2.isViewVisible(view2Copy), true); + assert.deepEqual(grid2.isViewVisible(view3Copy), true); + assert.deepEqual(grid2.isViewVisible(view4Copy), false); + assert.deepEqual(grid2.isViewVisible(view5Copy), true); + + grid2.setViewVisible(view4Copy, true); + + assert.deepEqual(view1Copy.size, [600, 300]); + assert.deepEqual(view2Copy.size, [600, 200]); + assert.deepEqual(view3Copy.size, [200, 400]); + assert.deepEqual(view4Copy.size, [200, 200]); + assert.deepEqual(view5Copy.size, [600, 100]); + + assert.deepEqual(grid2.isViewVisible(view1Copy), true); + assert.deepEqual(grid2.isViewVisible(view2Copy), true); + assert.deepEqual(grid2.isViewVisible(view3Copy), true); + assert.deepEqual(grid2.isViewVisible(view4Copy), true); + assert.deepEqual(grid2.isViewVisible(view5Copy), true); + }); }); diff --git a/src/vs/base/test/browser/ui/grid/gridview.test.ts b/src/vs/base/test/browser/ui/grid/gridview.test.ts index 3d000d85a..78cc44cc7 100644 --- a/src/vs/base/test/browser/ui/grid/gridview.test.ts +++ b/src/vs/base/test/browser/ui/grid/gridview.test.ts @@ -22,7 +22,7 @@ suite('Gridview', function () { }); test('empty gridview is empty', function () { - assert.deepEqual(nodesToArrays(gridview.getViews()), []); + assert.deepEqual(nodesToArrays(gridview.getView()), []); gridview.dispose(); }); @@ -43,7 +43,7 @@ suite('Gridview', function () { gridview.addView(views[1], 200, [1]); gridview.addView(views[2], 200, [2]); - assert.deepEqual(nodesToArrays(gridview.getViews()), views); + assert.deepEqual(nodesToArrays(gridview.getView()), views); gridview.dispose(); }); @@ -59,10 +59,10 @@ suite('Gridview', function () { ]; gridview.addView(views[0] as IView, 200, [0]); - gridview.addView(views[1][0] as IView, 200, [1]); - gridview.addView(views[1][1] as IView, 200, [1, 1]); + gridview.addView((views[1] as TestView[])[0] as IView, 200, [1]); + gridview.addView((views[1] as TestView[])[1] as IView, 200, [1, 1]); - assert.deepEqual(nodesToArrays(gridview.getViews()), views); + assert.deepEqual(nodesToArrays(gridview.getView()), views); gridview.dispose(); }); @@ -71,35 +71,35 @@ suite('Gridview', function () { const view1 = new TestView(20, 20, 20, 20); gridview.addView(view1 as IView, 200, [0]); - assert.deepEqual(nodesToArrays(gridview.getViews()), [view1]); + assert.deepEqual(nodesToArrays(gridview.getView()), [view1]); const view2 = new TestView(20, 20, 20, 20); gridview.addView(view2 as IView, 200, [1]); - assert.deepEqual(nodesToArrays(gridview.getViews()), [view1, view2]); + assert.deepEqual(nodesToArrays(gridview.getView()), [view1, view2]); const view3 = new TestView(20, 20, 20, 20); gridview.addView(view3 as IView, 200, [1, 0]); - assert.deepEqual(nodesToArrays(gridview.getViews()), [view1, [view3, view2]]); + assert.deepEqual(nodesToArrays(gridview.getView()), [view1, [view3, view2]]); const view4 = new TestView(20, 20, 20, 20); gridview.addView(view4 as IView, 200, [1, 0, 0]); - assert.deepEqual(nodesToArrays(gridview.getViews()), [view1, [[view4, view3], view2]]); + assert.deepEqual(nodesToArrays(gridview.getView()), [view1, [[view4, view3], view2]]); const view5 = new TestView(20, 20, 20, 20); gridview.addView(view5 as IView, 200, [1, 0]); - assert.deepEqual(nodesToArrays(gridview.getViews()), [view1, [view5, [view4, view3], view2]]); + assert.deepEqual(nodesToArrays(gridview.getView()), [view1, [view5, [view4, view3], view2]]); const view6 = new TestView(20, 20, 20, 20); gridview.addView(view6 as IView, 200, [2]); - assert.deepEqual(nodesToArrays(gridview.getViews()), [view1, [view5, [view4, view3], view2], view6]); + assert.deepEqual(nodesToArrays(gridview.getView()), [view1, [view5, [view4, view3], view2], view6]); const view7 = new TestView(20, 20, 20, 20); gridview.addView(view7 as IView, 200, [1, 1]); - assert.deepEqual(nodesToArrays(gridview.getViews()), [view1, [view5, view7, [view4, view3], view2], view6]); + assert.deepEqual(nodesToArrays(gridview.getView()), [view1, [view5, view7, [view4, view3], view2], view6]); const view8 = new TestView(20, 20, 20, 20); gridview.addView(view8 as IView, 200, [1, 1, 0]); - assert.deepEqual(nodesToArrays(gridview.getViews()), [view1, [view5, [view8, view7], [view4, view3], view2], view6]); + assert.deepEqual(nodesToArrays(gridview.getView()), [view1, [view5, [view8, view7], [view4, view3], view2], view6]); gridview.dispose(); }); @@ -107,19 +107,19 @@ suite('Gridview', function () { test('simple layout', function () { gridview.layout(800, 600); - const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const view1 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view1, 200, [0]); assert.deepEqual(view1.size, [800, 600]); assert.deepEqual(gridview.getViewSize([0]), { width: 800, height: 600 }); - const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const view2 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view2, 200, [0]); assert.deepEqual(view1.size, [800, 400]); assert.deepEqual(gridview.getViewSize([1]), { width: 800, height: 400 }); assert.deepEqual(view2.size, [800, 200]); assert.deepEqual(gridview.getViewSize([0]), { width: 800, height: 200 }); - const view3 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const view3 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view3, 200, [1, 1]); assert.deepEqual(view1.size, [600, 400]); assert.deepEqual(gridview.getViewSize([1, 0]), { width: 600, height: 400 }); @@ -128,7 +128,7 @@ suite('Gridview', function () { assert.deepEqual(view3.size, [200, 400]); assert.deepEqual(gridview.getViewSize([1, 1]), { width: 200, height: 400 }); - const view4 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const view4 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view4, 200, [0, 0]); assert.deepEqual(view1.size, [600, 400]); assert.deepEqual(gridview.getViewSize([1, 0]), { width: 600, height: 400 }); @@ -139,7 +139,7 @@ suite('Gridview', function () { assert.deepEqual(view4.size, [200, 200]); assert.deepEqual(gridview.getViewSize([0, 0]), { width: 200, height: 200 }); - const view5 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const view5 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view5, 100, [1, 0, 1]); assert.deepEqual(view1.size, [600, 300]); assert.deepEqual(gridview.getViewSize([1, 0, 0]), { width: 600, height: 300 }); @@ -156,30 +156,30 @@ suite('Gridview', function () { test('simple layout with automatic size distribution', function () { gridview.layout(800, 600); - const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const view1 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view1, Sizing.Distribute, [0]); assert.deepEqual(view1.size, [800, 600]); assert.deepEqual(gridview.getViewSize([0]), { width: 800, height: 600 }); - const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const view2 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view2, Sizing.Distribute, [0]); assert.deepEqual(view1.size, [800, 300]); assert.deepEqual(view2.size, [800, 300]); - const view3 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const view3 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view3, Sizing.Distribute, [1, 1]); assert.deepEqual(view1.size, [400, 300]); assert.deepEqual(view2.size, [800, 300]); assert.deepEqual(view3.size, [400, 300]); - const view4 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const view4 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view4, Sizing.Distribute, [0, 0]); assert.deepEqual(view1.size, [400, 300]); assert.deepEqual(view2.size, [400, 300]); assert.deepEqual(view3.size, [400, 300]); assert.deepEqual(view4.size, [400, 300]); - const view5 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const view5 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view5, Sizing.Distribute, [1, 0, 1]); assert.deepEqual(view1.size, [400, 150]); assert.deepEqual(view2.size, [400, 300]); @@ -190,13 +190,13 @@ suite('Gridview', function () { test('addviews before layout call 1', function () { - const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const view1 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view1, 200, [0]); - const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const view2 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view2, 200, [0]); - const view3 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const view3 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view3, 200, [1, 1]); gridview.layout(800, 600); @@ -207,14 +207,13 @@ suite('Gridview', function () { }); test('addviews before layout call 2', function () { - - const view1 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const view1 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view1, 200, [0]); - const view2 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const view2 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view2, 200, [0]); - const view3 = new TestView(50, Number.MAX_VALUE, 50, Number.MAX_VALUE); + const view3 = new TestView(50, Number.POSITIVE_INFINITY, 50, Number.POSITIVE_INFINITY); gridview.addView(view3, 200, [0, 0]); gridview.layout(800, 600); diff --git a/src/vs/base/test/browser/ui/grid/util.ts b/src/vs/base/test/browser/ui/grid/util.ts index 0efdc4485..39a35736d 100644 --- a/src/vs/base/test/browser/ui/grid/util.ts +++ b/src/vs/base/test/browser/ui/grid/util.ts @@ -5,7 +5,8 @@ import * as assert from 'assert'; import { Emitter, Event } from 'vs/base/common/event'; -import { IView, GridNode, isGridBranchNode, } from 'vs/base/browser/ui/grid/gridview'; +import { GridNode, isGridBranchNode } from 'vs/base/browser/ui/grid/gridview'; +import { IView } from 'vs/base/browser/ui/grid/grid'; export class TestView implements IView { @@ -78,4 +79,4 @@ export function nodesToArrays(node: GridNode): any { } else { return node.view; } -} \ No newline at end of file +} diff --git a/src/vs/base/test/browser/ui/splitview/splitview.test.ts b/src/vs/base/test/browser/ui/splitview/splitview.test.ts index 00c698c79..504e665f2 100644 --- a/src/vs/base/test/browser/ui/splitview/splitview.test.ts +++ b/src/vs/base/test/browser/ui/splitview/splitview.test.ts @@ -196,8 +196,8 @@ suite('Splitview', () => { splitview.resizeView(0, 70); assert.equal(view1.size, 70, 'view1 is collapsed'); - assert.equal(view2.size, 110, 'view2 is expanded'); - assert.equal(view3.size, 20, 'view3 stays the same'); + assert.equal(view2.size, 40, 'view2 stays the same'); + assert.equal(view3.size, 90, 'view3 is stretched'); splitview.resizeView(2, 40); @@ -474,10 +474,10 @@ suite('Splitview', () => { splitview.addView(view1, Sizing.Distribute); splitview.addView(view2, Sizing.Distribute); splitview.addView(view3, Sizing.Distribute); - assert.deepEqual([view1.size, view2.size, view3.size], [66, 66, 68]); + assert.deepEqual([view1.size, view2.size, view3.size], [66, 68, 66]); splitview.layout(180); - assert.deepEqual([view1.size, view2.size, view3.size], [66, 46, 68]); + assert.deepEqual([view1.size, view2.size, view3.size], [66, 48, 66]); splitview.layout(124); assert.deepEqual([view1.size, view2.size, view3.size], [66, 20, 38]); @@ -504,13 +504,13 @@ suite('Splitview', () => { splitview.addView(view1, Sizing.Distribute); splitview.addView(view2, Sizing.Distribute); splitview.addView(view3, Sizing.Distribute); - assert.deepEqual([view1.size, view2.size, view3.size], [66, 66, 68]); + assert.deepEqual([view1.size, view2.size, view3.size], [66, 68, 66]); splitview.layout(180); - assert.deepEqual([view1.size, view2.size, view3.size], [66, 46, 68]); + assert.deepEqual([view1.size, view2.size, view3.size], [66, 48, 66]); splitview.layout(132); - assert.deepEqual([view1.size, view2.size, view3.size], [44, 20, 68]); + assert.deepEqual([view1.size, view2.size, view3.size], [46, 20, 66]); splitview.layout(60); assert.deepEqual([view1.size, view2.size, view3.size], [20, 20, 20]); diff --git a/src/vs/base/test/browser/ui/tree/asyncDataTree.test.ts b/src/vs/base/test/browser/ui/tree/asyncDataTree.test.ts index 3c934126d..0e93e4bb3 100644 --- a/src/vs/base/test/browser/ui/tree/asyncDataTree.test.ts +++ b/src/vs/base/test/browser/ui/tree/asyncDataTree.test.ts @@ -326,4 +326,57 @@ suite('AsyncDataTree', function () { assert(!hasClass(twistie, 'collapsed')); assert(tree.getNode(_('a')).collapsed); }); + + test('support default collapse state per element', async () => { + const container = document.createElement('div'); + container.style.width = '200px'; + container.style.height = '200px'; + + const delegate = new class implements IListVirtualDelegate { + getHeight() { return 20; } + getTemplateId(element: Element): string { return 'default'; } + }; + + const renderer = new class implements ITreeRenderer { + readonly templateId = 'default'; + renderTemplate(container: HTMLElement): HTMLElement { + return container; + } + renderElement(element: ITreeNode, index: number, templateData: HTMLElement): void { + templateData.textContent = element.element.id; + } + disposeTemplate(templateData: HTMLElement): void { + // noop + } + }; + + const getChildrenCalls: string[] = []; + const dataSource = new class implements IAsyncDataSource { + hasChildren(element: Element): boolean { + return !!element.children && element.children.length > 0; + } + getChildren(element: Element): Promise { + getChildrenCalls.push(element.id); + return Promise.resolve(element.children || []); + } + }; + + const root: Element = { + id: 'root', + children: [{ + id: 'a', children: [{ id: 'aa' }, { id: 'ab' }, { id: 'ac' }] + }] + }; + + const _: (id: string) => Element = find.bind(null, root.children); + + const tree = new AsyncDataTree(container, delegate, [renderer], dataSource, { + collapseByDefault: el => el.id !== 'a' + }); + tree.layout(200); + + await tree.setInput(root); + assert(!tree.getNode(_('a')).collapsed); + assert.deepStrictEqual(getChildrenCalls, ['root', 'a']); + }); }); \ No newline at end of file diff --git a/src/vs/base/test/browser/ui/tree/compressedObjectTreeModel.test.ts b/src/vs/base/test/browser/ui/tree/compressedObjectTreeModel.test.ts new file mode 100644 index 000000000..4d03b49a0 --- /dev/null +++ b/src/vs/base/test/browser/ui/tree/compressedObjectTreeModel.test.ts @@ -0,0 +1,430 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import { compress, ICompressedTreeElement, ICompressedTreeNode, decompress, CompressedTreeModel } from 'vs/base/browser/ui/tree/compressedObjectTreeModel'; +import { Iterator } from 'vs/base/common/iterator'; +import { ITreeNode } from 'vs/base/browser/ui/tree/tree'; +import { ISpliceable } from 'vs/base/common/sequence'; + +interface IResolvedCompressedTreeElement extends ICompressedTreeElement { + readonly element: T; + readonly children?: ICompressedTreeElement[]; +} + +function resolve(treeElement: ICompressedTreeElement): IResolvedCompressedTreeElement { + const result: any = { element: treeElement.element }; + const children = Iterator.collect(Iterator.map(Iterator.from(treeElement.children), resolve)); + + if (treeElement.incompressible) { + result.incompressible = true; + } + + if (children.length > 0) { + result.children = children; + } + + return result; +} + +suite('CompressedObjectTree', function () { + + suite('compress & decompress', function () { + + test('small', function () { + const decompressed: ICompressedTreeElement = { element: 1 }; + const compressed: IResolvedCompressedTreeElement> = + { element: { elements: [1], incompressible: false } }; + + assert.deepEqual(resolve(compress(decompressed)), compressed); + assert.deepEqual(resolve(decompress(compressed)), decompressed); + }); + + test('no compression', function () { + const decompressed: ICompressedTreeElement = { + element: 1, children: [ + { element: 11 }, + { element: 12 }, + { element: 13 } + ] + }; + + const compressed: IResolvedCompressedTreeElement> = { + element: { elements: [1], incompressible: false }, + children: [ + { element: { elements: [11], incompressible: false } }, + { element: { elements: [12], incompressible: false } }, + { element: { elements: [13], incompressible: false } } + ] + }; + + assert.deepEqual(resolve(compress(decompressed)), compressed); + assert.deepEqual(resolve(decompress(compressed)), decompressed); + }); + + test('single hierarchy', function () { + const decompressed: ICompressedTreeElement = { + element: 1, children: [ + { + element: 11, children: [ + { + element: 111, children: [ + { element: 1111 } + ] + } + ] + } + ] + }; + + const compressed: IResolvedCompressedTreeElement> = { + element: { elements: [1, 11, 111, 1111], incompressible: false } + }; + + assert.deepEqual(resolve(compress(decompressed)), compressed); + assert.deepEqual(resolve(decompress(compressed)), decompressed); + }); + + test('deep compression', function () { + const decompressed: ICompressedTreeElement = { + element: 1, children: [ + { + element: 11, children: [ + { + element: 111, children: [ + { element: 1111 }, + { element: 1112 }, + { element: 1113 }, + { element: 1114 }, + ] + } + ] + } + ] + }; + + const compressed: IResolvedCompressedTreeElement> = { + element: { elements: [1, 11, 111], incompressible: false }, + children: [ + { element: { elements: [1111], incompressible: false } }, + { element: { elements: [1112], incompressible: false } }, + { element: { elements: [1113], incompressible: false } }, + { element: { elements: [1114], incompressible: false } }, + ] + }; + + assert.deepEqual(resolve(compress(decompressed)), compressed); + assert.deepEqual(resolve(decompress(compressed)), decompressed); + }); + + test('double deep compression', function () { + const decompressed: ICompressedTreeElement = { + element: 1, children: [ + { + element: 11, children: [ + { + element: 111, children: [ + { element: 1112 }, + { element: 1113 }, + ] + } + ] + }, + { + element: 12, children: [ + { + element: 121, children: [ + { element: 1212 }, + { element: 1213 }, + ] + } + ] + } + ] + }; + + const compressed: IResolvedCompressedTreeElement> = { + element: { elements: [1], incompressible: false }, + children: [ + { + element: { elements: [11, 111], incompressible: false }, + children: [ + { element: { elements: [1112], incompressible: false } }, + { element: { elements: [1113], incompressible: false } }, + ] + }, + { + element: { elements: [12, 121], incompressible: false }, + children: [ + { element: { elements: [1212], incompressible: false } }, + { element: { elements: [1213], incompressible: false } }, + ] + } + ] + }; + + assert.deepEqual(resolve(compress(decompressed)), compressed); + assert.deepEqual(resolve(decompress(compressed)), decompressed); + }); + + test('incompressible leaf', function () { + const decompressed: ICompressedTreeElement = { + element: 1, children: [ + { + element: 11, children: [ + { + element: 111, children: [ + { element: 1111, incompressible: true } + ] + } + ] + } + ] + }; + + const compressed: IResolvedCompressedTreeElement> = { + element: { elements: [1, 11, 111], incompressible: false }, + children: [ + { element: { elements: [1111], incompressible: true } } + ] + }; + + assert.deepEqual(resolve(compress(decompressed)), compressed); + assert.deepEqual(resolve(decompress(compressed)), decompressed); + }); + + test('incompressible branch', function () { + const decompressed: ICompressedTreeElement = { + element: 1, children: [ + { + element: 11, children: [ + { + element: 111, incompressible: true, children: [ + { element: 1111 } + ] + } + ] + } + ] + }; + + const compressed: IResolvedCompressedTreeElement> = { + element: { elements: [1, 11], incompressible: false }, + children: [ + { element: { elements: [111, 1111], incompressible: true } } + ] + }; + + assert.deepEqual(resolve(compress(decompressed)), compressed); + assert.deepEqual(resolve(decompress(compressed)), decompressed); + }); + + test('incompressible chain', function () { + const decompressed: ICompressedTreeElement = { + element: 1, children: [ + { + element: 11, children: [ + { + element: 111, incompressible: true, children: [ + { element: 1111, incompressible: true } + ] + } + ] + } + ] + }; + + const compressed: IResolvedCompressedTreeElement> = { + element: { elements: [1, 11], incompressible: false }, + children: [ + { + element: { elements: [111], incompressible: true }, + children: [ + { element: { elements: [1111], incompressible: true } } + ] + } + ] + }; + + assert.deepEqual(resolve(compress(decompressed)), compressed); + assert.deepEqual(resolve(decompress(compressed)), decompressed); + }); + + test('incompressible tree', function () { + const decompressed: ICompressedTreeElement = { + element: 1, children: [ + { + element: 11, incompressible: true, children: [ + { + element: 111, incompressible: true, children: [ + { element: 1111, incompressible: true } + ] + } + ] + } + ] + }; + + const compressed: IResolvedCompressedTreeElement> = { + element: { elements: [1], incompressible: false }, + children: [ + { + element: { elements: [11], incompressible: true }, + children: [ + { + element: { elements: [111], incompressible: true }, + children: [ + { element: { elements: [1111], incompressible: true } } + ] + } + ] + } + ] + }; + + assert.deepEqual(resolve(compress(decompressed)), compressed); + assert.deepEqual(resolve(decompress(compressed)), decompressed); + }); + }); + + function toSpliceable(arr: T[]): ISpliceable { + return { + splice(start: number, deleteCount: number, elements: T[]): void { + arr.splice(start, deleteCount, ...elements); + } + }; + } + + function toArray(list: ITreeNode>[]): T[][] { + return list.map(i => i.element.elements); + } + + suite('CompressedObjectTreeModel', function () { + + test('ctor', () => { + const list: ITreeNode>[] = []; + const model = new CompressedTreeModel(toSpliceable(list)); + assert(model); + assert.equal(list.length, 0); + assert.equal(model.size, 0); + }); + + test('flat', () => { + const list: ITreeNode>[] = []; + const model = new CompressedTreeModel(toSpliceable(list)); + + model.setChildren(null, Iterator.fromArray([ + { element: 0 }, + { element: 1 }, + { element: 2 } + ])); + + assert.deepEqual(toArray(list), [[0], [1], [2]]); + assert.equal(model.size, 3); + + model.setChildren(null, Iterator.fromArray([ + { element: 3 }, + { element: 4 }, + { element: 5 }, + ])); + + assert.deepEqual(toArray(list), [[3], [4], [5]]); + assert.equal(model.size, 3); + + model.setChildren(null, Iterator.empty()); + assert.deepEqual(toArray(list), []); + assert.equal(model.size, 0); + }); + + test('nested', () => { + const list: ITreeNode>[] = []; + const model = new CompressedTreeModel(toSpliceable(list)); + + model.setChildren(null, Iterator.fromArray([ + { + element: 0, children: Iterator.fromArray([ + { element: 10 }, + { element: 11 }, + { element: 12 }, + ]) + }, + { element: 1 }, + { element: 2 } + ])); + + assert.deepEqual(toArray(list), [[0], [10], [11], [12], [1], [2]]); + assert.equal(model.size, 6); + + model.setChildren(12, Iterator.fromArray([ + { element: 120 }, + { element: 121 } + ])); + + assert.deepEqual(toArray(list), [[0], [10], [11], [12], [120], [121], [1], [2]]); + assert.equal(model.size, 8); + + model.setChildren(0, Iterator.empty()); + assert.deepEqual(toArray(list), [[0], [1], [2]]); + assert.equal(model.size, 3); + + model.setChildren(null, Iterator.empty()); + assert.deepEqual(toArray(list), []); + assert.equal(model.size, 0); + }); + + test('compressed', () => { + const list: ITreeNode>[] = []; + const model = new CompressedTreeModel(toSpliceable(list)); + + model.setChildren(null, Iterator.fromArray([ + { + element: 1, children: Iterator.fromArray([{ + element: 11, children: Iterator.fromArray([{ + element: 111, children: Iterator.fromArray([ + { element: 1111 }, + { element: 1112 }, + { element: 1113 }, + ]) + }]) + }]) + } + ])); + + assert.deepEqual(toArray(list), [[1, 11, 111], [1111], [1112], [1113]]); + assert.equal(model.size, 6); + + model.setChildren(11, Iterator.fromArray([ + { element: 111 }, + { element: 112 }, + { element: 113 }, + ])); + + assert.deepEqual(toArray(list), [[1, 11], [111], [112], [113]]); + assert.equal(model.size, 5); + + model.setChildren(113, Iterator.fromArray([ + { element: 1131 } + ])); + + assert.deepEqual(toArray(list), [[1, 11], [111], [112], [113, 1131]]); + assert.equal(model.size, 6); + + model.setChildren(1131, Iterator.fromArray([ + { element: 1132 } + ])); + + assert.deepEqual(toArray(list), [[1, 11], [111], [112], [113, 1131, 1132]]); + assert.equal(model.size, 7); + + model.setChildren(1131, Iterator.fromArray([ + { element: 1132 }, + { element: 1133 }, + ])); + + assert.deepEqual(toArray(list), [[1, 11], [111], [112], [113, 1131], [1132], [1133]]); + assert.equal(model.size, 8); + }); + }); +}); \ No newline at end of file diff --git a/src/vs/base/test/common/decorators.test.ts b/src/vs/base/test/common/decorators.test.ts index aaabb2b50..05a58c318 100644 --- a/src/vs/base/test/common/decorators.test.ts +++ b/src/vs/base/test/common/decorators.test.ts @@ -119,7 +119,7 @@ suite('Decorators', () => { assert.equal(foo.answer, 42); try { - foo['$memoize$answer'] = 1337; + (foo as any)['$memoize$answer'] = 1337; assert(false); } catch (e) { assert.equal(foo.answer, 42); diff --git a/src/vs/base/test/common/event.test.ts b/src/vs/base/test/common/event.test.ts index efc4dec86..039743bbb 100644 --- a/src/vs/base/test/common/event.test.ts +++ b/src/vs/base/test/common/event.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; import { Event, Emitter, EventBufferer, EventMultiplexer, AsyncEmitter, IWaitUntil, PauseableEmitter } from 'vs/base/common/event'; -import { IDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import * as Errors from 'vs/base/common/errors'; import { timeout } from 'vs/base/common/async'; @@ -73,6 +73,27 @@ suite('Event', function () { while (bucket.length) { bucket.pop()!.dispose(); } + doc.setText('boo'); + + // noop + subscription.dispose(); + + doc.setText('boo'); + assert.equal(counter.count, 2); + }); + + test('Emitter, store', function () { + + let bucket = new DisposableStore(); + let doc = new Samples.Document3(); + let subscription = doc.onDidChange(counter.onEvent, counter, bucket); + + doc.setText('far'); + doc.setText('boo'); + + // unhook listener + bucket.clear(); + doc.setText('boo'); // noop subscription.dispose(); diff --git a/src/vs/base/test/common/filters.test.ts b/src/vs/base/test/common/filters.test.ts index c4d582eed..25cc50d57 100644 --- a/src/vs/base/test/common/filters.test.ts +++ b/src/vs/base/test/common/filters.test.ts @@ -13,8 +13,8 @@ function filterOk(filter: IFilter, word: string, wordToMatchAgainst: string, hig } } -function filterNotOk(filter: IFilter, word: string, suggestion: string) { - assert(!filter(word, suggestion)); +function filterNotOk(filter: IFilter, word: string, wordToMatchAgainst: string) { + assert(!filter(word, wordToMatchAgainst), `${word} matched ${wordToMatchAgainst}`); } suite('Filters', () => { @@ -185,23 +185,23 @@ suite('Filters', () => { assert(matchesWords('Debug Console', 'Open: Debug Console')); filterOk(matchesWords, 'gp', 'Git: Pull', [{ start: 0, end: 1 }, { start: 5, end: 6 }]); - filterOk(matchesWords, 'g p', 'Git: Pull', [{ start: 0, end: 1 }, { start: 4, end: 6 }]); + filterOk(matchesWords, 'g p', 'Git: Pull', [{ start: 0, end: 1 }, { start: 3, end: 4 }, { start: 5, end: 6 }]); filterOk(matchesWords, 'gipu', 'Git: Pull', [{ start: 0, end: 2 }, { start: 5, end: 7 }]); filterOk(matchesWords, 'gp', 'Category: Git: Pull', [{ start: 10, end: 11 }, { start: 15, end: 16 }]); - filterOk(matchesWords, 'g p', 'Category: Git: Pull', [{ start: 10, end: 11 }, { start: 14, end: 16 }]); + filterOk(matchesWords, 'g p', 'Category: Git: Pull', [{ start: 10, end: 11 }, { start: 13, end: 14 }, { start: 15, end: 16 }]); filterOk(matchesWords, 'gipu', 'Category: Git: Pull', [{ start: 10, end: 12 }, { start: 15, end: 17 }]); filterNotOk(matchesWords, 'it', 'Git: Pull'); filterNotOk(matchesWords, 'll', 'Git: Pull'); filterOk(matchesWords, 'git: プル', 'git: プル', [{ start: 0, end: 7 }]); - filterOk(matchesWords, 'git プル', 'git: プル', [{ start: 0, end: 3 }, { start: 4, end: 7 }]); + filterOk(matchesWords, 'git プル', 'git: プル', [{ start: 0, end: 4 }, { start: 5, end: 7 }]); filterOk(matchesWords, 'öäk', 'Öhm: Älles Klar', [{ start: 0, end: 1 }, { start: 5, end: 6 }, { start: 11, end: 12 }]); - assert.ok(matchesWords('gipu', 'Category: Git: Pull', true) === null); - assert.deepEqual(matchesWords('pu', 'Category: Git: Pull', true), [{ start: 15, end: 17 }]); + // assert.ok(matchesWords('gipu', 'Category: Git: Pull', true) === null); + // assert.deepEqual(matchesWords('pu', 'Category: Git: Pull', true), [{ start: 15, end: 17 }]); filterOk(matchesWords, 'bar', 'foo-bar'); filterOk(matchesWords, 'bar test', 'foo-bar test'); @@ -212,7 +212,12 @@ suite('Filters', () => { filterNotOk(matchesWords, 'bar est', 'foo-bar test'); filterNotOk(matchesWords, 'fo ar', 'foo-bar test'); filterNotOk(matchesWords, 'for', 'foo-bar test'); - filterNotOk(matchesWords, 'foo bar', 'foo-bar'); + + filterOk(matchesWords, 'foo bar', 'foo-bar'); + filterOk(matchesWords, 'foo bar', '123 foo-bar 456'); + filterOk(matchesWords, 'foo+bar', 'foo-bar'); + filterOk(matchesWords, 'foo-bar', 'foo bar'); + filterOk(matchesWords, 'foo:bar', 'foo:bar'); }); function assertMatches(pattern: string, word: string, decoratedWord: string | undefined, filter: FuzzyScorer, opts: { patternPos?: number, wordPos?: number, firstMatchCanBeWeak?: boolean } = {}) { @@ -465,4 +470,19 @@ suite('Filters', () => { test('List highlight filter: Not all characters from match are highlighterd #66923', () => { assertMatches('foo', 'barbarbarbarbarbarbarbarbarbarbarbarbarbarbarbar_foo', 'barbarbarbarbarbarbarbarbarbarbarbarbarbarbarbar_^f^o^o', fuzzyScore); }); + + test('Autocompletion is matched against truncated filterText to 54 characters #74133', () => { + assertMatches( + 'foo', + 'ffffffffffffffffffffffffffffbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbar_foo', + 'ffffffffffffffffffffffffffffbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbar_^f^o^o', + fuzzyScore + ); + assertMatches( + 'foo', + 'Gffffffffffffffffffffffffffffbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbar_foo', + undefined, + fuzzyScore + ); + }); }); diff --git a/src/vs/base/test/common/iterator.test.ts b/src/vs/base/test/common/iterator.test.ts new file mode 100644 index 000000000..b7a165c50 --- /dev/null +++ b/src/vs/base/test/common/iterator.test.ts @@ -0,0 +1,19 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import { Iterator } from 'vs/base/common/iterator'; + +suite('Iterator', () => { + test('concat', () => { + const first = Iterator.fromArray([1, 2, 3]); + const second = Iterator.fromArray([4, 5, 6]); + const third = Iterator.fromArray([7, 8, 9]); + const actualIterator = Iterator.concat(first, second, third); + const actual = Iterator.collect(actualIterator); + + assert.deepEqual(actual, [1, 2, 3, 4, 5, 6, 7, 8, 9]); + }); +}); \ No newline at end of file diff --git a/src/vs/base/test/common/lifecycle.test.ts b/src/vs/base/test/common/lifecycle.test.ts index 29e93e64a..46d8a254b 100644 --- a/src/vs/base/test/common/lifecycle.test.ts +++ b/src/vs/base/test/common/lifecycle.test.ts @@ -42,7 +42,8 @@ suite('Lifecycle', () => { assert(!disposable.isDisposed); assert(!disposable2.isDisposed); - dispose(disposable, disposable2); + dispose(disposable); + dispose(disposable2); assert(disposable.isDisposed); assert(disposable2.isDisposed); diff --git a/src/vs/base/test/common/mime.test.ts b/src/vs/base/test/common/mime.test.ts index 75f6d531f..7c99c964c 100644 --- a/src/vs/base/test/common/mime.test.ts +++ b/src/vs/base/test/common/mime.test.ts @@ -4,41 +4,43 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; import { guessMimeTypes, registerTextMime, suggestFilename } from 'vs/base/common/mime'; +import { URI } from 'vs/base/common/uri'; suite('Mime', () => { + test('Dynamically Register Text Mime', () => { - let guess = guessMimeTypes('foo.monaco'); + let guess = guessMimeTypes(URI.file('foo.monaco')); assert.deepEqual(guess, ['application/unknown']); registerTextMime({ id: 'monaco', extension: '.monaco', mime: 'text/monaco' }); - guess = guessMimeTypes('foo.monaco'); + guess = guessMimeTypes(URI.file('foo.monaco')); assert.deepEqual(guess, ['text/monaco', 'text/plain']); - guess = guessMimeTypes('.monaco'); + guess = guessMimeTypes(URI.file('.monaco')); assert.deepEqual(guess, ['text/monaco', 'text/plain']); registerTextMime({ id: 'codefile', filename: 'Codefile', mime: 'text/code' }); - guess = guessMimeTypes('Codefile'); + guess = guessMimeTypes(URI.file('Codefile')); assert.deepEqual(guess, ['text/code', 'text/plain']); - guess = guessMimeTypes('foo.Codefile'); + guess = guessMimeTypes(URI.file('foo.Codefile')); assert.deepEqual(guess, ['application/unknown']); registerTextMime({ id: 'docker', filepattern: 'Docker*', mime: 'text/docker' }); - guess = guessMimeTypes('Docker-debug'); + guess = guessMimeTypes(URI.file('Docker-debug')); assert.deepEqual(guess, ['text/docker', 'text/plain']); - guess = guessMimeTypes('docker-PROD'); + guess = guessMimeTypes(URI.file('docker-PROD')); assert.deepEqual(guess, ['text/docker', 'text/plain']); registerTextMime({ id: 'niceregex', mime: 'text/nice-regex', firstline: /RegexesAreNice/ }); - guess = guessMimeTypes('Randomfile.noregistration', 'RegexesAreNice'); + guess = guessMimeTypes(URI.file('Randomfile.noregistration'), 'RegexesAreNice'); assert.deepEqual(guess, ['text/nice-regex', 'text/plain']); - guess = guessMimeTypes('Randomfile.noregistration', 'RegexesAreNotNice'); + guess = guessMimeTypes(URI.file('Randomfile.noregistration'), 'RegexesAreNotNice'); assert.deepEqual(guess, ['application/unknown']); - guess = guessMimeTypes('Codefile', 'RegexesAreNice'); + guess = guessMimeTypes(URI.file('Codefile'), 'RegexesAreNice'); assert.deepEqual(guess, ['text/code', 'text/plain']); }); @@ -46,32 +48,37 @@ suite('Mime', () => { registerTextMime({ id: 'monaco', extension: '.monaco', mime: 'text/monaco' }); registerTextMime({ id: 'foobar', mime: 'text/foobar', firstline: /foobar/ }); - let guess = guessMimeTypes('foo.monaco'); + let guess = guessMimeTypes(URI.file('foo.monaco')); assert.deepEqual(guess, ['text/monaco', 'text/plain']); - guess = guessMimeTypes('foo.monaco', 'foobar'); + guess = guessMimeTypes(URI.file('foo.monaco'), 'foobar'); assert.deepEqual(guess, ['text/monaco', 'text/plain']); registerTextMime({ id: 'docker', filename: 'dockerfile', mime: 'text/winner' }); registerTextMime({ id: 'docker', filepattern: 'dockerfile*', mime: 'text/looser' }); - guess = guessMimeTypes('dockerfile'); + guess = guessMimeTypes(URI.file('dockerfile')); assert.deepEqual(guess, ['text/winner', 'text/plain']); + + registerTextMime({ id: 'azure-looser', mime: 'text/azure-looser', firstline: /azure/ }); + registerTextMime({ id: 'azure-winner', mime: 'text/azure-winner', firstline: /azure/ }); + guess = guessMimeTypes(URI.file('azure'), 'azure'); + assert.deepEqual(guess, ['text/azure-winner', 'text/plain']); }); test('Specificity priority 1', () => { registerTextMime({ id: 'monaco2', extension: '.monaco2', mime: 'text/monaco2' }); registerTextMime({ id: 'monaco2', filename: 'specific.monaco2', mime: 'text/specific-monaco2' }); - assert.deepEqual(guessMimeTypes('specific.monaco2'), ['text/specific-monaco2', 'text/plain']); - assert.deepEqual(guessMimeTypes('foo.monaco2'), ['text/monaco2', 'text/plain']); + assert.deepEqual(guessMimeTypes(URI.file('specific.monaco2')), ['text/specific-monaco2', 'text/plain']); + assert.deepEqual(guessMimeTypes(URI.file('foo.monaco2')), ['text/monaco2', 'text/plain']); }); test('Specificity priority 2', () => { registerTextMime({ id: 'monaco3', filename: 'specific.monaco3', mime: 'text/specific-monaco3' }); registerTextMime({ id: 'monaco3', extension: '.monaco3', mime: 'text/monaco3' }); - assert.deepEqual(guessMimeTypes('specific.monaco3'), ['text/specific-monaco3', 'text/plain']); - assert.deepEqual(guessMimeTypes('foo.monaco3'), ['text/monaco3', 'text/plain']); + assert.deepEqual(guessMimeTypes(URI.file('specific.monaco3')), ['text/specific-monaco3', 'text/plain']); + assert.deepEqual(guessMimeTypes(URI.file('foo.monaco3')), ['text/monaco3', 'text/plain']); }); test('Mimes Priority - Longest Extension wins', () => { @@ -79,13 +86,13 @@ suite('Mime', () => { registerTextMime({ id: 'monaco', extension: '.monaco.xml', mime: 'text/monaco-xml' }); registerTextMime({ id: 'monaco', extension: '.monaco.xml.build', mime: 'text/monaco-xml-build' }); - let guess = guessMimeTypes('foo.monaco'); + let guess = guessMimeTypes(URI.file('foo.monaco')); assert.deepEqual(guess, ['text/monaco', 'text/plain']); - guess = guessMimeTypes('foo.monaco.xml'); + guess = guessMimeTypes(URI.file('foo.monaco.xml')); assert.deepEqual(guess, ['text/monaco-xml', 'text/plain']); - guess = guessMimeTypes('foo.monaco.xml.build'); + guess = guessMimeTypes(URI.file('foo.monaco.xml.build')); assert.deepEqual(guess, ['text/monaco-xml-build', 'text/plain']); }); @@ -93,7 +100,7 @@ suite('Mime', () => { registerTextMime({ id: 'monaco', extension: '.monaco.xnl', mime: 'text/monaco', userConfigured: true }); registerTextMime({ id: 'monaco', extension: '.monaco.xml', mime: 'text/monaco-xml' }); - let guess = guessMimeTypes('foo.monaco.xnl'); + let guess = guessMimeTypes(URI.file('foo.monaco.xnl')); assert.deepEqual(guess, ['text/monaco', 'text/plain']); }); @@ -101,7 +108,7 @@ suite('Mime', () => { registerTextMime({ id: 'monaco', filepattern: '**/dot.monaco.xml', mime: 'text/monaco' }); registerTextMime({ id: 'other', filepattern: '*ot.other.xml', mime: 'text/other' }); - let guess = guessMimeTypes('/some/path/dot.monaco.xml'); + let guess = guessMimeTypes(URI.file('/some/path/dot.monaco.xml')); assert.deepEqual(guess, ['text/monaco', 'text/plain']); }); @@ -109,10 +116,16 @@ suite('Mime', () => { registerTextMime({ id: 'monaco', filepattern: '**/dot.monaco.xml', mime: 'text/monaco' }); registerTextMime({ id: 'other', filepattern: '**/dot.monaco.xml', mime: 'text/other' }); - let guess = guessMimeTypes('/some/path/dot.monaco.xml'); + let guess = guessMimeTypes(URI.file('/some/path/dot.monaco.xml')); assert.deepEqual(guess, ['text/other', 'text/plain']); }); + test('Data URIs', () => { + registerTextMime({ id: 'data', extension: '.data', mime: 'text/data' }); + + assert.deepEqual(guessMimeTypes(URI.parse(`data:;label:something.data;description:data,`)), ['text/data', 'text/plain']); + }); + test('Filename Suggestion - Suggest prefix only when there are no relevant extensions', () => { const id = 'plumbus0'; const mime = `text/${id}`; diff --git a/src/vs/base/test/common/resources.test.ts b/src/vs/base/test/common/resources.test.ts index 22d576dd3..cb5353622 100644 --- a/src/vs/base/test/common/resources.test.ts +++ b/src/vs/base/test/common/resources.test.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { dirname, basename, distinctParents, joinPath, isEqual, isEqualOrParent, hasToIgnoreCase, normalizePath, isAbsolutePath, relativePath, removeTrailingPathSeparator, hasTrailingPathSeparator, resolvePath } from 'vs/base/common/resources'; +import { dirname, basename, distinctParents, joinPath, isEqual, isEqualOrParent, hasToIgnoreCase, normalizePath, isAbsolutePath, relativePath, removeTrailingPathSeparator, hasTrailingPathSeparator, resolvePath, addTrailingPathSeparator } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { isWindows } from 'vs/base/common/platform'; import { toSlashes } from 'vs/base/common/extpath'; @@ -178,6 +178,9 @@ suite('Resources', () => { assertEqualURI(removeTrailingPathSeparator(u1), expected, u1.toString()); } + function assertAddTrailingSeparator(u1: URI, expected: URI) { + assertEqualURI(addTrailingPathSeparator(u1), expected, u1.toString()); + } test('trailingPathSeparator', () => { assertTrailingSeparator(URI.parse('foo://a/foo'), false); @@ -190,6 +193,11 @@ suite('Resources', () => { assertRemoveTrailingSeparator(URI.parse('foo://a/'), URI.parse('foo://a/')); assertRemoveTrailingSeparator(URI.parse('foo://a'), URI.parse('foo://a')); + assertAddTrailingSeparator(URI.parse('foo://a/foo'), URI.parse('foo://a/foo/')); + assertAddTrailingSeparator(URI.parse('foo://a/foo/'), URI.parse('foo://a/foo/')); + assertAddTrailingSeparator(URI.parse('foo://a/'), URI.parse('foo://a/')); + assertAddTrailingSeparator(URI.parse('foo://a'), URI.parse('foo://a/')); + if (isWindows) { assertTrailingSeparator(URI.file('c:\\a\\foo'), false); assertTrailingSeparator(URI.file('c:\\a\\foo\\'), true); @@ -202,6 +210,12 @@ suite('Resources', () => { assertRemoveTrailingSeparator(URI.file('c:\\'), URI.file('c:\\')); assertRemoveTrailingSeparator(URI.file('\\\\server\\share\\some\\'), URI.file('\\\\server\\share\\some')); assertRemoveTrailingSeparator(URI.file('\\\\server\\share\\'), URI.file('\\\\server\\share\\')); + + assertAddTrailingSeparator(URI.file('c:\\a\\foo'), URI.file('c:\\a\\foo\\')); + assertAddTrailingSeparator(URI.file('c:\\a\\foo\\'), URI.file('c:\\a\\foo\\')); + assertAddTrailingSeparator(URI.file('c:\\'), URI.file('c:\\')); + assertAddTrailingSeparator(URI.file('\\\\server\\share\\some'), URI.file('\\\\server\\share\\some\\')); + assertAddTrailingSeparator(URI.file('\\\\server\\share\\some\\'), URI.file('\\\\server\\share\\some\\')); } else { assertTrailingSeparator(URI.file('/foo/bar'), false); assertTrailingSeparator(URI.file('/foo/bar/'), true); @@ -210,17 +224,21 @@ suite('Resources', () => { assertRemoveTrailingSeparator(URI.file('/foo/bar'), URI.file('/foo/bar')); assertRemoveTrailingSeparator(URI.file('/foo/bar/'), URI.file('/foo/bar')); assertRemoveTrailingSeparator(URI.file('/'), URI.file('/')); + + assertAddTrailingSeparator(URI.file('/foo/bar'), URI.file('/foo/bar/')); + assertAddTrailingSeparator(URI.file('/foo/bar/'), URI.file('/foo/bar/')); + assertAddTrailingSeparator(URI.file('/'), URI.file('/')); } }); function assertEqualURI(actual: URI, expected: URI, message?: string) { if (!isEqual(expected, actual)) { - assert.equal(expected.toString(), actual.toString(), message); + assert.equal(actual.toString(), expected.toString(), message); } } - function assertRelativePath(u1: URI, u2: URI, expectedPath: string | undefined, ignoreJoin?: boolean) { - assert.equal(relativePath(u1, u2), expectedPath, `from ${u1.toString()} to ${u2.toString()}`); + function assertRelativePath(u1: URI, u2: URI, expectedPath: string | undefined, ignoreJoin?: boolean, ignoreCase?: boolean) { + assert.equal(relativePath(u1, u2, ignoreCase), expectedPath, `from ${u1.toString()} to ${u2.toString()}`); if (expectedPath !== undefined && !ignoreJoin) { assertEqualURI(removeTrailingPathSeparator(joinPath(u1, expectedPath)), removeTrailingPathSeparator(u2), 'joinPath on relativePath should be equal'); } @@ -245,6 +263,11 @@ suite('Resources', () => { assertRelativePath(URI.parse('foo://a2/b'), URI.parse('foo://a/b'), undefined); assertRelativePath(URI.parse('goo://a/b'), URI.parse('foo://a/b'), undefined); + assertRelativePath(URI.parse('foo://a/foo'), URI.parse('foo://A/FOO/bar/goo'), 'bar/goo', false, true); + assertRelativePath(URI.parse('foo://a/foo'), URI.parse('foo://A/FOO/BAR/GOO'), 'BAR/GOO', false, true); + assertRelativePath(URI.parse('foo://a/foo/xoo'), URI.parse('foo://A/FOO/BAR/GOO'), '../BAR/GOO', false, true); + assertRelativePath(URI.parse('foo:///c:/a/foo'), URI.parse('foo:///C:/a/foo/xoo/'), 'xoo', false, true); + if (isWindows) { assertRelativePath(URI.file('c:\\foo\\bar'), URI.file('c:\\foo\\bar'), ''); assertRelativePath(URI.file('c:\\foo\\bar\\huu'), URI.file('c:\\foo\\bar'), '..'); diff --git a/src/vs/base/test/common/uri.test.ts b/src/vs/base/test/common/uri.test.ts index 85f2ad691..0a72ec398 100644 --- a/src/vs/base/test/common/uri.test.ts +++ b/src/vs/base/test/common/uri.test.ts @@ -426,6 +426,19 @@ suite('URI', () => { assert.equal(uri.toString(true), input); }); + test('Unable to open \'%A0.txt\': URI malformed #76506', function () { + + let uri = URI.file('/foo/%A0.txt'); + let uri2 = URI.parse(uri.toString()); + assert.equal(uri.scheme, uri2.scheme); + assert.equal(uri.path, uri2.path); + + uri = URI.file('/foo/%2e.txt'); + uri2 = URI.parse(uri.toString()); + assert.equal(uri.scheme, uri2.scheme); + assert.equal(uri.path, uri2.path); + }); + test('URI - (de)serialize', function () { const values = [ diff --git a/src/vs/base/test/common/buffer.test.ts b/src/vs/base/test/node/buffer.test.ts similarity index 90% rename from src/vs/base/test/common/buffer.test.ts rename to src/vs/base/test/node/buffer.test.ts index c5a3cd676..65f84a66d 100644 --- a/src/vs/base/test/common/buffer.test.ts +++ b/src/vs/base/test/node/buffer.test.ts @@ -364,4 +364,42 @@ suite('Buffer', () => { assert.equal(ended, false); assert.equal(errors.length, 0); }); + + test('Performance issue with VSBuffer#slice #76076', function () { + // Buffer#slice creates a view + { + const buff = Buffer.from([10, 20, 30, 40]); + const b2 = buff.slice(1, 3); + assert.equal(buff[1], 20); + assert.equal(b2[0], 20); + + buff[1] = 17; // modify buff AND b2 + assert.equal(buff[1], 17); + assert.equal(b2[0], 17); + } + + // TypedArray#slice creates a copy + { + const unit = new Uint8Array([10, 20, 30, 40]); + const u2 = unit.slice(1, 3); + assert.equal(unit[1], 20); + assert.equal(u2[0], 20); + + unit[1] = 17; // modify unit, NOT b2 + assert.equal(unit[1], 17); + assert.equal(u2[0], 20); + } + + // TypedArray#subarray creates a view + { + const unit = new Uint8Array([10, 20, 30, 40]); + const u2 = unit.subarray(1, 3); + assert.equal(unit[1], 20); + assert.equal(u2[0], 20); + + unit[1] = 17; // modify unit AND b2 + assert.equal(unit[1], 17); + assert.equal(u2[0], 17); + } + }); }); diff --git a/src/vs/base/test/node/config.test.ts b/src/vs/base/test/node/config.test.ts index 055393500..3fa8f78de 100644 --- a/src/vs/base/test/node/config.test.ts +++ b/src/vs/base/test/node/config.test.ts @@ -20,7 +20,7 @@ suite('Config', () => { const newDir = path.join(parentDir, 'config', id); const testFile = path.join(newDir, 'config.json'); - let watcher = new ConfigWatcher(testFile); + let watcher = new ConfigWatcher<{}>(testFile); let config = watcher.getConfig(); assert.ok(config); diff --git a/src/vs/base/test/node/id.test.ts b/src/vs/base/test/node/id.test.ts index 689bb126d..637afa5b5 100644 --- a/src/vs/base/test/node/id.test.ts +++ b/src/vs/base/test/node/id.test.ts @@ -3,8 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import * as getmac from 'getmac'; import { getMachineId } from 'vs/base/node/id'; +import { getMac } from 'vs/base/node/macAddress'; suite('ID', () => { @@ -16,9 +16,7 @@ suite('ID', () => { }); test('getMac', () => { - return new Promise((resolve, reject) => { - getmac.getMac((err, macAddress) => err ? reject(err) : resolve(macAddress)); - }).then(macAddress => { + return getMac().then(macAddress => { assert.ok(/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/.test(macAddress), `Expected a MAC address, got: ${macAddress}`); }); }); diff --git a/src/vs/base/test/node/pfs/pfs.test.ts b/src/vs/base/test/node/pfs/pfs.test.ts index 4f09ad2b5..060913bbe 100644 --- a/src/vs/base/test/node/pfs/pfs.test.ts +++ b/src/vs/base/test/node/pfs/pfs.test.ts @@ -16,6 +16,7 @@ import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { isWindows, isLinux } from 'vs/base/common/platform'; import { canNormalize } from 'vs/base/common/normalization'; import { VSBuffer } from 'vs/base/common/buffer'; +import { join } from 'path'; const chunkSize = 64 * 1024; const readError = 'Error while reading'; @@ -386,6 +387,31 @@ suite('PFS', () => { } }); + test('readdirWithFileTypes', async () => { + if (canNormalize && typeof process.versions['electron'] !== 'undefined' /* needs electron */) { + const id = uuid.generateUuid(); + const parentDir = path.join(os.tmpdir(), 'vsctests', id); + const testDir = join(parentDir, 'pfs', id); + + const newDir = path.join(testDir, 'öäü'); + await pfs.mkdirp(newDir, 493); + + await pfs.writeFile(join(testDir, 'somefile.txt'), 'contents'); + + assert.ok(fs.existsSync(newDir)); + + const children = await pfs.readdirWithFileTypes(testDir); + + assert.equal(children.some(n => n.name === 'öäü'), true); // Mac always converts to NFD, so + assert.equal(children.some(n => n.isDirectory()), true); + + assert.equal(children.some(n => n.name === 'somefile.txt'), true); + assert.equal(children.some(n => n.isFile()), true); + + await pfs.rimraf(parentDir); + } + }); + test('writeFile (string)', async () => { const smallData = 'Hello World'; const bigData = (new Array(100 * 1024)).join('Large String\n'); diff --git a/src/vs/base/test/node/storage/storage.test.ts b/src/vs/base/test/node/storage/storage.test.ts deleted file mode 100644 index 784a797b8..000000000 --- a/src/vs/base/test/node/storage/storage.test.ts +++ /dev/null @@ -1,808 +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 { Storage, SQLiteStorageDatabase, IStorageDatabase, ISQLiteStorageDatabaseOptions, IStorageItemsChangeEvent } from 'vs/base/node/storage'; -import { generateUuid } from 'vs/base/common/uuid'; -import { join } from 'vs/base/common/path'; -import { tmpdir } from 'os'; -import { equal, ok } from 'assert'; -import { mkdirp, writeFile, exists, unlink, rimraf, RimRafMode } from 'vs/base/node/pfs'; -import { timeout } from 'vs/base/common/async'; -import { Event, Emitter } from 'vs/base/common/event'; -import { isWindows } from 'vs/base/common/platform'; - -suite('Storage Library', () => { - - function uniqueStorageDir(): string { - const id = generateUuid(); - - return join(tmpdir(), 'vsctests', id, 'storage2', id); - } - - test('basics', async () => { - const storageDir = uniqueStorageDir(); - await mkdirp(storageDir); - - const storage = new Storage(new SQLiteStorageDatabase(join(storageDir, 'storage.db'))); - - await storage.init(); - - // Empty fallbacks - equal(storage.get('foo', 'bar'), 'bar'); - equal(storage.getNumber('foo', 55), 55); - equal(storage.getBoolean('foo', true), true); - - let changes = new Set(); - storage.onDidChangeStorage(key => { - changes.add(key); - }); - - // Simple updates - const set1Promise = storage.set('bar', 'foo'); - const set2Promise = storage.set('barNumber', 55); - const set3Promise = storage.set('barBoolean', true); - - equal(storage.get('bar'), 'foo'); - equal(storage.getNumber('barNumber'), 55); - equal(storage.getBoolean('barBoolean'), true); - - equal(changes.size, 3); - ok(changes.has('bar')); - ok(changes.has('barNumber')); - ok(changes.has('barBoolean')); - - let setPromiseResolved = false; - await Promise.all([set1Promise, set2Promise, set3Promise]).then(() => setPromiseResolved = true); - equal(setPromiseResolved, true); - - changes = new Set(); - - // Does not trigger events for same update values - storage.set('bar', 'foo'); - storage.set('barNumber', 55); - storage.set('barBoolean', true); - equal(changes.size, 0); - - // Simple deletes - const delete1Promise = storage.delete('bar'); - const delete2Promise = storage.delete('barNumber'); - const delete3Promise = storage.delete('barBoolean'); - - ok(!storage.get('bar')); - ok(!storage.getNumber('barNumber')); - ok(!storage.getBoolean('barBoolean')); - - equal(changes.size, 3); - ok(changes.has('bar')); - ok(changes.has('barNumber')); - ok(changes.has('barBoolean')); - - changes = new Set(); - - // Does not trigger events for same delete values - storage.delete('bar'); - storage.delete('barNumber'); - storage.delete('barBoolean'); - equal(changes.size, 0); - - let deletePromiseResolved = false; - await Promise.all([delete1Promise, delete2Promise, delete3Promise]).then(() => deletePromiseResolved = true); - equal(deletePromiseResolved, true); - - await storage.close(); - await rimraf(storageDir, RimRafMode.MOVE); - }); - - test('external changes', async () => { - const storageDir = uniqueStorageDir(); - await mkdirp(storageDir); - - class TestSQLiteStorageDatabase extends SQLiteStorageDatabase { - private _onDidChangeItemsExternal = new Emitter(); - get onDidChangeItemsExternal(): Event { return this._onDidChangeItemsExternal.event; } - - fireDidChangeItemsExternal(event: IStorageItemsChangeEvent): void { - this._onDidChangeItemsExternal.fire(event); - } - } - - const database = new TestSQLiteStorageDatabase(join(storageDir, 'storage.db')); - const storage = new Storage(database); - - let changes = new Set(); - storage.onDidChangeStorage(key => { - changes.add(key); - }); - - await storage.init(); - - await storage.set('foo', 'bar'); - ok(changes.has('foo')); - changes.clear(); - - // Nothing happens if changing to same value - const change = new Map(); - change.set('foo', 'bar'); - database.fireDidChangeItemsExternal({ items: change }); - equal(changes.size, 0); - - // Change is accepted if valid - change.set('foo', 'bar1'); - database.fireDidChangeItemsExternal({ items: change }); - ok(changes.has('foo')); - equal(storage.get('foo'), 'bar1'); - changes.clear(); - - // Delete is accepted - change.set('foo', undefined); - database.fireDidChangeItemsExternal({ items: change }); - ok(changes.has('foo')); - equal(storage.get('foo', null!), null); - changes.clear(); - - // Nothing happens if changing to same value - change.set('foo', undefined); - database.fireDidChangeItemsExternal({ items: change }); - equal(changes.size, 0); - - await storage.close(); - await rimraf(storageDir, RimRafMode.MOVE); - }); - - test('close flushes data', async () => { - const storageDir = uniqueStorageDir(); - await mkdirp(storageDir); - - let storage = new Storage(new SQLiteStorageDatabase(join(storageDir, 'storage.db'))); - await storage.init(); - - const set1Promise = storage.set('foo', 'bar'); - const set2Promise = storage.set('bar', 'foo'); - - equal(storage.get('foo'), 'bar'); - equal(storage.get('bar'), 'foo'); - - let setPromiseResolved = false; - Promise.all([set1Promise, set2Promise]).then(() => setPromiseResolved = true); - - await storage.close(); - - equal(setPromiseResolved, true); - - storage = new Storage(new SQLiteStorageDatabase(join(storageDir, 'storage.db'))); - await storage.init(); - - equal(storage.get('foo'), 'bar'); - equal(storage.get('bar'), 'foo'); - - await storage.close(); - - storage = new Storage(new SQLiteStorageDatabase(join(storageDir, 'storage.db'))); - await storage.init(); - - const delete1Promise = storage.delete('foo'); - const delete2Promise = storage.delete('bar'); - - ok(!storage.get('foo')); - ok(!storage.get('bar')); - - let deletePromiseResolved = false; - Promise.all([delete1Promise, delete2Promise]).then(() => deletePromiseResolved = true); - - await storage.close(); - - equal(deletePromiseResolved, true); - - storage = new Storage(new SQLiteStorageDatabase(join(storageDir, 'storage.db'))); - await storage.init(); - - ok(!storage.get('foo')); - ok(!storage.get('bar')); - - await storage.close(); - await rimraf(storageDir, RimRafMode.MOVE); - }); - - test('conflicting updates', async () => { - const storageDir = uniqueStorageDir(); - await mkdirp(storageDir); - - let storage = new Storage(new SQLiteStorageDatabase(join(storageDir, 'storage.db'))); - await storage.init(); - - let changes = new Set(); - storage.onDidChangeStorage(key => { - changes.add(key); - }); - - const set1Promise = storage.set('foo', 'bar1'); - const set2Promise = storage.set('foo', 'bar2'); - const set3Promise = storage.set('foo', 'bar3'); - - equal(storage.get('foo'), 'bar3'); - equal(changes.size, 1); - ok(changes.has('foo')); - - let setPromiseResolved = false; - await Promise.all([set1Promise, set2Promise, set3Promise]).then(() => setPromiseResolved = true); - ok(setPromiseResolved); - - changes = new Set(); - - const set4Promise = storage.set('bar', 'foo'); - const delete1Promise = storage.delete('bar'); - - ok(!storage.get('bar')); - - equal(changes.size, 1); - ok(changes.has('bar')); - - let setAndDeletePromiseResolved = false; - await Promise.all([set4Promise, delete1Promise]).then(() => setAndDeletePromiseResolved = true); - ok(setAndDeletePromiseResolved); - - await storage.close(); - await rimraf(storageDir, RimRafMode.MOVE); - }); - - test('corrupt DB recovers', async () => { - const storageDir = uniqueStorageDir(); - await mkdirp(storageDir); - - const storageFile = join(storageDir, 'storage.db'); - - let storage = new Storage(new SQLiteStorageDatabase(storageFile)); - await storage.init(); - - await storage.set('bar', 'foo'); - - await writeFile(storageFile, 'This is a broken DB'); - - await storage.set('foo', 'bar'); - - equal(storage.get('bar'), 'foo'); - equal(storage.get('foo'), 'bar'); - - await storage.close(); - - storage = new Storage(new SQLiteStorageDatabase(storageFile)); - await storage.init(); - - equal(storage.get('bar'), 'foo'); - equal(storage.get('foo'), 'bar'); - - await storage.close(); - await rimraf(storageDir, RimRafMode.MOVE); - }); -}); - -suite('SQLite Storage Library', () => { - - function uniqueStorageDir(): string { - const id = generateUuid(); - - return join(tmpdir(), 'vsctests', id, 'storage', id); - } - - function toSet(elements: string[]): Set { - const set = new Set(); - elements.forEach(element => set.add(element)); - - return set; - } - - async function testDBBasics(path: string, logError?: (error: Error) => void) { - let options!: ISQLiteStorageDatabaseOptions; - if (logError) { - options = { - logging: { - logError - } - }; - } - - const storage = new SQLiteStorageDatabase(path, options); - - const items = new Map(); - items.set('foo', 'bar'); - items.set('some/foo/path', 'some/bar/path'); - items.set(JSON.stringify({ foo: 'bar' }), JSON.stringify({ bar: 'foo' })); - - let storedItems = await storage.getItems(); - equal(storedItems.size, 0); - - await storage.updateItems({ insert: items }); - - storedItems = await storage.getItems(); - equal(storedItems.size, items.size); - equal(storedItems.get('foo'), 'bar'); - equal(storedItems.get('some/foo/path'), 'some/bar/path'); - equal(storedItems.get(JSON.stringify({ foo: 'bar' })), JSON.stringify({ bar: 'foo' })); - - await storage.updateItems({ delete: toSet(['foo']) }); - storedItems = await storage.getItems(); - equal(storedItems.size, items.size - 1); - ok(!storedItems.has('foo')); - equal(storedItems.get('some/foo/path'), 'some/bar/path'); - equal(storedItems.get(JSON.stringify({ foo: 'bar' })), JSON.stringify({ bar: 'foo' })); - - await storage.updateItems({ insert: items }); - storedItems = await storage.getItems(); - equal(storedItems.size, items.size); - equal(storedItems.get('foo'), 'bar'); - equal(storedItems.get('some/foo/path'), 'some/bar/path'); - equal(storedItems.get(JSON.stringify({ foo: 'bar' })), JSON.stringify({ bar: 'foo' })); - - const itemsChange = new Map(); - itemsChange.set('foo', 'otherbar'); - await storage.updateItems({ insert: itemsChange }); - - storedItems = await storage.getItems(); - equal(storedItems.get('foo'), 'otherbar'); - - await storage.updateItems({ delete: toSet(['foo', 'bar', 'some/foo/path', JSON.stringify({ foo: 'bar' })]) }); - storedItems = await storage.getItems(); - equal(storedItems.size, 0); - - await storage.updateItems({ insert: items, delete: toSet(['foo', 'some/foo/path', 'other']) }); - storedItems = await storage.getItems(); - equal(storedItems.size, 1); - equal(storedItems.get(JSON.stringify({ foo: 'bar' })), JSON.stringify({ bar: 'foo' })); - - await storage.updateItems({ delete: toSet([JSON.stringify({ foo: 'bar' })]) }); - storedItems = await storage.getItems(); - equal(storedItems.size, 0); - - let recoveryCalled = false; - await storage.close(() => { - recoveryCalled = true; - - return new Map(); - }); - - equal(recoveryCalled, false); - } - - test('basics', async () => { - const storageDir = uniqueStorageDir(); - - await mkdirp(storageDir); - - await testDBBasics(join(storageDir, 'storage.db')); - - await rimraf(storageDir, RimRafMode.MOVE); - }); - - test('basics (open multiple times)', async () => { - const storageDir = uniqueStorageDir(); - - await mkdirp(storageDir); - - await testDBBasics(join(storageDir, 'storage.db')); - await testDBBasics(join(storageDir, 'storage.db')); - - await rimraf(storageDir, RimRafMode.MOVE); - }); - - test('basics (corrupt DB falls back to empty DB)', async () => { - const storageDir = uniqueStorageDir(); - - await mkdirp(storageDir); - - const corruptDBPath = join(storageDir, 'broken.db'); - await writeFile(corruptDBPath, 'This is a broken DB'); - - let expectedError: any; - await testDBBasics(corruptDBPath, error => { - expectedError = error; - }); - - ok(expectedError); - - await rimraf(storageDir, RimRafMode.MOVE); - }); - - test('basics (corrupt DB restores from previous backup)', async () => { - const storageDir = uniqueStorageDir(); - - await mkdirp(storageDir); - - const storagePath = join(storageDir, 'storage.db'); - let storage = new SQLiteStorageDatabase(storagePath); - - const items = new Map(); - items.set('foo', 'bar'); - items.set('some/foo/path', 'some/bar/path'); - items.set(JSON.stringify({ foo: 'bar' }), JSON.stringify({ bar: 'foo' })); - - await storage.updateItems({ insert: items }); - await storage.close(); - - await writeFile(storagePath, 'This is now a broken DB'); - - storage = new SQLiteStorageDatabase(storagePath); - - const storedItems = await storage.getItems(); - equal(storedItems.size, items.size); - equal(storedItems.get('foo'), 'bar'); - equal(storedItems.get('some/foo/path'), 'some/bar/path'); - equal(storedItems.get(JSON.stringify({ foo: 'bar' })), JSON.stringify({ bar: 'foo' })); - - let recoveryCalled = false; - await storage.close(() => { - recoveryCalled = true; - - return new Map(); - }); - - equal(recoveryCalled, false); - - await rimraf(storageDir, RimRafMode.MOVE); - }); - - test('basics (corrupt DB falls back to empty DB if backup is corrupt)', async () => { - const storageDir = uniqueStorageDir(); - - await mkdirp(storageDir); - - const storagePath = join(storageDir, 'storage.db'); - let storage = new SQLiteStorageDatabase(storagePath); - - const items = new Map(); - items.set('foo', 'bar'); - items.set('some/foo/path', 'some/bar/path'); - items.set(JSON.stringify({ foo: 'bar' }), JSON.stringify({ bar: 'foo' })); - - await storage.updateItems({ insert: items }); - await storage.close(); - - await writeFile(storagePath, 'This is now a broken DB'); - await writeFile(`${storagePath}.backup`, 'This is now also a broken DB'); - - storage = new SQLiteStorageDatabase(storagePath); - - const storedItems = await storage.getItems(); - equal(storedItems.size, 0); - - await testDBBasics(storagePath); - - await rimraf(storageDir, RimRafMode.MOVE); - }); - - test('basics (DB that becomes corrupt during runtime stores all state from cache on close)', async () => { - if (isWindows) { - await Promise.resolve(); // Windows will fail to write to open DB due to locking - - return; - } - - const storageDir = uniqueStorageDir(); - - await mkdirp(storageDir); - - const storagePath = join(storageDir, 'storage.db'); - let storage = new SQLiteStorageDatabase(storagePath); - - const items = new Map(); - items.set('foo', 'bar'); - items.set('some/foo/path', 'some/bar/path'); - items.set(JSON.stringify({ foo: 'bar' }), JSON.stringify({ bar: 'foo' })); - - await storage.updateItems({ insert: items }); - await storage.close(); - - const backupPath = `${storagePath}.backup`; - equal(await exists(backupPath), true); - - storage = new SQLiteStorageDatabase(storagePath); - await storage.getItems(); - - await writeFile(storagePath, 'This is now a broken DB'); - - // we still need to trigger a check to the DB so that we get to know that - // the DB is corrupt. We have no extra code on shutdown that checks for the - // health of the DB. This is an optimization to not perform too many tasks - // on shutdown. - await storage.checkIntegrity(true).then(null, error => { } /* error is expected here but we do not want to fail */); - - await unlink(backupPath); // also test that the recovery DB is backed up properly - - let recoveryCalled = false; - await storage.close(() => { - recoveryCalled = true; - - return items; - }); - - equal(recoveryCalled, true); - equal(await exists(backupPath), true); - - storage = new SQLiteStorageDatabase(storagePath); - - const storedItems = await storage.getItems(); - equal(storedItems.size, items.size); - equal(storedItems.get('foo'), 'bar'); - equal(storedItems.get('some/foo/path'), 'some/bar/path'); - equal(storedItems.get(JSON.stringify({ foo: 'bar' })), JSON.stringify({ bar: 'foo' })); - - recoveryCalled = false; - await storage.close(() => { - recoveryCalled = true; - - return new Map(); - }); - - equal(recoveryCalled, false); - - await rimraf(storageDir, RimRafMode.MOVE); - }); - - test('real world example', async function () { - this.timeout(20000); - - const storageDir = uniqueStorageDir(); - - await mkdirp(storageDir); - - let storage = new SQLiteStorageDatabase(join(storageDir, 'storage.db')); - - const items1 = new Map(); - items1.set('colorthemedata', '{"id":"vs vscode-theme-defaults-themes-light_plus-json","label":"Light+ (default light)","settingsId":"Default Light+","selector":"vs.vscode-theme-defaults-themes-light_plus-json","themeTokenColors":[{"settings":{"foreground":"#000000ff","background":"#ffffffff"}},{"scope":["meta.embedded","source.groovy.embedded"],"settings":{"foreground":"#000000ff"}},{"scope":"emphasis","settings":{"fontStyle":"italic"}},{"scope":"strong","settings":{"fontStyle":"bold"}},{"scope":"meta.diff.header","settings":{"foreground":"#000080"}},{"scope":"comment","settings":{"foreground":"#008000"}},{"scope":"constant.language","settings":{"foreground":"#0000ff"}},{"scope":["constant.numeric"],"settings":{"foreground":"#09885a"}},{"scope":"constant.regexp","settings":{"foreground":"#811f3f"}},{"name":"css tags in selectors, xml tags","scope":"entity.name.tag","settings":{"foreground":"#800000"}},{"scope":"entity.name.selector","settings":{"foreground":"#800000"}},{"scope":"entity.other.attribute-name","settings":{"foreground":"#ff0000"}},{"scope":["entity.other.attribute-name.class.css","entity.other.attribute-name.class.mixin.css","entity.other.attribute-name.id.css","entity.other.attribute-name.parent-selector.css","entity.other.attribute-name.pseudo-class.css","entity.other.attribute-name.pseudo-element.css","source.css.less entity.other.attribute-name.id","entity.other.attribute-name.attribute.scss","entity.other.attribute-name.scss"],"settings":{"foreground":"#800000"}},{"scope":"invalid","settings":{"foreground":"#cd3131"}},{"scope":"markup.underline","settings":{"fontStyle":"underline"}},{"scope":"markup.bold","settings":{"fontStyle":"bold","foreground":"#000080"}},{"scope":"markup.heading","settings":{"fontStyle":"bold","foreground":"#800000"}},{"scope":"markup.italic","settings":{"fontStyle":"italic"}},{"scope":"markup.inserted","settings":{"foreground":"#09885a"}},{"scope":"markup.deleted","settings":{"foreground":"#a31515"}},{"scope":"markup.changed","settings":{"foreground":"#0451a5"}},{"scope":["punctuation.definition.quote.begin.markdown","punctuation.definition.list.begin.markdown"],"settings":{"foreground":"#0451a5"}},{"scope":"markup.inline.raw","settings":{"foreground":"#800000"}},{"name":"brackets of XML/HTML tags","scope":"punctuation.definition.tag","settings":{"foreground":"#800000"}},{"scope":"meta.preprocessor","settings":{"foreground":"#0000ff"}},{"scope":"meta.preprocessor.string","settings":{"foreground":"#a31515"}},{"scope":"meta.preprocessor.numeric","settings":{"foreground":"#09885a"}},{"scope":"meta.structure.dictionary.key.python","settings":{"foreground":"#0451a5"}},{"scope":"storage","settings":{"foreground":"#0000ff"}},{"scope":"storage.type","settings":{"foreground":"#0000ff"}},{"scope":"storage.modifier","settings":{"foreground":"#0000ff"}},{"scope":"string","settings":{"foreground":"#a31515"}},{"scope":["string.comment.buffered.block.pug","string.quoted.pug","string.interpolated.pug","string.unquoted.plain.in.yaml","string.unquoted.plain.out.yaml","string.unquoted.block.yaml","string.quoted.single.yaml","string.quoted.double.xml","string.quoted.single.xml","string.unquoted.cdata.xml","string.quoted.double.html","string.quoted.single.html","string.unquoted.html","string.quoted.single.handlebars","string.quoted.double.handlebars"],"settings":{"foreground":"#0000ff"}},{"scope":"string.regexp","settings":{"foreground":"#811f3f"}},{"name":"String interpolation","scope":["punctuation.definition.template-expression.begin","punctuation.definition.template-expression.end","punctuation.section.embedded"],"settings":{"foreground":"#0000ff"}},{"name":"Reset JavaScript string interpolation expression","scope":["meta.template.expression"],"settings":{"foreground":"#000000"}},{"scope":["support.constant.property-value","support.constant.font-name","support.constant.media-type","support.constant.media","constant.other.color.rgb-value","constant.other.rgb-value","support.constant.color"],"settings":{"foreground":"#0451a5"}},{"scope":["support.type.vendored.property-name","support.type.property-name","variable.css","variable.scss","variable.other.less","source.coffee.embedded"],"settings":{"foreground":"#ff0000"}},{"scope":["support.type.property-name.json"],"settings":{"foreground":"#0451a5"}},{"scope":"keyword","settings":{"foreground":"#0000ff"}},{"scope":"keyword.control","settings":{"foreground":"#0000ff"}},{"scope":"keyword.operator","settings":{"foreground":"#000000"}},{"scope":["keyword.operator.new","keyword.operator.expression","keyword.operator.cast","keyword.operator.sizeof","keyword.operator.instanceof","keyword.operator.logical.python"],"settings":{"foreground":"#0000ff"}},{"scope":"keyword.other.unit","settings":{"foreground":"#09885a"}},{"scope":["punctuation.section.embedded.begin.php","punctuation.section.embedded.end.php"],"settings":{"foreground":"#800000"}},{"scope":"support.function.git-rebase","settings":{"foreground":"#0451a5"}},{"scope":"constant.sha.git-rebase","settings":{"foreground":"#09885a"}},{"name":"coloring of the Java import and package identifiers","scope":["storage.modifier.import.java","variable.language.wildcard.java","storage.modifier.package.java"],"settings":{"foreground":"#000000"}},{"name":"this.self","scope":"variable.language","settings":{"foreground":"#0000ff"}},{"name":"Function declarations","scope":["entity.name.function","support.function","support.constant.handlebars"],"settings":{"foreground":"#795E26"}},{"name":"Types declaration and references","scope":["meta.return-type","support.class","support.type","entity.name.type","entity.name.class","storage.type.numeric.go","storage.type.byte.go","storage.type.boolean.go","storage.type.string.go","storage.type.uintptr.go","storage.type.error.go","storage.type.rune.go","storage.type.cs","storage.type.generic.cs","storage.type.modifier.cs","storage.type.variable.cs","storage.type.annotation.java","storage.type.generic.java","storage.type.java","storage.type.object.array.java","storage.type.primitive.array.java","storage.type.primitive.java","storage.type.token.java","storage.type.groovy","storage.type.annotation.groovy","storage.type.parameters.groovy","storage.type.generic.groovy","storage.type.object.array.groovy","storage.type.primitive.array.groovy","storage.type.primitive.groovy"],"settings":{"foreground":"#267f99"}},{"name":"Types declaration and references, TS grammar specific","scope":["meta.type.cast.expr","meta.type.new.expr","support.constant.math","support.constant.dom","support.constant.json","entity.other.inherited-class"],"settings":{"foreground":"#267f99"}},{"name":"Control flow keywords","scope":"keyword.control","settings":{"foreground":"#AF00DB"}},{"name":"Variable and parameter name","scope":["variable","meta.definition.variable.name","support.variable","entity.name.variable"],"settings":{"foreground":"#001080"}},{"name":"Object keys, TS grammar specific","scope":["meta.object-literal.key"],"settings":{"foreground":"#001080"}},{"name":"CSS property value","scope":["support.constant.property-value","support.constant.font-name","support.constant.media-type","support.constant.media","constant.other.color.rgb-value","constant.other.rgb-value","support.constant.color"],"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":"#ff0000"}},{"scope":"token.info-token","settings":{"foreground":"#316bcd"}},{"scope":"token.warn-token","settings":{"foreground":"#cd9731"}},{"scope":"token.error-token","settings":{"foreground":"#cd3131"}},{"scope":"token.debug-token","settings":{"foreground":"#800080"}}],"extensionData":{"extensionId":"vscode.theme-defaults","extensionPublisher":"vscode","extensionName":"theme-defaults","extensionIsBuiltin":true},"colorMap":{"editor.background":"#ffffff","editor.foreground":"#000000","editor.inactiveSelectionBackground":"#e5ebf1","editorIndentGuide.background":"#d3d3d3","editorIndentGuide.activeBackground":"#939393","editor.selectionHighlightBackground":"#add6ff4d","editorSuggestWidget.background":"#f3f3f3","activityBarBadge.background":"#007acc","sideBarTitle.foreground":"#6f6f6f","list.hoverBackground":"#e8e8e8","input.placeholderForeground":"#767676","settings.textInputBorder":"#cecece","settings.numberInputBorder":"#cecece"}}'); - items1.set('commandpalette.mru.cache', '{"usesLRU":true,"entries":[{"key":"revealFileInOS","value":3},{"key":"extension.openInGitHub","value":4},{"key":"workbench.extensions.action.openExtensionsFolder","value":11},{"key":"workbench.action.showRuntimeExtensions","value":14},{"key":"workbench.action.toggleTabsVisibility","value":15},{"key":"extension.liveServerPreview.open","value":16},{"key":"workbench.action.openIssueReporter","value":18},{"key":"workbench.action.openProcessExplorer","value":19},{"key":"workbench.action.toggleSharedProcess","value":20},{"key":"workbench.action.configureLocale","value":21},{"key":"workbench.action.appPerf","value":22},{"key":"workbench.action.reportPerformanceIssueUsingReporter","value":23},{"key":"workbench.action.openGlobalKeybindings","value":25},{"key":"workbench.action.output.toggleOutput","value":27},{"key":"extension.sayHello","value":29}]}'); - items1.set('cpp.1.lastsessiondate', 'Fri Oct 05 2018'); - items1.set('debug.actionswidgetposition', '0.6880952380952381'); - - const items2 = new Map(); - items2.set('workbench.editors.files.textfileeditor', '{"textEditorViewState":[["file:///Users/dummy/Documents/ticino-playground/play.htm",{"0":{"cursorState":[{"inSelectionMode":false,"selectionStart":{"lineNumber":6,"column":16},"position":{"lineNumber":6,"column":16}}],"viewState":{"scrollLeft":0,"firstPosition":{"lineNumber":1,"column":1},"firstPositionDeltaTop":0},"contributionsState":{"editor.contrib.folding":{},"editor.contrib.wordHighlighter":false}}}],["file:///Users/dummy/Documents/ticino-playground/nakefile.js",{"0":{"cursorState":[{"inSelectionMode":false,"selectionStart":{"lineNumber":7,"column":81},"position":{"lineNumber":7,"column":81}}],"viewState":{"scrollLeft":0,"firstPosition":{"lineNumber":1,"column":1},"firstPositionDeltaTop":20},"contributionsState":{"editor.contrib.folding":{},"editor.contrib.wordHighlighter":false}}}],["file:///Users/dummy/Desktop/vscode2/.gitattributes",{"0":{"cursorState":[{"inSelectionMode":false,"selectionStart":{"lineNumber":9,"column":12},"position":{"lineNumber":9,"column":12}}],"viewState":{"scrollLeft":0,"firstPosition":{"lineNumber":1,"column":1},"firstPositionDeltaTop":20},"contributionsState":{"editor.contrib.folding":{},"editor.contrib.wordHighlighter":false}}}],["file:///Users/dummy/Desktop/vscode2/src/vs/workbench/contrib/search/browser/openAnythingHandler.ts",{"0":{"cursorState":[{"inSelectionMode":false,"selectionStart":{"lineNumber":1,"column":1},"position":{"lineNumber":1,"column":1}}],"viewState":{"scrollLeft":0,"firstPosition":{"lineNumber":1,"column":1},"firstPositionDeltaTop":0},"contributionsState":{"editor.contrib.folding":{},"editor.contrib.wordHighlighter":false}}}]]}'); - - const items3 = new Map(); - items3.set('nps/iscandidate', 'false'); - items3.set('telemetry.instanceid', 'd52bfcd4-4be6-476b-a38f-d44c717c41d6'); - items3.set('workbench.activity.pinnedviewlets', '[{"id":"workbench.view.explorer","pinned":true,"order":0,"visible":true},{"id":"workbench.view.search","pinned":true,"order":1,"visible":true},{"id":"workbench.view.scm","pinned":true,"order":2,"visible":true},{"id":"workbench.view.debug","pinned":true,"order":3,"visible":true},{"id":"workbench.view.extensions","pinned":true,"order":4,"visible":true},{"id":"workbench.view.extension.gitlens","pinned":true,"order":7,"visible":true},{"id":"workbench.view.extension.test","pinned":false,"visible":false}]'); - items3.set('workbench.panel.height', '419'); - items3.set('very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.very.long.key.', 'is long'); - - let storedItems = await storage.getItems(); - equal(storedItems.size, 0); - - await Promise.all([ - await storage.updateItems({ insert: items1 }), - await storage.updateItems({ insert: items2 }), - await storage.updateItems({ insert: items3 }) - ]); - - equal(await storage.checkIntegrity(true), 'ok'); - equal(await storage.checkIntegrity(false), 'ok'); - - storedItems = await storage.getItems(); - equal(storedItems.size, items1.size + items2.size + items3.size); - - const items1Keys: string[] = []; - items1.forEach((value, key) => { - items1Keys.push(key); - equal(storedItems.get(key), value); - }); - - const items2Keys: string[] = []; - items2.forEach((value, key) => { - items2Keys.push(key); - equal(storedItems.get(key), value); - }); - - const items3Keys: string[] = []; - items3.forEach((value, key) => { - items3Keys.push(key); - equal(storedItems.get(key), value); - }); - - await Promise.all([ - await storage.updateItems({ delete: toSet(items1Keys) }), - await storage.updateItems({ delete: toSet(items2Keys) }), - await storage.updateItems({ delete: toSet(items3Keys) }) - ]); - - storedItems = await storage.getItems(); - equal(storedItems.size, 0); - - await Promise.all([ - await storage.updateItems({ insert: items1 }), - await storage.getItems(), - await storage.updateItems({ insert: items2 }), - await storage.getItems(), - await storage.updateItems({ insert: items3 }), - await storage.getItems(), - ]); - - storedItems = await storage.getItems(); - equal(storedItems.size, items1.size + items2.size + items3.size); - - await storage.close(); - - storage = new SQLiteStorageDatabase(join(storageDir, 'storage.db')); - - storedItems = await storage.getItems(); - equal(storedItems.size, items1.size + items2.size + items3.size); - - await storage.close(); - - await rimraf(storageDir, RimRafMode.MOVE); - }); - - test('very large item value', async function () { - this.timeout(20000); - - const storageDir = uniqueStorageDir(); - - await mkdirp(storageDir); - - let storage = new SQLiteStorageDatabase(join(storageDir, 'storage.db')); - - const items = new Map(); - items.set('colorthemedata', '{"id":"vs vscode-theme-defaults-themes-light_plus-json","label":"Light+ (default light)","settingsId":"Default Light+","selector":"vs.vscode-theme-defaults-themes-light_plus-json","themeTokenColors":[{"settings":{"foreground":"#000000ff","background":"#ffffffff"}},{"scope":["meta.embedded","source.groovy.embedded"],"settings":{"foreground":"#000000ff"}},{"scope":"emphasis","settings":{"fontStyle":"italic"}},{"scope":"strong","settings":{"fontStyle":"bold"}},{"scope":"meta.diff.header","settings":{"foreground":"#000080"}},{"scope":"comment","settings":{"foreground":"#008000"}},{"scope":"constant.language","settings":{"foreground":"#0000ff"}},{"scope":["constant.numeric"],"settings":{"foreground":"#09885a"}},{"scope":"constant.regexp","settings":{"foreground":"#811f3f"}},{"name":"css tags in selectors, xml tags","scope":"entity.name.tag","settings":{"foreground":"#800000"}},{"scope":"entity.name.selector","settings":{"foreground":"#800000"}},{"scope":"entity.other.attribute-name","settings":{"foreground":"#ff0000"}},{"scope":["entity.other.attribute-name.class.css","entity.other.attribute-name.class.mixin.css","entity.other.attribute-name.id.css","entity.other.attribute-name.parent-selector.css","entity.other.attribute-name.pseudo-class.css","entity.other.attribute-name.pseudo-element.css","source.css.less entity.other.attribute-name.id","entity.other.attribute-name.attribute.scss","entity.other.attribute-name.scss"],"settings":{"foreground":"#800000"}},{"scope":"invalid","settings":{"foreground":"#cd3131"}},{"scope":"markup.underline","settings":{"fontStyle":"underline"}},{"scope":"markup.bold","settings":{"fontStyle":"bold","foreground":"#000080"}},{"scope":"markup.heading","settings":{"fontStyle":"bold","foreground":"#800000"}},{"scope":"markup.italic","settings":{"fontStyle":"italic"}},{"scope":"markup.inserted","settings":{"foreground":"#09885a"}},{"scope":"markup.deleted","settings":{"foreground":"#a31515"}},{"scope":"markup.changed","settings":{"foreground":"#0451a5"}},{"scope":["punctuation.definition.quote.begin.markdown","punctuation.definition.list.begin.markdown"],"settings":{"foreground":"#0451a5"}},{"scope":"markup.inline.raw","settings":{"foreground":"#800000"}},{"name":"brackets of XML/HTML tags","scope":"punctuation.definition.tag","settings":{"foreground":"#800000"}},{"scope":"meta.preprocessor","settings":{"foreground":"#0000ff"}},{"scope":"meta.preprocessor.string","settings":{"foreground":"#a31515"}},{"scope":"meta.preprocessor.numeric","settings":{"foreground":"#09885a"}},{"scope":"meta.structure.dictionary.key.python","settings":{"foreground":"#0451a5"}},{"scope":"storage","settings":{"foreground":"#0000ff"}},{"scope":"storage.type","settings":{"foreground":"#0000ff"}},{"scope":"storage.modifier","settings":{"foreground":"#0000ff"}},{"scope":"string","settings":{"foreground":"#a31515"}},{"scope":["string.comment.buffered.block.pug","string.quoted.pug","string.interpolated.pug","string.unquoted.plain.in.yaml","string.unquoted.plain.out.yaml","string.unquoted.block.yaml","string.quoted.single.yaml","string.quoted.double.xml","string.quoted.single.xml","string.unquoted.cdata.xml","string.quoted.double.html","string.quoted.single.html","string.unquoted.html","string.quoted.single.handlebars","string.quoted.double.handlebars"],"settings":{"foreground":"#0000ff"}},{"scope":"string.regexp","settings":{"foreground":"#811f3f"}},{"name":"String interpolation","scope":["punctuation.definition.template-expression.begin","punctuation.definition.template-expression.end","punctuation.section.embedded"],"settings":{"foreground":"#0000ff"}},{"name":"Reset JavaScript string interpolation expression","scope":["meta.template.expression"],"settings":{"foreground":"#000000"}},{"scope":["support.constant.property-value","support.constant.font-name","support.constant.media-type","support.constant.media","constant.other.color.rgb-value","constant.other.rgb-value","support.constant.color"],"settings":{"foreground":"#0451a5"}},{"scope":["support.type.vendored.property-name","support.type.property-name","variable.css","variable.scss","variable.other.less","source.coffee.embedded"],"settings":{"foreground":"#ff0000"}},{"scope":["support.type.property-name.json"],"settings":{"foreground":"#0451a5"}},{"scope":"keyword","settings":{"foreground":"#0000ff"}},{"scope":"keyword.control","settings":{"foreground":"#0000ff"}},{"scope":"keyword.operator","settings":{"foreground":"#000000"}},{"scope":["keyword.operator.new","keyword.operator.expression","keyword.operator.cast","keyword.operator.sizeof","keyword.operator.instanceof","keyword.operator.logical.python"],"settings":{"foreground":"#0000ff"}},{"scope":"keyword.other.unit","settings":{"foreground":"#09885a"}},{"scope":["punctuation.section.embedded.begin.php","punctuation.section.embedded.end.php"],"settings":{"foreground":"#800000"}},{"scope":"support.function.git-rebase","settings":{"foreground":"#0451a5"}},{"scope":"constant.sha.git-rebase","settings":{"foreground":"#09885a"}},{"name":"coloring of the Java import and package identifiers","scope":["storage.modifier.import.java","variable.language.wildcard.java","storage.modifier.package.java"],"settings":{"foreground":"#000000"}},{"name":"this.self","scope":"variable.language","settings":{"foreground":"#0000ff"}},{"name":"Function declarations","scope":["entity.name.function","support.function","support.constant.handlebars"],"settings":{"foreground":"#795E26"}},{"name":"Types declaration and references","scope":["meta.return-type","support.class","support.type","entity.name.type","entity.name.class","storage.type.numeric.go","storage.type.byte.go","storage.type.boolean.go","storage.type.string.go","storage.type.uintptr.go","storage.type.error.go","storage.type.rune.go","storage.type.cs","storage.type.generic.cs","storage.type.modifier.cs","storage.type.variable.cs","storage.type.annotation.java","storage.type.generic.java","storage.type.java","storage.type.object.array.java","storage.type.primitive.array.java","storage.type.primitive.java","storage.type.token.java","storage.type.groovy","storage.type.annotation.groovy","storage.type.parameters.groovy","storage.type.generic.groovy","storage.type.object.array.groovy","storage.type.primitive.array.groovy","storage.type.primitive.groovy"],"settings":{"foreground":"#267f99"}},{"name":"Types declaration and references, TS grammar specific","scope":["meta.type.cast.expr","meta.type.new.expr","support.constant.math","support.constant.dom","support.constant.json","entity.other.inherited-class"],"settings":{"foreground":"#267f99"}},{"name":"Control flow keywords","scope":"keyword.control","settings":{"foreground":"#AF00DB"}},{"name":"Variable and parameter name","scope":["variable","meta.definition.variable.name","support.variable","entity.name.variable"],"settings":{"foreground":"#001080"}},{"name":"Object keys, TS grammar specific","scope":["meta.object-literal.key"],"settings":{"foreground":"#001080"}},{"name":"CSS property value","scope":["support.constant.property-value","support.constant.font-name","support.constant.media-type","support.constant.media","constant.other.color.rgb-value","constant.other.rgb-value","support.constant.color"],"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":"#ff0000"}},{"scope":"token.info-token","settings":{"foreground":"#316bcd"}},{"scope":"token.warn-token","settings":{"foreground":"#cd9731"}},{"scope":"token.error-token","settings":{"foreground":"#cd3131"}},{"scope":"token.debug-token","settings":{"foreground":"#800080"}}],"extensionData":{"extensionId":"vscode.theme-defaults","extensionPublisher":"vscode","extensionName":"theme-defaults","extensionIsBuiltin":true},"colorMap":{"editor.background":"#ffffff","editor.foreground":"#000000","editor.inactiveSelectionBackground":"#e5ebf1","editorIndentGuide.background":"#d3d3d3","editorIndentGuide.activeBackground":"#939393","editor.selectionHighlightBackground":"#add6ff4d","editorSuggestWidget.background":"#f3f3f3","activityBarBadge.background":"#007acc","sideBarTitle.foreground":"#6f6f6f","list.hoverBackground":"#e8e8e8","input.placeholderForeground":"#767676","settings.textInputBorder":"#cecece","settings.numberInputBorder":"#cecece"}}'); - items.set('commandpalette.mru.cache', '{"usesLRU":true,"entries":[{"key":"revealFileInOS","value":3},{"key":"extension.openInGitHub","value":4},{"key":"workbench.extensions.action.openExtensionsFolder","value":11},{"key":"workbench.action.showRuntimeExtensions","value":14},{"key":"workbench.action.toggleTabsVisibility","value":15},{"key":"extension.liveServerPreview.open","value":16},{"key":"workbench.action.openIssueReporter","value":18},{"key":"workbench.action.openProcessExplorer","value":19},{"key":"workbench.action.toggleSharedProcess","value":20},{"key":"workbench.action.configureLocale","value":21},{"key":"workbench.action.appPerf","value":22},{"key":"workbench.action.reportPerformanceIssueUsingReporter","value":23},{"key":"workbench.action.openGlobalKeybindings","value":25},{"key":"workbench.action.output.toggleOutput","value":27},{"key":"extension.sayHello","value":29}]}'); - - let uuid = generateUuid(); - let value: string[] = []; - for (let i = 0; i < 100000; i++) { - value.push(uuid); - } - items.set('super.large.string', value.join()); // 3.6MB - - await storage.updateItems({ insert: items }); - - let storedItems = await storage.getItems(); - equal(items.get('colorthemedata'), storedItems.get('colorthemedata')); - equal(items.get('commandpalette.mru.cache'), storedItems.get('commandpalette.mru.cache')); - equal(items.get('super.large.string'), storedItems.get('super.large.string')); - - uuid = generateUuid(); - value = []; - for (let i = 0; i < 100000; i++) { - value.push(uuid); - } - items.set('super.large.string', value.join()); // 3.6MB - - await storage.updateItems({ insert: items }); - - storedItems = await storage.getItems(); - equal(items.get('colorthemedata'), storedItems.get('colorthemedata')); - equal(items.get('commandpalette.mru.cache'), storedItems.get('commandpalette.mru.cache')); - equal(items.get('super.large.string'), storedItems.get('super.large.string')); - - const toDelete = new Set(); - toDelete.add('super.large.string'); - await storage.updateItems({ delete: toDelete }); - - storedItems = await storage.getItems(); - equal(items.get('colorthemedata'), storedItems.get('colorthemedata')); - equal(items.get('commandpalette.mru.cache'), storedItems.get('commandpalette.mru.cache')); - ok(!storedItems.get('super.large.string')); - - await storage.close(); - - await rimraf(storageDir, RimRafMode.MOVE); - }); - - test('multiple concurrent writes execute in sequence', async () => { - const storageDir = uniqueStorageDir(); - await mkdirp(storageDir); - - class TestStorage extends Storage { - getStorage(): IStorageDatabase { - return this.database; - } - } - - const storage = new TestStorage(new SQLiteStorageDatabase(join(storageDir, 'storage.db'))); - - await storage.init(); - - storage.set('foo', 'bar'); - storage.set('some/foo/path', 'some/bar/path'); - - await timeout(10); - - storage.set('foo1', 'bar'); - storage.set('some/foo1/path', 'some/bar/path'); - - await timeout(10); - - storage.set('foo2', 'bar'); - storage.set('some/foo2/path', 'some/bar/path'); - - await timeout(10); - - storage.delete('foo1'); - storage.delete('some/foo1/path'); - - await timeout(10); - - storage.delete('foo4'); - storage.delete('some/foo4/path'); - - await timeout(70); - - storage.set('foo3', 'bar'); - await storage.set('some/foo3/path', 'some/bar/path'); - - const items = await storage.getStorage().getItems(); - equal(items.get('foo'), 'bar'); - equal(items.get('some/foo/path'), 'some/bar/path'); - equal(items.has('foo1'), false); - equal(items.has('some/foo1/path'), false); - equal(items.get('foo2'), 'bar'); - equal(items.get('some/foo2/path'), 'some/bar/path'); - equal(items.get('foo3'), 'bar'); - equal(items.get('some/foo3/path'), 'some/bar/path'); - - await storage.close(); - - await rimraf(storageDir, RimRafMode.MOVE); - }); - - test('lots of INSERT & DELETE (below inline max)', async () => { - const storageDir = uniqueStorageDir(); - - await mkdirp(storageDir); - - const storage = new SQLiteStorageDatabase(join(storageDir, 'storage.db')); - - const items = new Map(); - const keys: Set = new Set(); - for (let i = 0; i < 200; i++) { - const uuid = generateUuid(); - const key = `key: ${uuid}`; - - items.set(key, `value: ${uuid}`); - keys.add(key); - } - - await storage.updateItems({ insert: items }); - - let storedItems = await storage.getItems(); - equal(storedItems.size, items.size); - - await storage.updateItems({ delete: keys }); - - storedItems = await storage.getItems(); - equal(storedItems.size, 0); - - await storage.close(); - - await rimraf(storageDir, RimRafMode.MOVE); - }); - - test('lots of INSERT & DELETE (above inline max)', async () => { - const storageDir = uniqueStorageDir(); - - await mkdirp(storageDir); - - const storage = new SQLiteStorageDatabase(join(storageDir, 'storage.db')); - - const items = new Map(); - const keys: Set = new Set(); - for (let i = 0; i < 400; i++) { - const uuid = generateUuid(); - const key = `key: ${uuid}`; - - items.set(key, `value: ${uuid}`); - keys.add(key); - } - - await storage.updateItems({ insert: items }); - - let storedItems = await storage.getItems(); - equal(storedItems.size, items.size); - - await storage.updateItems({ delete: keys }); - - storedItems = await storage.getItems(); - equal(storedItems.size, 0); - - await storage.close(); - - await rimraf(storageDir, RimRafMode.MOVE); - }); -}); diff --git a/src/vs/base/test/node/stream/fixtures/file.css b/src/vs/base/test/node/stream/fixtures/file.css deleted file mode 100644 index f7b51e752..000000000 --- a/src/vs/base/test/node/stream/fixtures/file.css +++ /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. - *--------------------------------------------------------------------------------------------*/ - -/*---------------------------------------------------------- -The base color for this template is #5c87b2. If you'd like -to use a different color start by replacing all instances of -#5c87b2 with your new color. -----------------------------------------------------------*/ -body -{ - background-color: #5c87b2; - font-size: .75em; - font-family: Segoe UI, Verdana, Helvetica, Sans-Serif; - margin: 8px; - padding: 0; - color: #696969; -} - -h1, h2, h3, h4, h5, h6 -{ - color: #000; - font-size: 40px; - margin: 0px; -} - -textarea -{ - font-family: Consolas -} - -#results -{ - margin-top: 2em; - margin-left: 2em; - color: black; - font-size: medium; -} - diff --git a/src/vs/base/test/node/stream/stream.test.ts b/src/vs/base/test/node/stream/stream.test.ts deleted file mode 100644 index f813b0a48..000000000 --- a/src/vs/base/test/node/stream/stream.test.ts +++ /dev/null @@ -1,28 +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 * as stream from 'vs/base/node/stream'; -import { getPathFromAmdModule } from 'vs/base/common/amd'; - -suite('Stream', () => { - test('readToMatchingString - ANSI', function () { - const file = getPathFromAmdModule(require, './fixtures/file.css'); - - return stream.readToMatchingString(file, '\n', 10, 100).then((result: string) => { - // \r may be present on Windows - assert.equal(result.replace('\r', ''), '/*---------------------------------------------------------------------------------------------'); - }); - }); - - test('readToMatchingString - empty', function () { - const file = getPathFromAmdModule(require, './fixtures/empty.txt'); - - return stream.readToMatchingString(file, '\n', 10, 100).then((result: string) => { - assert.equal(result, null); - }); - }); -}); diff --git a/src/vs/base/test/node/utils.ts b/src/vs/base/test/node/utils.ts index 58e77924f..5ba6f6e24 100644 --- a/src/vs/base/test/node/utils.ts +++ b/src/vs/base/test/node/utils.ts @@ -16,8 +16,8 @@ export interface ITestFileResult { export function testFile(folder: string, file: string): Promise { const id = generateUuid(); const parentDir = join(tmpdir(), 'vsctests', id); - const newDir = join(parentDir, 'config', id); - const testFile = join(newDir, 'config.json'); + const newDir = join(parentDir, folder, id); + const testFile = join(newDir, file); return mkdirp(newDir, 493).then(() => { return { diff --git a/src/vs/base/worker/defaultWorkerFactory.ts b/src/vs/base/worker/defaultWorkerFactory.ts index eccaa81f1..c2a7ddc54 100644 --- a/src/vs/base/worker/defaultWorkerFactory.ts +++ b/src/vs/base/worker/defaultWorkerFactory.ts @@ -63,7 +63,7 @@ class WebWorker implements IWorker { } else { this.worker = Promise.resolve(workerOrPromise); } - this.postMessage(moduleId); + this.postMessage(moduleId, []); this.worker.then((w) => { w.onmessage = function (ev: any) { onMessageCallback(ev.data); @@ -79,9 +79,9 @@ class WebWorker implements IWorker { return this.id; } - public postMessage(msg: string): void { + public postMessage(message: any, transfer: Transferable[]): void { if (this.worker) { - this.worker.then(w => w.postMessage(msg)); + this.worker.then(w => w.postMessage(message, transfer)); } } diff --git a/src/vs/code/browser/workbench/workbench.html b/src/vs/code/browser/workbench/workbench.html new file mode 100644 index 000000000..5b06636ed --- /dev/null +++ b/src/vs/code/browser/workbench/workbench.html @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/vs/code/browser/workbench/workbench.js b/src/vs/code/browser/workbench/workbench.js new file mode 100644 index 000000000..65fae7c82 --- /dev/null +++ b/src/vs/code/browser/workbench/workbench.js @@ -0,0 +1,27 @@ +/*--------------------------------------------------------------------------------------------- + * 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 () { + + require.config({ + baseUrl: `${window.location.origin}/out`, + paths: { + 'vscode-textmate': `${window.location.origin}/node_modules/vscode-textmate/release/main`, + 'onigasm-umd': `${window.location.origin}/node_modules/onigasm-umd/release/main`, + 'xterm': `${window.location.origin}/node_modules/xterm/lib/xterm.js`, + 'xterm-addon-search': `${window.location.origin}/node_modules/xterm-addon-search/lib/xterm-addon-search.js`, + 'xterm-addon-web-links': `${window.location.origin}/node_modules/xterm-addon-web-links/lib/xterm-addon-web-links.js`, + 'semver-umd': `${window.location.origin}/node_modules/semver-umd/lib/semver-umd.js`, + } + }); + + require(['vs/workbench/workbench.web.api'], function (api) { + const options = JSON.parse(document.getElementById('vscode-workbench-web-configuration').getAttribute('data-settings')); + + api.create(document.body, options); + }); +})(); \ No newline at end of file diff --git a/src/vs/code/code.main.ts b/src/vs/code/code.main.ts deleted file mode 100644 index 074dca196..000000000 --- a/src/vs/code/code.main.ts +++ /dev/null @@ -1,6 +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 'vs/platform/update/node/update.config.contribution'; \ No newline at end of file diff --git a/src/vs/code/electron-browser/issue/issueReporterMain.ts b/src/vs/code/electron-browser/issue/issueReporterMain.ts index 90767e1a8..2302d162f 100644 --- a/src/vs/code/electron-browser/issue/issueReporterMain.ts +++ b/src/vs/code/electron-browser/issue/issueReporterMain.ts @@ -33,16 +33,16 @@ import { EnvironmentService } from 'vs/platform/environment/node/environmentServ import { IssueReporterModel, IssueReporterData as IssueReporterModelData } from 'vs/code/electron-browser/issue/issueReporterModel'; import { IssueReporterData, IssueReporterStyles, IssueType, ISettingsSearchIssueReporterData, IssueReporterFeatures, IssueReporterExtensionData } from 'vs/platform/issue/common/issue'; import BaseHtml from 'vs/code/electron-browser/issue/issueReporterPage'; -import { createSpdLogService } from 'vs/platform/log/node/spdlogService'; -import { LogLevelSetterChannelClient, FollowerLogService } from 'vs/platform/log/node/logIpc'; +import { LogLevelSetterChannelClient, FollowerLogService } from 'vs/platform/log/common/logIpc'; import { ILogService, getLogLevel } from 'vs/platform/log/common/log'; import { OcticonLabel } from 'vs/base/browser/ui/octiconLabel/octiconLabel'; import { normalizeGitHubUrl } from 'vs/code/electron-browser/issue/issueReporterUtil'; import { Button } from 'vs/base/browser/ui/button/button'; import { withUndefinedAsNull } from 'vs/base/common/types'; import { SystemInfo, isRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnosticsService'; +import { SpdLogService } from 'vs/platform/log/node/spdlogService'; -const MAX_URL_LENGTH = platform.isWindows ? 2081 : 5400; +const MAX_URL_LENGTH = 2045; interface SearchResult { html_url: string; @@ -300,7 +300,7 @@ export class IssueReporter extends Disposable { serviceCollection.set(IWindowsService, new WindowsService(mainProcessService)); this.environmentService = new EnvironmentService(configuration, configuration.execPath); - const logService = createSpdLogService(`issuereporter${configuration.windowId}`, getLogLevel(this.environmentService), this.environmentService.logsPath); + const logService = new SpdLogService(`issuereporter${configuration.windowId}`, this.environmentService.logsPath, getLogLevel(this.environmentService)); const logLevelClient = new LogLevelSetterChannelClient(mainProcessService.getChannel('loglevel')); this.logService = new FollowerLogService(logLevelClient, logService); @@ -312,7 +312,7 @@ export class IssueReporter extends Disposable { const channel = getDelayedChannel(sharedProcess.then(c => c.getChannel('telemetryAppender'))); const appender = combinedAppender(new TelemetryAppenderClient(channel), new LogAppender(logService)); const commonProperties = resolveCommonProperties(product.commit || 'Commit unknown', pkg.version, configuration.machineId, this.environmentService.installSourcePath); - const piiPaths = [this.environmentService.appRoot, this.environmentService.extensionsPath]; + const piiPaths = this.environmentService.extensionsPath ? [this.environmentService.appRoot, this.environmentService.extensionsPath] : [this.environmentService.appRoot]; const config: ITelemetryServiceConfig = { appender, commonProperties, piiPaths }; const telemetryService = instantiationService.createInstance(TelemetryService, config); @@ -336,7 +336,7 @@ export class IssueReporter extends Disposable { this.render(); }); - ['includeSystemInfo', 'includeProcessInfo', 'includeWorkspaceInfo', 'includeExtensions', 'includeSearchedExtensions', 'includeSettingsSearchDetails'].forEach(elementId => { + (['includeSystemInfo', 'includeProcessInfo', 'includeWorkspaceInfo', 'includeExtensions', 'includeSearchedExtensions', 'includeSettingsSearchDetails'] as const).forEach(elementId => { this.addEventListener(elementId, 'click', (event: Event) => { event.stopPropagation(); this.issueReporterModel.update({ [elementId]: !this.issueReporterModel.getData()[elementId] }); @@ -346,7 +346,7 @@ export class IssueReporter extends Disposable { const showInfoElements = document.getElementsByClassName('showInfo'); for (let i = 0; i < showInfoElements.length; i++) { const showInfo = showInfoElements.item(i); - showInfo!.addEventListener('click', (e) => { + showInfo!.addEventListener('click', (e: MouseEvent) => { e.preventDefault(); const label = (e.target); if (label) { @@ -440,11 +440,11 @@ export class IssueReporter extends Disposable { } }); - document.onkeydown = (e: KeyboardEvent) => { + document.onkeydown = async (e: KeyboardEvent) => { const cmdOrCtrlKey = platform.isMacintosh ? e.metaKey : e.ctrlKey; // Cmd/Ctrl+Enter previews issue and closes window if (cmdOrCtrlKey && e.keyCode === 13) { - if (this.createIssue()) { + if (await this.createIssue()) { ipcRenderer.send('vscode:closeIssueReporter'); } } @@ -676,12 +676,14 @@ export class IssueReporter extends Disposable { private logSearchError(error: Error) { this.logService.warn('issueReporter#search ', error.message); - /* __GDPR__ - "issueReporterSearchError" : { - "message" : { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" } - } - */ - this.telemetryService.publicLog('issueReporterSearchError', { message: error.message }); + type IssueReporterSearchErrorClassification = { + message: { classification: 'CallstackOrException', purpose: 'PerformanceAndHealth' } + }; + + type IssueReporterSearchError = { + message: string; + }; + this.telemetryService.publicLog2('issueReporterSearchError', { message: error.message }); } private setUpTypes(): void { @@ -843,7 +845,7 @@ export class IssueReporter extends Disposable { return isValid; } - private createIssue(): boolean { + private async createIssue(): Promise { if (!this.validateInputs()) { // If inputs are invalid, set focus to the first one and add listeners on them // to detect further changes @@ -873,13 +875,15 @@ export class IssueReporter extends Disposable { return false; } - /* __GDPR__ - "issueReporterSubmit" : { - "issueType" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "numSimilarIssuesDisplayed" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } - } - */ - this.telemetryService.publicLog('issueReporterSubmit', { issueType: this.issueReporterModel.getData().issueType, numSimilarIssuesDisplayed: this.numberOfSearchResultsDisplayed }); + type IssueReporterSubmitClassification = { + issueType: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + numSimilarIssuesDisplayed: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + }; + type IssueReporterSubmitEvent = { + issueType: any; + numSimilarIssuesDisplayed: number; + }; + this.telemetryService.publicLog2('issueReporterSubmit', { issueType: this.issueReporterModel.getData().issueType, numSimilarIssuesDisplayed: this.numberOfSearchResultsDisplayed }); this.hasBeenSubmitted = true; const baseUrl = this.getIssueUrlWithTitle((this.getElementById('issue-title')).value); @@ -887,14 +891,32 @@ export class IssueReporter extends Disposable { let url = baseUrl + `&body=${encodeURIComponent(issueBody)}`; if (url.length > MAX_URL_LENGTH) { - clipboard.writeText(issueBody); - url = baseUrl + `&body=${encodeURIComponent(localize('pasteData', "We have written the needed data into your clipboard because it was too large to send. Please paste."))}`; + try { + url = await this.writeToClipboard(baseUrl, issueBody); + } catch (_) { + return false; + } } ipcRenderer.send('vscode:openExternal', url); return true; } + private async writeToClipboard(baseUrl: string, issueBody: string): Promise { + return new Promise((resolve, reject) => { + ipcRenderer.once('vscode:issueReporterClipboardResponse', (_: unknown, shouldWrite: boolean) => { + if (shouldWrite) { + clipboard.writeText(issueBody); + resolve(baseUrl + `&body=${encodeURIComponent(localize('pasteData', "We have written the needed data into your clipboard because it was too large to send. Please paste."))}`); + } else { + reject(); + } + }); + + ipcRenderer.send('vscode:issueReporterClipboard'); + }); + } + private getExtensionGitHubUrl(): string { let repositoryUrl = ''; const bugsUrl = this.getExtensionBugsUrl(); @@ -1088,11 +1110,7 @@ export class IssueReporter extends Disposable { // Exclude right click if (event.which < 3) { shell.openExternal((event.target).href); - - /* __GDPR__ - "issueReporterViewSimilarIssue" : { } - */ - this.telemetryService.publicLog('issueReporterViewSimilarIssue'); + this.telemetryService.publicLog2('issueReporterViewSimilarIssue'); } } @@ -1103,12 +1121,13 @@ export class IssueReporter extends Disposable { } else { const error = new Error(`${elementId} not found.`); this.logService.error(error); - /* __GDPR__ - "issueReporterGetElementError" : { - "message" : { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" } - } - */ - this.telemetryService.publicLog('issueReporterGetElementError', { message: error.message }); + type IssueReporterGetElementErrorClassification = { + message: { classification: 'CallstackOrException', purpose: 'PerformanceAndHealth' }; + }; + type IssueReporterGetElementErrorEvent = { + message: string; + }; + this.telemetryService.publicLog2('issueReporterGetElementError', { message: error.message }); return undefined; } diff --git a/src/vs/code/electron-browser/processExplorer/processExplorerMain.ts b/src/vs/code/electron-browser/processExplorer/processExplorerMain.ts index 58cdb40a4..321a5611e 100644 --- a/src/vs/code/electron-browser/processExplorer/processExplorerMain.ts +++ b/src/vs/code/electron-browser/processExplorer/processExplorerMain.ts @@ -16,7 +16,7 @@ import { IContextMenuItem } from 'vs/base/parts/contextmenu/common/contextmenu'; import { popup } from 'vs/base/parts/contextmenu/electron-browser/contextmenu'; import { ProcessItem } from 'vs/base/common/processes'; import { addDisposableListener } from 'vs/base/browser/dom'; -import { IDisposable } from 'vs/base/common/lifecycle'; +import { DisposableStore } from 'vs/base/common/lifecycle'; import { isRemoteDiagnosticError, IRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnosticsService'; @@ -24,7 +24,7 @@ let mapPidToWindowTitle = new Map(); const DEBUG_FLAGS_PATTERN = /\s--(inspect|debug)(-brk|port)?=(\d+)?/; const DEBUG_PORT_PATTERN = /\s--(inspect|debug)-port=(\d+)/; -const listeners: IDisposable[] = []; +const listeners = new DisposableStore(); const collapsedStateCache: Map = new Map(); let lastRequestTime: number; @@ -171,7 +171,7 @@ function renderProcessGroupHeader(sectionName: string, body: HTMLElement, contai updateSectionCollapsedState(!collapsedStateCache.get(sectionName), body, twistie, sectionName); data.prepend(twistie); - listeners.push(addDisposableListener(data, 'click', (e) => { + listeners.add(addDisposableListener(data, 'click', (e) => { const isHidden = body.classList.contains('hidden'); updateSectionCollapsedState(isHidden, body, twistie, sectionName); })); @@ -222,7 +222,7 @@ function renderTableSection(sectionName: string, processList: FormattedProcessIt row.append(cpu, memory, pid, name); - listeners.push(addDisposableListener(row, 'contextmenu', (e) => { + listeners.add(addDisposableListener(row, 'contextmenu', (e) => { showContextMenu(e, p, sectionIsLocal); })); @@ -239,7 +239,7 @@ function updateProcessInfo(processLists: [{ name: string, rootProcess: ProcessIt } container.innerHTML = ''; - listeners.forEach(l => l.dispose()); + listeners.clear(); const tableHead = document.createElement('thead'); tableHead.innerHTML = ` diff --git a/src/vs/code/electron-browser/sharedProcess/contrib/languagePackCachedDataCleaner.ts b/src/vs/code/electron-browser/sharedProcess/contrib/languagePackCachedDataCleaner.ts index e7f1eec77..0f791bb8c 100644 --- a/src/vs/code/electron-browser/sharedProcess/contrib/languagePackCachedDataCleaner.ts +++ b/src/vs/code/electron-browser/sharedProcess/contrib/languagePackCachedDataCleaner.ts @@ -8,7 +8,7 @@ import * as pfs from 'vs/base/node/pfs'; import { IStringDictionary } from 'vs/base/common/collections'; import product from 'vs/platform/product/node/product'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; import { onUnexpectedError } from 'vs/base/common/errors'; import { ILogService } from 'vs/platform/log/common/log'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -30,14 +30,13 @@ interface LanguagePackFile { [locale: string]: LanguagePackEntry; } -export class LanguagePackCachedDataCleaner { - - private _disposables: IDisposable[] = []; +export class LanguagePackCachedDataCleaner extends Disposable { constructor( @IEnvironmentService private readonly _environmentService: IEnvironmentService, @ILogService private readonly _logService: ILogService ) { + super(); // We have no Language pack support for dev version (run from source) // So only cleanup when we have a build version. if (this._environmentService.isBuilt) { @@ -45,10 +44,6 @@ export class LanguagePackCachedDataCleaner { } } - dispose(): void { - this._disposables = dispose(this._disposables); - } - private _manageCachedDataSoon(): void { let handle: any = setTimeout(async () => { handle = undefined; @@ -101,12 +96,10 @@ export class LanguagePackCachedDataCleaner { } }, 40 * 1000); - this._disposables.push({ - dispose() { - if (handle !== undefined) { - clearTimeout(handle); - } + this._register(toDisposable(() => { + if (handle !== undefined) { + clearTimeout(handle); } - }); + })); } } \ No newline at end of file diff --git a/src/vs/code/electron-browser/sharedProcess/contrib/nodeCachedDataCleaner.ts b/src/vs/code/electron-browser/sharedProcess/contrib/nodeCachedDataCleaner.ts index fba3f2eb4..5c0b0ef0b 100644 --- a/src/vs/code/electron-browser/sharedProcess/contrib/nodeCachedDataCleaner.ts +++ b/src/vs/code/electron-browser/sharedProcess/contrib/nodeCachedDataCleaner.ts @@ -5,7 +5,7 @@ import { basename, dirname, join } from 'vs/base/common/path'; import { onUnexpectedError } from 'vs/base/common/errors'; -import { dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { readdir, rimraf, stat } from 'vs/base/node/pfs'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import product from 'vs/platform/product/node/product'; @@ -16,7 +16,7 @@ export class NodeCachedDataCleaner { ? 1000 * 60 * 60 * 24 * 7 // roughly 1 week : 1000 * 60 * 60 * 24 * 30 * 3; // roughly 3 months - private _disposables: IDisposable[] = []; + private readonly _disposables = new DisposableStore(); constructor( @IEnvironmentService private readonly _environmentService: IEnvironmentService @@ -25,7 +25,7 @@ export class NodeCachedDataCleaner { } dispose(): void { - this._disposables = dispose(this._disposables); + this._disposables.dispose(); } private _manageCachedDataSoon(): void { @@ -76,7 +76,7 @@ export class NodeCachedDataCleaner { }, 30 * 1000); - this._disposables.push(toDisposable(() => { + this._disposables.add(toDisposable(() => { if (handle) { clearTimeout(handle); handle = undefined; diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index e270021b7..b85c29ffc 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -13,14 +13,14 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment'; import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; -import { ExtensionManagementChannel } from 'vs/platform/extensionManagement/node/extensionManagementIpc'; +import { ExtensionManagementChannel } from 'vs/platform/extensionManagement/common/extensionManagementIpc'; import { IExtensionManagementService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; -import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; +import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ConfigurationService } from 'vs/platform/configuration/node/configurationService'; -import { IRequestService } from 'vs/platform/request/node/request'; -import { RequestService } from 'vs/platform/request/electron-browser/requestService'; +import { IRequestService } from 'vs/platform/request/common/request'; +import { RequestService } from 'vs/platform/request/browser/requestService'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { combinedAppender, NullTelemetryService, ITelemetryAppender, NullAppender, LogAppender } from 'vs/platform/telemetry/common/telemetryUtils'; import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProperties'; @@ -30,16 +30,15 @@ import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppen import { IWindowsService, ActiveWindowManager } from 'vs/platform/windows/common/windows'; import { WindowsService } from 'vs/platform/windows/electron-browser/windowsService'; import { ipcRenderer } from 'electron'; -import { createSpdLogService } from 'vs/platform/log/node/spdlogService'; import { ILogService, LogLevel } from 'vs/platform/log/common/log'; -import { LogLevelSetterChannelClient, FollowerLogService } from 'vs/platform/log/node/logIpc'; +import { LogLevelSetterChannelClient, FollowerLogService } from 'vs/platform/log/common/logIpc'; import { LocalizationsService } from 'vs/platform/localizations/node/localizations'; import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; import { LocalizationsChannel } from 'vs/platform/localizations/node/localizationsIpc'; import { DialogChannelClient } from 'vs/platform/dialogs/node/dialogIpc'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { IDisposable, dispose, combinedDisposable } from 'vs/base/common/lifecycle'; -import { DownloadService } from 'vs/platform/download/node/downloadService'; +import { combinedDisposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; +import { DownloadService } from 'vs/platform/download/common/downloadService'; import { IDownloadService } from 'vs/platform/download/common/download'; import { IChannel, IServerChannel, StaticRouter } from 'vs/base/parts/ipc/common/ipc'; import { NodeCachedDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/nodeCachedDataCleaner'; @@ -48,6 +47,16 @@ import { StorageDataCleaner } from 'vs/code/electron-browser/sharedProcess/contr import { LogsDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/logsDataCleaner'; import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { SpdLogService } from 'vs/platform/log/node/spdlogService'; +import { DiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsService'; +import { IDiagnosticsService } from 'vs/platform/diagnostics/common/diagnosticsService'; +import { DiagnosticsChannel } from 'vs/platform/diagnostics/node/diagnosticsIpc'; +import { FileService } from 'vs/platform/files/common/fileService'; +import { IFileService } from 'vs/platform/files/common/files'; +import { DiskFileSystemProvider } from 'vs/platform/files/electron-browser/diskFileSystemProvider'; +import { Schemas } from 'vs/base/common/network'; +import { IProductService } from 'vs/platform/product/common/product'; +import { ProductService } from 'vs/platform/product/node/productService'; export interface ISharedProcessConfiguration { readonly machineId: string; @@ -79,31 +88,34 @@ class MainProcessService implements IMainProcessService { } } -function main(server: Server, initData: ISharedProcessInitData, configuration: ISharedProcessConfiguration): void { +async function main(server: Server, initData: ISharedProcessInitData, configuration: ISharedProcessConfiguration): Promise { const services = new ServiceCollection(); - const disposables: IDisposable[] = []; + const disposables = new DisposableStore(); - const onExit = () => dispose(disposables); + const onExit = () => disposables.dispose(); process.once('exit', onExit); ipcRenderer.once('handshake:goodbye', onExit); - disposables.push(server); + disposables.add(server); const environmentService = new EnvironmentService(initData.args, process.execPath); const mainRouter = new StaticRouter(ctx => ctx === 'main'); const logLevelClient = new LogLevelSetterChannelClient(server.getChannel('loglevel', mainRouter)); - const logService = new FollowerLogService(logLevelClient, createSpdLogService('sharedprocess', initData.logLevel, environmentService.logsPath)); - disposables.push(logService); - + const logService = new FollowerLogService(logLevelClient, new SpdLogService('sharedprocess', environmentService.logsPath, initData.logLevel)); + disposables.add(logService); logService.info('main', JSON.stringify(configuration)); + const configurationService = new ConfigurationService(environmentService.settingsResource); + disposables.add(configurationService); + await configurationService.initialize(); + services.set(IEnvironmentService, environmentService); services.set(ILogService, logService); - services.set(IConfigurationService, new SyncDescriptor(ConfigurationService, [environmentService.appSettingsPath])); + services.set(IConfigurationService, configurationService); services.set(IRequestService, new SyncDescriptor(RequestService)); - services.set(IDownloadService, new SyncDescriptor(DownloadService)); + services.set(IProductService, new SyncDescriptor(ProductService)); const mainProcessService = new MainProcessService(server, mainRouter); services.set(IMainProcessService, mainProcessService); @@ -116,13 +128,25 @@ function main(server: Server, initData: ISharedProcessInitData, configuration: I const dialogChannel = server.getChannel('dialog', activeWindowRouter); services.set(IDialogService, new DialogChannelClient(dialogChannel)); + // Files + const fileService = new FileService(logService); + services.set(IFileService, fileService); + disposables.add(fileService); + + const diskFileSystemProvider = new DiskFileSystemProvider(logService); + disposables.add(diskFileSystemProvider); + fileService.registerProvider(Schemas.file, diskFileSystemProvider); + + services.set(IDownloadService, new SyncDescriptor(DownloadService)); + const instantiationService = new InstantiationService(services); + let telemetryService: ITelemetryService; instantiationService.invokeFunction(accessor => { const services = new ServiceCollection(); const environmentService = accessor.get(IEnvironmentService); const { appRoot, extensionsPath, extensionDevelopmentLocationURI: extensionDevelopmentLocationURI, isBuilt, installSourcePath } = environmentService; - const telemetryLogService = new FollowerLogService(logLevelClient, createSpdLogService('telemetry', initData.logLevel, environmentService.logsPath)); + const telemetryLogService = new FollowerLogService(logLevelClient, new SpdLogService('telemetry', environmentService.logsPath, initData.logLevel)); telemetryLogService.info('The below are logs for every telemetry event sent from VS Code once the log level is set to trace.'); telemetryLogService.info('==========================================================='); @@ -130,23 +154,26 @@ function main(server: Server, initData: ISharedProcessInitData, configuration: I if (!extensionDevelopmentLocationURI && !environmentService.args['disable-telemetry'] && product.enableTelemetry) { if (product.aiConfig && product.aiConfig.asimovKey && isBuilt) { appInsightsAppender = new AppInsightsAppender(eventPrefix, null, product.aiConfig.asimovKey, telemetryLogService); - disposables.push(appInsightsAppender); // Ensure the AI appender is disposed so that it flushes remaining data + disposables.add(toDisposable(() => appInsightsAppender!.flush())); // Ensure the AI appender is disposed so that it flushes remaining data } const config: ITelemetryServiceConfig = { appender: combinedAppender(appInsightsAppender, new LogAppender(logService)), commonProperties: resolveCommonProperties(product.commit, pkg.version, configuration.machineId, installSourcePath), - piiPaths: [appRoot, extensionsPath] + piiPaths: extensionsPath ? [appRoot, extensionsPath] : [appRoot] }; - services.set(ITelemetryService, new SyncDescriptor(TelemetryService, [config])); + telemetryService = new TelemetryService(config, configurationService); + services.set(ITelemetryService, telemetryService); } else { + telemetryService = NullTelemetryService; services.set(ITelemetryService, NullTelemetryService); } server.registerChannel('telemetryAppender', new TelemetryAppenderChannel(appInsightsAppender)); - services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService, [false])); + services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService)); services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService)); services.set(ILocalizationsService, new SyncDescriptor(LocalizationsService)); + services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService)); const instantiationService2 = instantiationService.createChild(services); @@ -160,18 +187,22 @@ function main(server: Server, initData: ISharedProcessInitData, configuration: I const localizationsChannel = new LocalizationsChannel(localizationsService); server.registerChannel('localizations', localizationsChannel); + const diagnosticsService = accessor.get(IDiagnosticsService); + const diagnosticsChannel = new DiagnosticsChannel(diagnosticsService); + server.registerChannel('diagnostics', diagnosticsChannel); + // clean up deprecated extensions (extensionManagementService as ExtensionManagementService).removeDeprecatedExtensions(); // update localizations cache (localizationsService as LocalizationsService).update(); // cache clean ups - disposables.push(combinedDisposable([ + disposables.add(combinedDisposable( instantiationService2.createInstance(NodeCachedDataCleaner), instantiationService2.createInstance(LanguagePackCachedDataCleaner), instantiationService2.createInstance(StorageDataCleaner), instantiationService2.createInstance(LogsDataCleaner) - ])); - disposables.push(extensionManagementService as ExtensionManagementService); + )); + disposables.add(extensionManagementService as ExtensionManagementService); }); }); } @@ -218,6 +249,6 @@ async function handshake(configuration: ISharedProcessConfiguration): Promise - + diff --git a/src/vs/code/electron-browser/workbench/workbench.js b/src/vs/code/electron-browser/workbench/workbench.js index dbec9eadb..dfe41b3d9 100644 --- a/src/vs/code/electron-browser/workbench/workbench.js +++ b/src/vs/code/electron-browser/workbench/workbench.js @@ -35,13 +35,7 @@ bootstrapWindow.load([ showPartsSplash(windowConfig); }, beforeLoaderConfig: function (windowConfig, loaderConfig) { - loaderConfig.recordStats = !!windowConfig['prof-modules']; - if (loaderConfig.nodeCachedData) { - const onNodeCachedData = window['MonacoEnvironment'].onNodeCachedData = []; - loaderConfig.nodeCachedData.onData = function () { - onNodeCachedData.push(arguments); - }; - } + loaderConfig.recordStats = true; }, beforeRequire: function () { perf.mark('willLoadWorkbenchMain'); @@ -49,7 +43,6 @@ bootstrapWindow.load([ }); /** - * // configuration: IWindowConfiguration * @param {{ * partsSplashPath?: string, * highContrast?: boolean, @@ -70,7 +63,7 @@ function showPartsSplash(configuration) { } } - // high contrast mode has been turned on from the outside, e.g OS -> ignore stored colors and layouts + // high contrast mode has been turned on from the outside, e.g. OS -> ignore stored colors and layouts if (data && configuration.highContrast && data.baseTheme !== 'hc-black') { data = undefined; } @@ -87,8 +80,8 @@ function showPartsSplash(configuration) { const style = document.createElement('style'); style.className = 'initialShellColors'; document.head.appendChild(style); - document.body.className = `monaco-shell ${baseTheme}`; - style.innerHTML = `.monaco-shell { background-color: ${shellBackground}; color: ${shellForeground}; }`; + document.body.className = baseTheme; + style.innerHTML = `body { background-color: ${shellBackground}; color: ${shellForeground}; }`; if (data && data.layoutInfo) { // restore parts if possible (we might not always store layout info) diff --git a/src/vs/code/electron-browser/workbench/workbench.nodeless.html b/src/vs/code/electron-browser/workbench/workbench.nodeless.html deleted file mode 100644 index e37abfdf5..000000000 --- a/src/vs/code/electron-browser/workbench/workbench.nodeless.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/src/vs/code/electron-browser/workbench/workbench.nodeless.js b/src/vs/code/electron-browser/workbench/workbench.nodeless.js deleted file mode 100644 index 4d7098fa3..000000000 --- a/src/vs/code/electron-browser/workbench/workbench.nodeless.js +++ /dev/null @@ -1,67 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -//@ts-check -'use strict'; - -(function () { - - function uriFromPath(_path) { - let pathName = _path.replace(/\\/g, '/'); - if (pathName.length > 0 && pathName.charAt(0) !== '/') { - pathName = '/' + pathName; - } - - let uri; - if (navigator.userAgent.indexOf('Windows') >= 0 && pathName.startsWith('//')) { // specially handle Windows UNC paths - uri = encodeURI('file:' + pathName); - } else { - uri = encodeURI('file://' + pathName); - } - - return uri.replace(/#/g, '%23'); - } - - function parseURLQueryArgs() { - const search = window.location.search || ''; - - return search.split(/[?&]/) - .filter(function (param) { return !!param; }) - .map(function (param) { return param.split('='); }) - .filter(function (param) { return param.length === 2; }) - .reduce(function (r, param) { r[param[0]] = decodeURIComponent(param[1]); return r; }, {}); - } - - function loadScript(path, callback) { - let script = document.createElement('script'); - script.onload = callback; - script.async = true; - script.type = 'text/javascript'; - script.src = path; - document.head.appendChild(script); - } - - loadScript('../../../../../out/vs/loader.js', function () { - - const args = parseURLQueryArgs(); - const configuration = JSON.parse(args['config'] || '{}') || {}; - - // @ts-ignore - require.config({ - baseUrl: uriFromPath(configuration.appRoot) + '/out', - }); - - // @ts-ignore - require([ - 'vs/workbench/workbench.nodeless.main', - 'vs/nls!vs/workbench/workbench.nodeless.main', - 'vs/css!vs/workbench/workbench.nodeless.main' - ], function () { - - // @ts-ignore - require('vs/workbench/browser/nodeless.main').main().then(undefined, console.error); - }); - }); -})(); \ No newline at end of file diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 5ba6e0944..785a214c7 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -9,7 +9,7 @@ import { WindowsManager } from 'vs/code/electron-main/windows'; import { IWindowsService, OpenContext, ActiveWindowManager, IURIToOpen } from 'vs/platform/windows/common/windows'; import { WindowsChannel } from 'vs/platform/windows/node/windowsIpc'; import { WindowsService } from 'vs/platform/windows/electron-main/windowsService'; -import { ILifecycleService, LifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; +import { ILifecycleService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; import { getShellEnvironment } from 'vs/code/node/shellEnv'; import { IUpdateService } from 'vs/platform/update/common/update'; import { UpdateChannel } from 'vs/platform/update/node/updateIpc'; @@ -36,12 +36,10 @@ import { getDelayedChannel, StaticRouter } from 'vs/base/parts/ipc/common/ipc'; import product from 'vs/platform/product/node/product'; import pkg from 'vs/platform/product/node/package'; import { ProxyAuthHandler } from 'vs/code/electron-main/auth'; -import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; -import { ConfigurationService } from 'vs/platform/configuration/node/configurationService'; +import { Disposable } from 'vs/base/common/lifecycle'; import { IWindowsMainService, ICodeWindow } from 'vs/platform/windows/electron-main/windows'; import { IHistoryMainService } from 'vs/platform/history/common/history'; -import { isUndefinedOrNull, withUndefinedAsNull } from 'vs/base/common/types'; -import { KeyboardLayoutMonitor } from 'vs/code/electron-main/keyboard'; +import { withUndefinedAsNull } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; import { WorkspacesChannel } from 'vs/platform/workspaces/node/workspacesIpc'; import { IWorkspacesMainService, hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces'; @@ -52,7 +50,7 @@ import { DarwinUpdateService } from 'vs/platform/update/electron-main/updateServ import { IIssueService } from 'vs/platform/issue/common/issue'; import { IssueChannel } from 'vs/platform/issue/node/issueIpc'; import { IssueService } from 'vs/platform/issue/electron-main/issueService'; -import { LogLevelSetterChannel } from 'vs/platform/log/node/logIpc'; +import { LogLevelSetterChannel } from 'vs/platform/log/common/logIpc'; import { setUnexpectedErrorHandler, onUnexpectedError } from 'vs/base/common/errors'; import { ElectronURLListener } from 'vs/platform/url/electron-main/electronUrlListener'; import { serve as serveDriver } from 'vs/platform/driver/electron-main/driver'; @@ -63,7 +61,6 @@ import { MenubarChannel } from 'vs/platform/menubar/node/menubarIpc'; import { hasArgs } from 'vs/platform/environment/node/argv'; import { RunOnceScheduler } from 'vs/base/common/async'; import { registerContextMenuListener } from 'vs/base/parts/contextmenu/electron-main/contextmenu'; -import { storeBackgroundColor } from 'vs/code/electron-main/theme'; import { homedir } from 'os'; import { join, sep } from 'vs/base/common/path'; import { localize } from 'vs/nls'; @@ -80,20 +77,23 @@ import { HistoryMainService } from 'vs/platform/history/electron-main/historyMai import { URLService } from 'vs/platform/url/common/urlService'; import { WorkspacesMainService } from 'vs/platform/workspaces/electron-main/workspacesMainService'; import { RemoteAgentConnectionContext } from 'vs/platform/remote/common/remoteAgentEnvironment'; -import { nodeWebSocketFactory } from 'vs/platform/remote/node/nodeWebSocketFactory'; +import { nodeSocketFactory } from 'vs/platform/remote/node/nodeSocketFactory'; import { VSBuffer } from 'vs/base/common/buffer'; import { statSync } from 'fs'; +import { ISignService } from 'vs/platform/sign/common/sign'; +import { IDiagnosticsService } from 'vs/platform/diagnostics/common/diagnosticsService'; +import { DiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsIpc'; +import { FileService } from 'vs/platform/files/common/fileService'; +import { IFileService } from 'vs/platform/files/common/files'; +import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; +import { ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/extensionHostDebugIpc'; export class CodeApplication extends Disposable { private static readonly MACHINE_ID_KEY = 'telemetry.machineId'; + private static readonly TRUE_MACHINE_ID_KEY = 'telemetry.trueMachineId'; - private windowsMainService: IWindowsMainService; - - private electronIpcServer: ElectronIPCServer; - - private sharedProcess: SharedProcess; - private sharedProcessClient: Promise; + private windowsMainService: IWindowsMainService | undefined; constructor( private readonly mainIpcServer: Server, @@ -102,14 +102,12 @@ export class CodeApplication extends Disposable { @ILogService private readonly logService: ILogService, @IEnvironmentService private readonly environmentService: IEnvironmentService, @ILifecycleService private readonly lifecycleService: ILifecycleService, - @IConfigurationService private readonly configurationService: ConfigurationService, - @IStateService private readonly stateService: IStateService + @IConfigurationService private readonly configurationService: IConfigurationService, + @IStateService private readonly stateService: IStateService, + @ISignService private readonly signService: ISignService ) { super(); - this._register(mainIpcServer); - this._register(configurationService); - this.registerListeners(); } @@ -120,12 +118,12 @@ export class CodeApplication extends Disposable { process.on('uncaughtException', err => this.onUnexpectedError(err)); process.on('unhandledRejection', (reason: unknown) => onUnexpectedError(reason)); - // Contextmenu via IPC support - registerContextMenuListener(); - // Dispose on shutdown this.lifecycleService.onWillShutdown(() => this.dispose()); + // Contextmenu via IPC support + registerContextMenuListener(); + app.on('accessibility-support-changed', (event: Event, accessibilitySupportEnabled: boolean) => { if (this.windowsMainService) { this.windowsMainService.sendToAll('vscode:accessibilitySupportChanged', accessibilitySupportEnabled); @@ -142,8 +140,40 @@ export class CodeApplication extends Disposable { }); // Security related measures (https://electronjs.org/docs/tutorial/security) - // DO NOT CHANGE without consulting the documentation - app.on('web-contents-created', (event: Electron.Event, contents) => { + // + // !!! DO NOT CHANGE without consulting the documentation !!! + // + // app.on('remote-get-guest-web-contents', event => event.preventDefault()); // TODO@Ben TODO@Matt revisit this need for + app.on('remote-require', (event, sender, module) => { + this.logService.trace('App#on(remote-require): prevented'); + + event.preventDefault(); + }); + app.on('remote-get-global', (event, sender, module) => { + this.logService.trace(`App#on(remote-get-global): prevented on ${module}`); + + event.preventDefault(); + }); + app.on('remote-get-builtin', (event, sender, module) => { + this.logService.trace(`App#on(remote-get-builtin): prevented on ${module}`); + + if (module !== 'clipboard') { + event.preventDefault(); + } + }); + app.on('remote-get-current-window', event => { + this.logService.trace(`App#on(remote-get-current-window): prevented`); + + event.preventDefault(); + }); + app.on('remote-get-current-web-contents', event => { + // The driver needs access to web contents + if (!this.environmentService.args.driver) { + this.logService.trace(`App#on(remote-get-current-web-contents): prevented`); + event.preventDefault(); + } + }); + app.on('web-contents-created', (_event: Electron.Event, contents) => { contents.on('will-attach-webview', (event: Electron.Event, webPreferences, params) => { const isValidWebviewSource = (source: string): boolean => { @@ -198,7 +228,7 @@ export class CodeApplication extends Disposable { event.preventDefault(); // Keep in array because more might come! - macOpenFileURIs.push(getURIToOpenFromPathSync(path)); + macOpenFileURIs.push(this.getURIToOpenFromPathSync(path)); // Clear previous handler if any if (runningTimeout !== null) { @@ -213,8 +243,10 @@ export class CodeApplication extends Disposable { context: OpenContext.DOCK /* can also be opening from finder while app is running */, cli: this.environmentService.args, urisToOpen: macOpenFileURIs, + gotoLineMode: false, preferNewWindow: true /* dropping on the dock or opening from finder prefers to open in a new window */ }); + macOpenFileURIs = []; runningTimeout = null; } @@ -222,7 +254,9 @@ export class CodeApplication extends Disposable { }); app.on('new-window-for-tab', () => { - this.windowsMainService.openNewWindow(OpenContext.DESKTOP); //macOS native tab "+" button + if (this.windowsMainService) { + this.windowsMainService.openNewWindow(OpenContext.DESKTOP); //macOS native tab "+" button + } }); ipc.on('vscode:exit', (event: Event, code: number) => { @@ -232,37 +266,20 @@ export class CodeApplication extends Disposable { this.lifecycleService.kill(code); }); - ipc.on('vscode:fetchShellEnv', (event: Event) => { + ipc.on('vscode:fetchShellEnv', async (event: Event) => { const webContents = event.sender; - getShellEnvironment().then(shellEnv => { + + try { + const shellEnv = await getShellEnvironment(this.logService, this.environmentService); if (!webContents.isDestroyed()) { webContents.send('vscode:acceptShellEnv', shellEnv); } - }, err => { + } catch (error) { if (!webContents.isDestroyed()) { webContents.send('vscode:acceptShellEnv', {}); } - this.logService.error('Error fetching shell env', err); - }); - }); - - ipc.on('vscode:broadcast', (event: Event, windowId: number, broadcast: { channel: string; payload: object; }) => { - if (this.windowsMainService && broadcast.channel && !isUndefinedOrNull(broadcast.payload)) { - this.logService.trace('IPC#vscode:broadcast', broadcast.channel, broadcast.payload); - - // Handle specific events on main side - this.onBroadcast(broadcast.channel, broadcast.payload); - - // Send to all windows (except sender window) - this.windowsMainService.sendToAll('vscode:broadcast', broadcast, [windowId]); - } - }); - - ipc.on('vscode:extensionHostDebug', (_: Event, windowId: number, broadcast: any) => { - if (this.windowsMainService) { - // Send to all windows (except sender window) - this.windowsMainService.sendToAll('vscode:extensionHostDebug', broadcast, [windowId]); + this.logService.error('Error fetching shell env', error); } }); @@ -271,11 +288,25 @@ export class CodeApplication extends Disposable { ipc.on('vscode:reloadWindow', (event: Event) => event.sender.reload()); - powerMonitor.on('resume', () => { // After waking up from sleep - if (this.windowsMainService) { - this.windowsMainService.sendToAll('vscode:osResume', undefined); - } - }); + // Some listeners after window opened + (async () => { + await this.lifecycleService.when(LifecycleMainPhase.AfterWindowOpen); + + // After waking up from sleep (after window opened) + powerMonitor.on('resume', () => { + if (this.windowsMainService) { + this.windowsMainService.sendToAll('vscode:osResume', undefined); + } + }); + + // Keyboard layout changes (after window opened) + const nativeKeymap = await import('native-keymap'); + nativeKeymap.onDidChangeKeyboardLayout(() => { + if (this.windowsMainService) { + this.windowsMainService.sendToAll('vscode:keyboardLayoutChanged', false); + } + }); + })(); } private onUnexpectedError(err: Error): void { @@ -299,15 +330,7 @@ export class CodeApplication extends Disposable { } } - private onBroadcast(event: string, payload: object): void { - - // Theme changes - if (event === 'vscode:changeColorTheme' && typeof payload === 'string') { - storeBackgroundColor(this.stateService, JSON.parse(payload)); - } - } - - startup(): Promise { + async startup(): Promise { this.logService.debug('Starting VS Code'); this.logService.debug(`from: ${this.environmentService.appRoot}`); this.logService.debug('args:', this.environmentService.args); @@ -335,167 +358,182 @@ export class CodeApplication extends Disposable { } // Create Electron IPC Server - this.electronIpcServer = new ElectronIPCServer(); - - const startupWithMachineId = (machineId: string) => { - this.logService.trace(`Resolved machine identifier: ${machineId}`); + const electronIpcServer = new ElectronIPCServer(); - // Spawn shared process - this.sharedProcess = this.instantiationService.createInstance(SharedProcess, machineId, this.userEnv); - this.sharedProcessClient = this.sharedProcess.whenReady().then(() => connect(this.environmentService.sharedIPCHandle, 'main')); + // Resolve unique machine ID + this.logService.trace('Resolving machine identifier...'); + const { machineId, trueMachineId } = await this.resolveMachineId(); + this.logService.trace(`Resolved machine identifier: ${machineId} (trueMachineId: ${trueMachineId})`); + + // Spawn shared process after the first window has opened and 3s have passed + const sharedProcess = this.instantiationService.createInstance(SharedProcess, machineId, this.userEnv); + const sharedProcessClient = sharedProcess.whenReady().then(() => connect(this.environmentService.sharedIPCHandle, 'main')); + this.lifecycleService.when(LifecycleMainPhase.AfterWindowOpen).then(() => { + this._register(new RunOnceScheduler(async () => { + const userEnv = await getShellEnvironment(this.logService, this.environmentService); + + sharedProcess.spawn(userEnv); + }, 3000)).schedule(); + }); - // Services - return this.initServices(machineId).then(appInstantiationService => { + // Services + const appInstantiationService = await this.createServices(machineId, trueMachineId, sharedProcess, sharedProcessClient); - // Create driver - if (this.environmentService.driverHandle) { - serveDriver(this.electronIpcServer, this.environmentService.driverHandle, this.environmentService, appInstantiationService).then(server => { - this.logService.info('Driver started at:', this.environmentService.driverHandle); - this._register(server); - }); - } + // Create driver + if (this.environmentService.driverHandle) { + const server = await serveDriver(electronIpcServer, this.environmentService.driverHandle!, this.environmentService, appInstantiationService); - // Setup Auth Handler - const authHandler = appInstantiationService.createInstance(ProxyAuthHandler); - this._register(authHandler); + this.logService.info('Driver started at:', this.environmentService.driverHandle); + this._register(server); + } - // Open Windows - const windows = appInstantiationService.invokeFunction(accessor => this.openFirstWindow(accessor)); + // Setup Auth Handler + const authHandler = appInstantiationService.createInstance(ProxyAuthHandler); + this._register(authHandler); - // Post Open Windows Tasks - appInstantiationService.invokeFunction(accessor => this.afterWindowOpen(accessor)); + // Open Windows + const windows = appInstantiationService.invokeFunction(accessor => this.openFirstWindow(accessor, electronIpcServer, sharedProcessClient)); - // Tracing: Stop tracing after windows are ready if enabled - if (this.environmentService.args.trace) { - this.stopTracingEventually(windows); - } - }); - }; + // Post Open Windows Tasks + this.afterWindowOpen(); - // Resolve unique machine ID - this.logService.trace('Resolving machine identifier...'); - const resolvedMachineId = this.resolveMachineId(); - if (typeof resolvedMachineId === 'string') { - return startupWithMachineId(resolvedMachineId); - } else { - return resolvedMachineId.then(machineId => startupWithMachineId(machineId)); + // Tracing: Stop tracing after windows are ready if enabled + if (this.environmentService.args.trace) { + this.stopTracingEventually(windows); } } - private resolveMachineId(): string | Promise { - const machineId = this.stateService.getItem(CodeApplication.MACHINE_ID_KEY); - if (machineId) { - return machineId; - } + private async resolveMachineId(): Promise<{ machineId: string, trueMachineId?: string }> { - return getMachineId().then(machineId => { - this.stateService.setItem(CodeApplication.MACHINE_ID_KEY, machineId); + // We cache the machineId for faster lookups on startup + // and resolve it only once initially if not cached + let machineId = this.stateService.getItem(CodeApplication.MACHINE_ID_KEY); + if (!machineId) { + machineId = await getMachineId(); - return machineId; - }); - } + this.stateService.setItem(CodeApplication.MACHINE_ID_KEY, machineId); + } - private stopTracingEventually(windows: ICodeWindow[]): void { - this.logService.info(`Tracing: waiting for windows to get ready...`); + // Check if machineId is hashed iBridge Device + let trueMachineId: string | undefined; + if (isMacintosh && machineId === '6c9d2bc8f91b89624add29c0abeae7fb42bf539fa1cdb2e3e57cd668fa9bcead') { + trueMachineId = this.stateService.getItem(CodeApplication.TRUE_MACHINE_ID_KEY); + if (!trueMachineId) { + trueMachineId = await getMachineId(); - let recordingStopped = false; - const stopRecording = (timeout: boolean) => { - if (recordingStopped) { - return; + this.stateService.setItem(CodeApplication.TRUE_MACHINE_ID_KEY, trueMachineId); } + } - recordingStopped = true; // only once + return { machineId, trueMachineId }; + } - contentTracing.stopRecording(join(homedir(), `${product.applicationName}-${Math.random().toString(16).slice(-4)}.trace.txt`), path => { - if (!timeout) { - this.windowsMainService.showMessageBox({ - type: 'info', - message: localize('trace.message', "Successfully created trace."), - detail: localize('trace.detail', "Please create an issue and manually attach the following file:\n{0}", path), - buttons: [localize('trace.ok', "Ok")] - }, this.windowsMainService.getLastActiveWindow()); - } else { - this.logService.info(`Tracing: data recorded (after 30s timeout) to ${path}`); - } - }); - }; + private async createServices(machineId: string, trueMachineId: string | undefined, sharedProcess: SharedProcess, sharedProcessClient: Promise>): Promise { + const services = new ServiceCollection(); - // Wait up to 30s before creating the trace anyways - const timeoutHandle = setTimeout(() => stopRecording(true), 30000); + // Files + const fileService = this._register(new FileService(this.logService)); + services.set(IFileService, fileService); - // Wait for all windows to get ready and stop tracing then - Promise.all(windows.map(window => window.ready())).then(() => { - clearTimeout(timeoutHandle); - stopRecording(false); - }); - } + const diskFileSystemProvider = this._register(new DiskFileSystemProvider(this.logService)); + fileService.registerProvider(Schemas.file, diskFileSystemProvider); - private initServices(machineId: string): Promise { - const services = new ServiceCollection(); + switch (process.platform) { + case 'win32': + services.set(IUpdateService, new SyncDescriptor(Win32UpdateService)); + break; - if (process.platform === 'win32') { - services.set(IUpdateService, new SyncDescriptor(Win32UpdateService)); - } else if (process.platform === 'linux') { - if (process.env.SNAP && process.env.SNAP_REVISION) { - services.set(IUpdateService, new SyncDescriptor(SnapUpdateService, [process.env.SNAP, process.env.SNAP_REVISION])); - } else { - services.set(IUpdateService, new SyncDescriptor(LinuxUpdateService)); - } - } else if (process.platform === 'darwin') { - services.set(IUpdateService, new SyncDescriptor(DarwinUpdateService)); + case 'linux': + if (process.env.SNAP && process.env.SNAP_REVISION) { + services.set(IUpdateService, new SyncDescriptor(SnapUpdateService, [process.env.SNAP, process.env.SNAP_REVISION])); + } else { + services.set(IUpdateService, new SyncDescriptor(LinuxUpdateService)); + } + break; + + case 'darwin': + services.set(IUpdateService, new SyncDescriptor(DarwinUpdateService)); + break; } - services.set(IWindowsMainService, new SyncDescriptor(WindowsManager, [machineId])); - services.set(IWindowsService, new SyncDescriptor(WindowsService, [this.sharedProcess])); + services.set(IWindowsMainService, new SyncDescriptor(WindowsManager, [machineId, this.userEnv])); + services.set(IWindowsService, new SyncDescriptor(WindowsService, [sharedProcess])); services.set(ILaunchService, new SyncDescriptor(LaunchService)); + + const diagnosticsChannel = getDelayedChannel(sharedProcessClient.then(client => client.getChannel('diagnostics'))); + services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService, [diagnosticsChannel])); + services.set(IIssueService, new SyncDescriptor(IssueService, [machineId, this.userEnv])); services.set(IMenubarService, new SyncDescriptor(MenubarService)); - services.set(IStorageMainService, new SyncDescriptor(StorageMainService)); - services.set(IBackupMainService, new SyncDescriptor(BackupMainService)); + + const storageMainService = new StorageMainService(this.logService, this.environmentService); + services.set(IStorageMainService, storageMainService); + this.lifecycleService.onWillShutdown(e => e.join(storageMainService.close())); + + const backupMainService = new BackupMainService(this.environmentService, this.configurationService, this.logService); + services.set(IBackupMainService, backupMainService); + services.set(IHistoryMainService, new SyncDescriptor(HistoryMainService)); services.set(IURLService, new SyncDescriptor(URLService)); services.set(IWorkspacesMainService, new SyncDescriptor(WorkspacesMainService)); // Telemetry if (!this.environmentService.isExtensionDevelopment && !this.environmentService.args['disable-telemetry'] && !!product.enableTelemetry) { - const channel = getDelayedChannel(this.sharedProcessClient.then(c => c.getChannel('telemetryAppender'))); + const channel = getDelayedChannel(sharedProcessClient.then(client => client.getChannel('telemetryAppender'))); const appender = combinedAppender(new TelemetryAppenderClient(channel), new LogAppender(this.logService)); const commonProperties = resolveCommonProperties(product.commit, pkg.version, machineId, this.environmentService.installSourcePath); - const piiPaths = [this.environmentService.appRoot, this.environmentService.extensionsPath]; - const config: ITelemetryServiceConfig = { appender, commonProperties, piiPaths }; + const piiPaths = this.environmentService.extensionsPath ? [this.environmentService.appRoot, this.environmentService.extensionsPath] : [this.environmentService.appRoot]; + const config: ITelemetryServiceConfig = { appender, commonProperties, piiPaths, trueMachineId }; services.set(ITelemetryService, new SyncDescriptor(TelemetryService, [config])); } else { services.set(ITelemetryService, NullTelemetryService); } - const appInstantiationService = this.instantiationService.createChild(services); - // Init services that require it - return appInstantiationService.invokeFunction(accessor => Promise.all([ - this.initStorageService(accessor), - this.initBackupService(accessor) - ])).then(() => appInstantiationService); + await backupMainService.initialize(); + + return this.instantiationService.createChild(services); } - private initStorageService(accessor: ServicesAccessor): Promise { - const storageMainService = accessor.get(IStorageMainService) as StorageMainService; + private stopTracingEventually(windows: ICodeWindow[]): void { + this.logService.info(`Tracing: waiting for windows to get ready...`); - // Ensure to close storage on shutdown - this.lifecycleService.onWillShutdown(e => e.join(storageMainService.close())); + let recordingStopped = false; + const stopRecording = (timeout: boolean) => { + if (recordingStopped) { + return; + } - return Promise.resolve(); + recordingStopped = true; // only once - } + contentTracing.stopRecording(join(homedir(), `${product.applicationName}-${Math.random().toString(16).slice(-4)}.trace.txt`), path => { + if (!timeout) { + if (this.windowsMainService) { + this.windowsMainService.showMessageBox({ + type: 'info', + message: localize('trace.message', "Successfully created trace."), + detail: localize('trace.detail', "Please create an issue and manually attach the following file:\n{0}", path), + buttons: [localize('trace.ok', "Ok")] + }, this.windowsMainService.getLastActiveWindow()); + } + } else { + this.logService.info(`Tracing: data recorded (after 30s timeout) to ${path}`); + } + }); + }; - private initBackupService(accessor: ServicesAccessor): Promise { - const backupMainService = accessor.get(IBackupMainService) as BackupMainService; + // Wait up to 30s before creating the trace anyways + const timeoutHandle = setTimeout(() => stopRecording(true), 30000); - return backupMainService.initialize(); + // Wait for all windows to get ready and stop tracing then + Promise.all(windows.map(window => window.ready())).then(() => { + clearTimeout(timeoutHandle); + stopRecording(false); + }); } - private openFirstWindow(accessor: ServicesAccessor): ICodeWindow[] { - const appInstantiationService = accessor.get(IInstantiationService); + private openFirstWindow(accessor: ServicesAccessor, electronIpcServer: ElectronIPCServer, sharedProcessClient: Promise>): ICodeWindow[] { // Register more Main IPC services const launchService = accessor.get(ILaunchService); @@ -505,48 +543,51 @@ export class CodeApplication extends Disposable { // Register more Electron IPC services const updateService = accessor.get(IUpdateService); const updateChannel = new UpdateChannel(updateService); - this.electronIpcServer.registerChannel('update', updateChannel); + electronIpcServer.registerChannel('update', updateChannel); const issueService = accessor.get(IIssueService); const issueChannel = new IssueChannel(issueService); - this.electronIpcServer.registerChannel('issue', issueChannel); + electronIpcServer.registerChannel('issue', issueChannel); const workspacesService = accessor.get(IWorkspacesMainService); - const workspacesChannel = appInstantiationService.createInstance(WorkspacesChannel, workspacesService); - this.electronIpcServer.registerChannel('workspaces', workspacesChannel); + const workspacesChannel = new WorkspacesChannel(workspacesService); + electronIpcServer.registerChannel('workspaces', workspacesChannel); const windowsService = accessor.get(IWindowsService); const windowsChannel = new WindowsChannel(windowsService); - this.electronIpcServer.registerChannel('windows', windowsChannel); - this.sharedProcessClient.then(client => client.registerChannel('windows', windowsChannel)); + electronIpcServer.registerChannel('windows', windowsChannel); + sharedProcessClient.then(client => client.registerChannel('windows', windowsChannel)); const menubarService = accessor.get(IMenubarService); const menubarChannel = new MenubarChannel(menubarService); - this.electronIpcServer.registerChannel('menubar', menubarChannel); + electronIpcServer.registerChannel('menubar', menubarChannel); const urlService = accessor.get(IURLService); const urlChannel = new URLServiceChannel(urlService); - this.electronIpcServer.registerChannel('url', urlChannel); + electronIpcServer.registerChannel('url', urlChannel); const storageMainService = accessor.get(IStorageMainService); const storageChannel = this._register(new GlobalStorageDatabaseChannel(this.logService, storageMainService as StorageMainService)); - this.electronIpcServer.registerChannel('storage', storageChannel); + electronIpcServer.registerChannel('storage', storageChannel); // Log level management const logLevelChannel = new LogLevelSetterChannel(accessor.get(ILogService)); - this.electronIpcServer.registerChannel('loglevel', logLevelChannel); - this.sharedProcessClient.then(client => client.registerChannel('loglevel', logLevelChannel)); + electronIpcServer.registerChannel('loglevel', logLevelChannel); + sharedProcessClient.then(client => client.registerChannel('loglevel', logLevelChannel)); + + // ExtensionHost Debug broadcast service + electronIpcServer.registerChannel(ExtensionHostDebugBroadcastChannel.ChannelName, new ExtensionHostDebugBroadcastChannel()); - // Lifecycle - (this.lifecycleService as LifecycleService).ready(); + // Signal phase: ready (services set) + this.lifecycleService.phase = LifecycleMainPhase.Ready; // Propagate to clients - const windowsMainService = this.windowsMainService = accessor.get(IWindowsMainService); // TODO@Joao: unfold this + const windowsMainService = this.windowsMainService = accessor.get(IWindowsMainService); // Create a URL handler which forwards to the last active window const activeWindowManager = new ActiveWindowManager(windowsService); const activeWindowRouter = new StaticRouter(ctx => activeWindowManager.getActiveClientId().then(id => ctx === id)); - const urlHandlerChannel = this.electronIpcServer.getChannel('urlHandler', activeWindowRouter); + const urlHandlerChannel = electronIpcServer.getChannel('urlHandler', activeWindowRouter); const multiplexURLHandler = new URLHandlerChannelClient(urlHandlerChannel); // On Mac, Code can be running without any open windows, so we must create a window to handle urls, @@ -555,15 +596,17 @@ export class CodeApplication extends Disposable { const environmentService = accessor.get(IEnvironmentService); urlService.registerHandler({ - handleURL(uri: URI): Promise { + async handleURL(uri: URI): Promise { if (windowsMainService.getWindowCount() === 0) { - const cli = { ...environmentService.args, goto: true }; - const [window] = windowsMainService.open({ context: OpenContext.API, cli, forceEmpty: true }); + const cli = { ...environmentService.args }; + const [window] = windowsMainService.open({ context: OpenContext.API, cli, forceEmpty: true, gotoLineMode: true }); + + await window.ready(); - return window.ready().then(() => urlService.open(uri)); + return urlService.open(uri); } - return Promise.resolve(false); + return false; } }); } @@ -574,11 +617,9 @@ export class CodeApplication extends Disposable { // Watch Electron URLs and forward them to the UrlService const args = this.environmentService.args; const urls = args['open-url'] ? args._urls : []; - const urlListener = new ElectronURLListener(urls || [], urlService, this.windowsMainService); + const urlListener = new ElectronURLListener(urls || [], urlService, windowsMainService); this._register(urlListener); - this.windowsMainService.ready(this.userEnv); - // Open our first window const macOpenFiles: string[] = (global).macOpenFiles; const context = !!process.env['VSCODE_CLI'] ? OpenContext.CLI : OpenContext.DESKTOP; @@ -588,9 +629,9 @@ export class CodeApplication extends Disposable { const noRecentEntry = args['skip-add-to-recently-opened'] === true; const waitMarkerFileURI = args.wait && args.waitMarkerFilePath ? URI.file(args.waitMarkerFilePath) : undefined; + // new window if "-n" was used without paths if (args['new-window'] && !hasCliArgs && !hasFolderURIs && !hasFileURIs) { - // new window if "-n" was used without paths - return this.windowsMainService.open({ + return windowsMainService.open({ context, cli: args, forceNewWindow: true, @@ -601,85 +642,56 @@ export class CodeApplication extends Disposable { }); } + // mac: open-file event received on startup if (macOpenFiles && macOpenFiles.length && !hasCliArgs && !hasFolderURIs && !hasFileURIs) { - // mac: open-file event received on startup - return this.windowsMainService.open({ + return windowsMainService.open({ context: OpenContext.DOCK, cli: args, - urisToOpen: macOpenFiles.map(getURIToOpenFromPathSync), + urisToOpen: macOpenFiles.map(file => this.getURIToOpenFromPathSync(file)), noRecentEntry, waitMarkerFileURI, + gotoLineMode: false, initialStartup: true }); } // default: read paths from cli - return this.windowsMainService.open({ + return windowsMainService.open({ context, cli: args, forceNewWindow: args['new-window'] || (!hasCliArgs && args['unity-launch']), diffMode: args.diff, noRecentEntry, waitMarkerFileURI, + gotoLineMode: args.goto, initialStartup: true }); } - private afterWindowOpen(accessor: ServicesAccessor): void { - const windowsMainService = accessor.get(IWindowsMainService); - const historyMainService = accessor.get(IHistoryMainService); - - if (isWindows) { - - // Setup Windows mutex - try { - const Mutex = (require.__$__nodeRequire('windows-mutex') as any).Mutex; - const windowsMutex = new Mutex(product.win32MutexName); - this._register(toDisposable(() => windowsMutex.release())); - } catch (e) { - if (!this.environmentService.isBuilt) { - windowsMainService.showMessageBox({ - title: product.nameLong, - type: 'warning', - message: 'Failed to load windows-mutex!', - detail: e.toString(), - noLink: true - }); - } + private getURIToOpenFromPathSync(path: string): IURIToOpen { + try { + const fileStat = statSync(path); + if (fileStat.isDirectory()) { + return { folderUri: URI.file(path) }; } - // Ensure Windows foreground love module - try { - // tslint:disable-next-line:no-unused-expression - require.__$__nodeRequire('windows-foreground-love'); - } catch (e) { - if (!this.environmentService.isBuilt) { - windowsMainService.showMessageBox({ - title: product.nameLong, - type: 'warning', - message: 'Failed to load windows-foreground-love!', - detail: e.toString(), - noLink: true - }); - } + if (hasWorkspaceFileExtension(path)) { + return { workspaceUri: URI.file(path) }; } + } catch (error) { + // ignore errors } - // Remote Authorities - this.handleRemoteAuthorities(); + return { fileUri: URI.file(path) }; + } - // Keyboard layout changes - KeyboardLayoutMonitor.INSTANCE.onDidChangeKeyboardLayout(() => { - this.windowsMainService.sendToAll('vscode:keyboardLayoutChanged', false); - }); + private afterWindowOpen(): void { - // Jump List - historyMainService.updateWindowsJumpList(); - historyMainService.onRecentlyOpenedChange(() => historyMainService.updateWindowsJumpList()); + // Signal phase: after window open + this.lifecycleService.phase = LifecycleMainPhase.AfterWindowOpen; - // Start shared process after a while - const sharedProcessSpawn = this._register(new RunOnceScheduler(() => getShellEnvironment().then(userEnv => this.sharedProcess.spawn(userEnv)), 3000)); - sharedProcessSpawn.schedule(); + // Remote Authorities + this.handleRemoteAuthorities(); } private handleRemoteAuthorities(): void { @@ -692,18 +704,21 @@ export class CodeApplication extends Disposable { private readonly _connection: Promise; private readonly _disposeRunner: RunOnceScheduler; - constructor(authority: string, host: string, port: number) { + constructor(authority: string, host: string, port: number, signService: ISignService) { this._authority = authority; + const options: IConnectionOptions = { - isBuilt: isBuilt, + isBuilt, commit: product.commit, - webSocketFactory: nodeWebSocketFactory, + socketFactory: nodeSocketFactory, addressProvider: { getAddress: () => { return Promise.resolve({ host, port }); } - } + }, + signService }; + this._connection = connectRemoteAgentManagement(options, authority, `main`); this._disposeRunner = new RunOnceScheduler(() => this.dispose(), 5000); } @@ -711,14 +726,13 @@ export class CodeApplication extends Disposable { dispose(): void { this._disposeRunner.dispose(); connectionPool.delete(this._authority); - this._connection.then((connection) => { - connection.dispose(); - }); + this._connection.then(connection => connection.dispose()); } async getClient(): Promise> { this._disposeRunner.schedule(); const connection = await this._connection; + return connection.client; } } @@ -726,7 +740,9 @@ export class CodeApplication extends Disposable { const resolvedAuthorities = new Map(); ipc.on('vscode:remoteAuthorityResolved', (event: Electron.Event, data: ResolvedAuthority) => { this.logService.info('Received resolved authority', data.authority); + resolvedAuthorities.set(data.authority, data); + // Make sure to close and remove any existing connections if (connectionPool.has(data.authority)) { connectionPool.get(data.authority)!.dispose(); @@ -735,15 +751,19 @@ export class CodeApplication extends Disposable { const resolveAuthority = (authority: string): ResolvedAuthority | null => { this.logService.info('Resolving authority', authority); + if (authority.indexOf('+') >= 0) { if (resolvedAuthorities.has(authority)) { return withUndefinedAsNull(resolvedAuthorities.get(authority)); } + this.logService.info('Didnot find resolved authority for', authority); + return null; } else { const [host, strPort] = authority.split(':'); const port = parseInt(strPort, 10); + return { authority, host, port }; } }; @@ -752,6 +772,7 @@ export class CodeApplication extends Disposable { if (request.method !== 'GET') { return callback(undefined); } + const uri = URI.parse(request.url); let activeConnection: ActiveConnection | undefined; @@ -763,9 +784,11 @@ export class CodeApplication extends Disposable { callback(undefined); return; } - activeConnection = new ActiveConnection(uri.authority, resolvedAuthority.host, resolvedAuthority.port); + + activeConnection = new ActiveConnection(uri.authority, resolvedAuthority.host, resolvedAuthority.port, this.signService); connectionPool.set(uri.authority, activeConnection); } + try { const rawClient = await activeConnection!.getClient(); if (connectionPool.has(uri.authority)) { // not disposed in the meantime @@ -784,16 +807,3 @@ export class CodeApplication extends Disposable { }); } } - -function getURIToOpenFromPathSync(path: string): IURIToOpen { - try { - const fileStat = statSync(path); - if (fileStat.isDirectory()) { - return { folderUri: URI.file(path) }; - } else if (hasWorkspaceFileExtension(path)) { - return { workspaceUri: URI.file(path) }; - } - } catch (error) { - } - return { fileUri: URI.file(path) }; -} diff --git a/src/vs/code/electron-main/auth.ts b/src/vs/code/electron-main/auth.ts index ed92533c3..6fbd3fcce 100644 --- a/src/vs/code/electron-main/auth.ts +++ b/src/vs/code/electron-main/auth.ts @@ -54,7 +54,11 @@ export class ProxyAuthHandler { width: 450, height: 220, show: true, - title: 'VS Code' + title: 'VS Code', + webPreferences: { + nodeIntegration: true, + webviewTag: true + } }; const focusedWindow = this.windowsMainService.getFocusedWindow(); diff --git a/src/vs/code/electron-main/keyboard.ts b/src/vs/code/electron-main/keyboard.ts deleted file mode 100644 index 2ec1623f1..000000000 --- a/src/vs/code/electron-main/keyboard.ts +++ /dev/null @@ -1,32 +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 nativeKeymap from 'native-keymap'; -import { IDisposable } from 'vs/base/common/lifecycle'; -import { Emitter } from 'vs/base/common/event'; - -export class KeyboardLayoutMonitor { - - public static readonly INSTANCE = new KeyboardLayoutMonitor(); - - private readonly _emitter: Emitter; - private _registered: boolean; - - private constructor() { - this._emitter = new Emitter(); - this._registered = false; - } - - public onDidChangeKeyboardLayout(callback: () => void): IDisposable { - if (!this._registered) { - this._registered = true; - - nativeKeymap.onDidChangeKeyboardLayout(() => { - this._emitter.fire(); - }); - } - return this._emitter.event(callback); - } -} \ No newline at end of file diff --git a/src/vs/code/electron-main/logUploader.ts b/src/vs/code/electron-main/logUploader.ts deleted file mode 100644 index 28ce4f7f1..000000000 --- a/src/vs/code/electron-main/logUploader.ts +++ /dev/null @@ -1,153 +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 os from 'os'; -import * as cp from 'child_process'; -import * as fs from 'fs'; - -import * as path from 'vs/base/common/path'; -import { localize } from 'vs/nls'; -import product from 'vs/platform/product/node/product'; -import { IRequestService } from 'vs/platform/request/node/request'; -import { IRequestContext } from 'vs/base/node/request'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { CancellationToken } from 'vs/base/common/cancellation'; -import { ILaunchService } from 'vs/platform/launch/electron-main/launchService'; - -interface PostResult { - readonly blob_id: string; -} - -class Endpoint { - private constructor( - public readonly url: string - ) { } - - public static getFromProduct(): Endpoint | undefined { - const logUploaderUrl = product.logUploaderUrl; - return logUploaderUrl ? new Endpoint(logUploaderUrl) : undefined; - } -} - -export async function uploadLogs( - launchService: ILaunchService, - requestService: IRequestService, - environmentService: IEnvironmentService -): Promise { - const endpoint = Endpoint.getFromProduct(); - if (!endpoint) { - console.error(localize('invalidEndpoint', 'Invalid log uploader endpoint')); - return; - } - - const logsPath = await launchService.getLogsPath(); - - if (await promptUserToConfirmLogUpload(logsPath, environmentService)) { - console.log(localize('beginUploading', 'Uploading...')); - const outZip = await zipLogs(logsPath); - const result = await postLogs(endpoint, outZip, requestService); - console.log(localize('didUploadLogs', 'Upload successful! Log file ID: {0}', result.blob_id)); - } -} - -function promptUserToConfirmLogUpload( - logsPath: string, - environmentService: IEnvironmentService -): boolean { - const confirmKey = 'iConfirmLogsUpload'; - if ((environmentService.args['upload-logs'] || '').toLowerCase() === confirmKey.toLowerCase()) { - return true; - } else { - const message = localize('logUploadPromptHeader', 'You are about to upload your session logs to a secure Microsoft endpoint that only Microsoft\'s members of the VS Code team can access.') - + '\n\n' + localize('logUploadPromptBody', 'Session logs may contain personal information such as full paths or file contents. Please review and redact your session log files here: \'{0}\'', logsPath) - + '\n\n' + localize('logUploadPromptBodyDetails', 'By continuing you confirm that you have reviewed and redacted your session log files and that you agree to Microsoft using them to debug VS Code.') - + '\n\n' + localize('logUploadPromptAcceptInstructions', 'Please run code with \'--upload-logs={0}\' to proceed with upload', confirmKey); - console.log(message); - return false; - } -} - -async function postLogs( - endpoint: Endpoint, - outZip: string, - requestService: IRequestService -): Promise { - const dotter = setInterval(() => console.log('.'), 5000); - let result: IRequestContext; - try { - result = await requestService.request({ - url: endpoint.url, - type: 'POST', - data: Buffer.from(fs.readFileSync(outZip)).toString('base64'), - headers: { - 'Content-Type': 'application/zip' - } - }, CancellationToken.None); - } catch (e) { - clearInterval(dotter); - console.log(localize('postError', 'Error posting logs: {0}', e)); - throw e; - } - - return new Promise((resolve, reject) => { - const parts: Buffer[] = []; - result.stream.on('data', data => { - parts.push(data); - }); - - result.stream.on('end', () => { - clearInterval(dotter); - try { - const response = Buffer.concat(parts).toString('utf-8'); - if (result.res.statusCode === 200) { - resolve(JSON.parse(response)); - } else { - const errorMessage = localize('responseError', 'Error posting logs. Got {0} — {1}', result.res.statusCode, response); - console.log(errorMessage); - reject(new Error(errorMessage)); - } - } catch (e) { - console.log(localize('parseError', 'Error parsing response')); - reject(e); - } - }); - }); -} - -function zipLogs( - logsPath: string -): Promise { - const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'vscode-log-upload')); - const outZip = path.join(tempDir, 'logs.zip'); - return new Promise((resolve, reject) => { - doZip(logsPath, outZip, tempDir, (err, stdout, stderr) => { - if (err) { - console.error(localize('zipError', 'Error zipping logs: {0}', err.message)); - reject(err); - } else { - resolve(outZip); - } - }); - }); -} - -function doZip( - logsPath: string, - outZip: string, - tempDir: string, - callback: (error: Error, stdout: string, stderr: string) => void -) { - switch (os.platform()) { - case 'win32': - // Copy directory first to avoid file locking issues - const sub = path.join(tempDir, 'sub'); - return cp.execFile('powershell', ['-Command', - `[System.IO.Directory]::CreateDirectory("${sub}"); Copy-Item -recurse "${logsPath}" "${sub}"; Compress-Archive -Path "${sub}" -DestinationPath "${outZip}"`], - { cwd: logsPath }, - callback); - default: - return cp.execFile('zip', ['-r', outZip, '.'], { cwd: logsPath }, callback); - } -} diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index 76d042d1e..c6301eb4a 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import 'vs/code/code.main'; +import 'vs/platform/update/node/update.config.contribution'; import { app, dialog } from 'electron'; import { assign } from 'vs/base/common/objects'; import * as platform from 'vs/base/common/platform'; @@ -23,348 +23,381 @@ import { ILogService, ConsoleLogMainService, MultiplexLogService, getLogLevel } import { StateService } from 'vs/platform/state/node/stateService'; import { IStateService } from 'vs/platform/state/common/state'; import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment'; -import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; +import { EnvironmentService, xdgRuntimeDir } from 'vs/platform/environment/node/environmentService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ConfigurationService } from 'vs/platform/configuration/node/configurationService'; -import { IRequestService } from 'vs/platform/request/node/request'; +import { IRequestService } from 'vs/platform/request/common/request'; import { RequestService } from 'vs/platform/request/electron-main/requestService'; import * as fs from 'fs'; import { CodeApplication } from 'vs/code/electron-main/app'; import { localize } from 'vs/nls'; import { mnemonicButtonLabel } from 'vs/base/common/labels'; -import { createSpdLogService } from 'vs/platform/log/node/spdlogService'; -import { IDiagnosticsService, DiagnosticsService } from 'vs/platform/diagnostics/electron-main/diagnosticsService'; +import { SpdLogService } from 'vs/platform/log/node/spdlogService'; import { BufferLogService } from 'vs/platform/log/common/bufferLog'; -import { uploadLogs } from 'vs/code/electron-main/logUploader'; import { setUnexpectedErrorHandler } from 'vs/base/common/errors'; +import { IThemeMainService, ThemeMainService } from 'vs/platform/theme/electron-main/themeMainService'; +import { Client } from 'vs/base/parts/ipc/common/ipc.net'; +import { once } from 'vs/base/common/functional'; +import { ISignService } from 'vs/platform/sign/common/sign'; +import { SignService } from 'vs/platform/sign/node/signService'; +import { DiagnosticsService } from 'vs/platform/diagnostics/node/diagnosticsIpc'; class ExpectedError extends Error { readonly isExpected = true; } -function setupIPC(accessor: ServicesAccessor): Promise { - const logService = accessor.get(ILogService); - const environmentService = accessor.get(IEnvironmentService); - const instantiationService = accessor.get(IInstantiationService); +class CodeMain { - function allowSetForegroundWindow(service: LaunchChannelClient): Promise { - let promise: Promise = Promise.resolve(); - if (platform.isWindows) { - promise = service.getMainProcessId() - .then(processId => { - logService.trace('Sending some foreground love to the running instance:', processId); - - try { - const { allowSetForegroundWindow } = require.__$__nodeRequire('windows-foreground-love'); - allowSetForegroundWindow(processId); - } catch (e) { - // noop - } - }); + main(): void { + + // Set the error handler early enough so that we are not getting the + // default electron error dialog popping up + setUnexpectedErrorHandler(err => console.error(err)); + + // Parse arguments + let args: ParsedArgs; + try { + args = parseMainProcessArgv(process.argv); + args = validatePaths(args); + } catch (err) { + console.error(err.message); + app.exit(1); + + return; } - return promise; + // If we are started with --wait create a random temporary file + // and pass it over to the starting instance. We can use this file + // to wait for it to be deleted to monitor that the edited file + // is closed and then exit the waiting process. + // + // Note: we are not doing this if the wait marker has been already + // added as argument. This can happen if Code was started from CLI. + if (args.wait && !args.waitMarkerFilePath) { + const waitMarkerFilePath = createWaitMarkerFile(args.verbose); + if (waitMarkerFilePath) { + addArg(process.argv, '--waitMarkerFilePath', waitMarkerFilePath); + args.waitMarkerFilePath = waitMarkerFilePath; + } + } + + // Launch + this.startup(args); } - function setup(retry: boolean): Promise { - return serve(environmentService.mainIPCHandle).then(server => { + private async startup(args: ParsedArgs): Promise { - // Print --status usage info - if (environmentService.args.status) { - logService.warn('Warning: The --status argument can only be used if Code is already running. Please run it again after Code has started.'); - throw new ExpectedError('Terminating...'); - } + // We need to buffer the spdlog logs until we are sure + // we are the only instance running, otherwise we'll have concurrent + // log file access on Windows (https://github.com/Microsoft/vscode/issues/41218) + const bufferLogService = new BufferLogService(); - // Log uploader usage info - if (typeof environmentService.args['upload-logs'] !== 'undefined') { - logService.warn('Warning: The --upload-logs argument can only be used if Code is already running. Please run it again after Code has started.'); - throw new ExpectedError('Terminating...'); - } + const [instantiationService, instanceEnvironment] = this.createServices(args, bufferLogService); + try { - // dock might be hidden at this case due to a retry - if (platform.isMacintosh) { - app.dock.show(); - } + // Init services + await instantiationService.invokeFunction(async accessor => { + const environmentService = accessor.get(IEnvironmentService); + const configurationService = accessor.get(IConfigurationService); + const stateService = accessor.get(IStateService); - // Set the VSCODE_PID variable here when we are sure we are the first - // instance to startup. Otherwise we would wrongly overwrite the PID - process.env['VSCODE_PID'] = String(process.pid); + try { + await this.initServices(environmentService, configurationService as ConfigurationService, stateService as StateService); + } catch (error) { - return server; - }, err => { + // Show a dialog for errors that can be resolved by the user + this.handleStartupDataDirError(environmentService, error); - // Handle unexpected errors (the only expected error is EADDRINUSE that - // indicates a second instance of Code is running) - if (err.code !== 'EADDRINUSE') { + throw error; + } + }); - // Show a dialog for errors that can be resolved by the user - handleStartupDataDirError(environmentService, err); + // Startup + await instantiationService.invokeFunction(async accessor => { + const environmentService = accessor.get(IEnvironmentService); + const logService = accessor.get(ILogService); + const lifecycleService = accessor.get(ILifecycleService); + const configurationService = accessor.get(IConfigurationService); - // Any other runtime error is just printed to the console - return Promise.reject(err); - } + const mainIpcServer = await this.doStartup(logService, environmentService, lifecycleService, instantiationService, true); - // Since we are the second instance, we do not want to show the dock - if (platform.isMacintosh) { - app.dock.hide(); - } + bufferLogService.logger = new SpdLogService('main', environmentService.logsPath, bufferLogService.getLevel()); + once(lifecycleService.onWillShutdown)(() => (configurationService as ConfigurationService).dispose()); - // there's a running instance, let's connect to it - return connect(environmentService.mainIPCHandle, 'main').then( - client => { + return instantiationService.createInstance(CodeApplication, mainIpcServer, instanceEnvironment).startup(); + }); + } catch (error) { + instantiationService.invokeFunction(this.quit, error); + } + } - // Tests from CLI require to be the only instance currently - if (environmentService.extensionTestsLocationURI && !environmentService.debugExtensionHost.break) { - const msg = 'Running extension tests from the command line is currently only supported if no other instance of Code is running.'; - logService.error(msg); - client.dispose(); + private createServices(args: ParsedArgs, bufferLogService: BufferLogService): [IInstantiationService, typeof process.env] { + const services = new ServiceCollection(); - return Promise.reject(new Error(msg)); - } + const environmentService = new EnvironmentService(args, process.execPath); + const instanceEnvironment = this.patchEnvironment(environmentService); // Patch `process.env` with the instance's environment + services.set(IEnvironmentService, environmentService); - // Show a warning dialog after some timeout if it takes long to talk to the other instance - // Skip this if we are running with --wait where it is expected that we wait for a while. - // Also skip when gathering diagnostics (--status) which can take a longer time. - let startupWarningDialogHandle: NodeJS.Timeout; - if (!environmentService.wait && !environmentService.status && !environmentService.args['upload-logs']) { - startupWarningDialogHandle = setTimeout(() => { - showStartupWarningDialog( - localize('secondInstanceNoResponse', "Another instance of {0} is running but not responding", product.nameShort), - localize('secondInstanceNoResponseDetail', "Please close all other instances and try again.") - ); - }, 10000); - } + const logService = new MultiplexLogService([new ConsoleLogMainService(getLogLevel(environmentService)), bufferLogService]); + process.once('exit', () => logService.dispose()); + services.set(ILogService, logService); - const channel = client.getChannel('launch'); - const service = new LaunchChannelClient(channel); - - // Process Info - if (environmentService.args.status) { - return instantiationService.invokeFunction(accessor => { - return accessor.get(IDiagnosticsService).getDiagnostics(service).then(diagnostics => { - console.log(diagnostics); - return Promise.reject(new ExpectedError()); - }); - }); - } + services.set(IConfigurationService, new ConfigurationService(environmentService.settingsResource)); + services.set(ILifecycleService, new SyncDescriptor(LifecycleService)); + services.set(IStateService, new SyncDescriptor(StateService)); + services.set(IRequestService, new SyncDescriptor(RequestService)); + services.set(IThemeMainService, new SyncDescriptor(ThemeMainService)); + services.set(ISignService, new SyncDescriptor(SignService)); - // Log uploader - if (typeof environmentService.args['upload-logs'] !== 'undefined') { - return instantiationService.invokeFunction(accessor => { - return uploadLogs(service, accessor.get(IRequestService), environmentService) - .then(() => Promise.reject(new ExpectedError())); - }); - } + return [new InstantiationService(services, true), instanceEnvironment]; + } - logService.trace('Sending env to running instance...'); - - return allowSetForegroundWindow(service) - .then(() => service.start(environmentService.args, process.env as platform.IProcessEnvironment)) - .then(() => client.dispose()) - .then(() => { - - // Now that we started, make sure the warning dialog is prevented - if (startupWarningDialogHandle) { - clearTimeout(startupWarningDialogHandle); - } - - return Promise.reject(new ExpectedError('Sent env to running instance. Terminating...')); - }); - }, - err => { - if (!retry || platform.isWindows || err.code !== 'ECONNREFUSED') { - if (err.code === 'EPERM') { - showStartupWarningDialog( - localize('secondInstanceAdmin', "A second instance of {0} is already running as administrator.", product.nameShort), - localize('secondInstanceAdminDetail', "Please close the other instance and try again.") - ); - } - - return Promise.reject(err); - } + private initServices(environmentService: IEnvironmentService, configurationService: ConfigurationService, stateService: StateService): Promise { - // 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 then retry the whole thing - try { - fs.unlinkSync(environmentService.mainIPCHandle); - } catch (e) { - logService.warn('Could not delete obsolete instance handle', e); - return Promise.reject(e); - } + // Environment service (paths) + const environmentServiceInitialization = Promise.all([ + environmentService.extensionsPath, + environmentService.nodeCachedDataDir, + environmentService.logsPath, + environmentService.globalStorageHome, + environmentService.workspaceStorageHome, + environmentService.backupHome.fsPath + ].map((path): undefined | Promise => path ? mkdirp(path) : undefined)); - return setup(false); - } - ); - }); + // Configuration service + const configurationServiceInitialization = configurationService.initialize(); + + // State service + const stateServiceInitialization = stateService.init(); + + return Promise.all([environmentServiceInitialization, configurationServiceInitialization, stateServiceInitialization]); } - return setup(true); -} + private patchEnvironment(environmentService: IEnvironmentService): typeof process.env { + const instanceEnvironment: typeof process.env = { + VSCODE_IPC_HOOK: environmentService.mainIPCHandle, + VSCODE_NLS_CONFIG: process.env['VSCODE_NLS_CONFIG'], + VSCODE_LOGS: process.env['VSCODE_LOGS'] + }; -function showStartupWarningDialog(message: string, detail: string): void { - dialog.showMessageBox({ - title: product.nameLong, - type: 'warning', - buttons: [mnemonicButtonLabel(localize({ key: 'close', comment: ['&& denotes a mnemonic'] }, "&&Close"))], - message, - detail, - noLink: true - }); -} + if (process.env['VSCODE_PORTABLE']) { + instanceEnvironment['VSCODE_PORTABLE'] = process.env['VSCODE_PORTABLE']; + } + + assign(process.env, instanceEnvironment); -function handleStartupDataDirError(environmentService: IEnvironmentService, error: NodeJS.ErrnoException): void { - if (error.code === 'EACCES' || error.code === 'EPERM') { - showStartupWarningDialog( - localize('startupDataDirError', "Unable to write program user data."), - localize('startupDataDirErrorDetail', "Please make sure the directories {0} and {1} are writeable.", environmentService.userDataPath, environmentService.extensionsPath) - ); + return instanceEnvironment; } -} -function quit(accessor: ServicesAccessor, reason?: ExpectedError | Error): void { - const logService = accessor.get(ILogService); - const lifecycleService = accessor.get(ILifecycleService); + private async doStartup(logService: ILogService, environmentService: IEnvironmentService, lifecycleService: ILifecycleService, instantiationService: IInstantiationService, retry: boolean): Promise { + + // Try to setup a server for running. If that succeeds it means + // we are the first instance to startup. Otherwise it is likely + // that another instance is already running. + let server: Server; + try { + server = await serve(environmentService.mainIPCHandle); + once(lifecycleService.onWillShutdown)(() => server.dispose()); + } catch (error) { + + // Handle unexpected errors (the only expected error is EADDRINUSE that + // indicates a second instance of Code is running) + if (error.code !== 'EADDRINUSE') { - let exitCode = 0; + // Show a dialog for errors that can be resolved by the user + this.handleStartupDataDirError(environmentService, error); - if (reason) { - if ((reason as ExpectedError).isExpected) { - if (reason.message) { - logService.trace(reason.message); + // Any other runtime error is just printed to the console + throw error; } - } else { - exitCode = 1; // signal error to the outside - if (reason.stack) { - logService.error(reason.stack); - } else { - logService.error(`Startup error: ${reason.toString()}`); + // Since we are the second instance, we do not want to show the dock + if (platform.isMacintosh) { + app.dock.hide(); } - } - } - lifecycleService.kill(exitCode); -} + // there's a running instance, let's connect to it + let client: Client; + try { + client = await connect(environmentService.mainIPCHandle, 'main'); + } catch (error) { + + // Handle unexpected connection errors by showing a dialog to the user + if (!retry || platform.isWindows || error.code !== 'ECONNREFUSED') { + if (error.code === 'EPERM') { + this.showStartupWarningDialog( + localize('secondInstanceAdmin', "A second instance of {0} is already running as administrator.", product.nameShort), + localize('secondInstanceAdminDetail', "Please close the other instance and try again.") + ); + } -function patchEnvironment(environmentService: IEnvironmentService): typeof process.env { - const instanceEnvironment: typeof process.env = { - VSCODE_IPC_HOOK: environmentService.mainIPCHandle, - VSCODE_NLS_CONFIG: process.env['VSCODE_NLS_CONFIG'], - VSCODE_LOGS: process.env['VSCODE_LOGS'] - }; + throw error; + } - if (process.env['VSCODE_PORTABLE']) { - instanceEnvironment['VSCODE_PORTABLE'] = process.env['VSCODE_PORTABLE']; - } + // 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 then + // retry the whole thing + try { + fs.unlinkSync(environmentService.mainIPCHandle); + } catch (error) { + logService.warn('Could not delete obsolete instance handle', error); + + throw error; + } - assign(process.env, instanceEnvironment); + return this.doStartup(logService, environmentService, lifecycleService, instantiationService, false); + } - return instanceEnvironment; -} + // Tests from CLI require to be the only instance currently + if (environmentService.extensionTestsLocationURI && !environmentService.debugExtensionHost.break) { + const msg = 'Running extension tests from the command line is currently only supported if no other instance of Code is running.'; + logService.error(msg); + client.dispose(); -function startup(args: ParsedArgs): void { + throw new Error(msg); + } - // We need to buffer the spdlog logs until we are sure - // we are the only instance running, otherwise we'll have concurrent - // log file access on Windows (https://github.com/Microsoft/vscode/issues/41218) - const bufferLogService = new BufferLogService(); + // Show a warning dialog after some timeout if it takes long to talk to the other instance + // Skip this if we are running with --wait where it is expected that we wait for a while. + // Also skip when gathering diagnostics (--status) which can take a longer time. + let startupWarningDialogHandle: NodeJS.Timeout | undefined = undefined; + if (!environmentService.wait && !environmentService.status) { + startupWarningDialogHandle = setTimeout(() => { + this.showStartupWarningDialog( + localize('secondInstanceNoResponse', "Another instance of {0} is running but not responding", product.nameShort), + localize('secondInstanceNoResponseDetail', "Please close all other instances and try again.") + ); + }, 10000); + } - const instantiationService = createServices(args, bufferLogService); - instantiationService.invokeFunction(accessor => { - const environmentService = accessor.get(IEnvironmentService); - const stateService = accessor.get(IStateService); + const channel = client.getChannel('launch'); + const launchClient = new LaunchChannelClient(channel); - // Patch `process.env` with the instance's environment - const instanceEnvironment = patchEnvironment(environmentService); + // Process Info + if (environmentService.args.status) { + return instantiationService.invokeFunction(async accessor => { + // Create a diagnostic service connected to the existing shared process + const sharedProcessClient = await connect(environmentService.sharedIPCHandle, 'main'); + const diagnosticsChannel = sharedProcessClient.getChannel('diagnostics'); + const diagnosticsService = new DiagnosticsService(diagnosticsChannel); + const mainProcessInfo = await launchClient.getMainProcessInfo(); + const remoteDiagnostics = await launchClient.getRemoteDiagnostics({ includeProcesses: true, includeWorkspaceMetadata: true }); + const diagnostics = await diagnosticsService.getDiagnostics(mainProcessInfo, remoteDiagnostics); + console.log(diagnostics); + + throw new ExpectedError(); + }); + } - // Startup - return initServices(environmentService, stateService as StateService) - .then(() => instantiationService.invokeFunction(setupIPC), error => { + // Windows: allow to set foreground + if (platform.isWindows) { + await this.windowsAllowSetForegroundWindow(launchClient, logService); + } - // Show a dialog for errors that can be resolved by the user - handleStartupDataDirError(environmentService, error); + // Send environment over... + logService.trace('Sending env to running instance...'); + await launchClient.start(environmentService.args, process.env as platform.IProcessEnvironment); - return Promise.reject(error); - }) - .then(mainIpcServer => { - bufferLogService.logger = createSpdLogService('main', bufferLogService.getLevel(), environmentService.logsPath); + // Cleanup + await client.dispose(); - return instantiationService.createInstance(CodeApplication, mainIpcServer, instanceEnvironment).startup(); - }); - }).then(null, err => instantiationService.invokeFunction(quit, err)); -} + // Now that we started, make sure the warning dialog is prevented + if (startupWarningDialogHandle) { + clearTimeout(startupWarningDialogHandle); + } -function createServices(args: ParsedArgs, bufferLogService: BufferLogService): IInstantiationService { - const services = new ServiceCollection(); + throw new ExpectedError('Sent env to running instance. Terminating...'); + } - const environmentService = new EnvironmentService(args, process.execPath); + // Print --status usage info + if (environmentService.args.status) { + logService.warn('Warning: The --status argument can only be used if Code is already running. Please run it again after Code has started.'); - const logService = new MultiplexLogService([new ConsoleLogMainService(getLogLevel(environmentService)), bufferLogService]); - process.once('exit', () => logService.dispose()); + throw new ExpectedError('Terminating...'); + } - services.set(IEnvironmentService, environmentService); - services.set(ILogService, logService); - services.set(ILifecycleService, new SyncDescriptor(LifecycleService)); - services.set(IStateService, new SyncDescriptor(StateService)); - services.set(IConfigurationService, new SyncDescriptor(ConfigurationService, [environmentService.appSettingsPath])); - services.set(IRequestService, new SyncDescriptor(RequestService)); - services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService)); + // dock might be hidden at this case due to a retry + if (platform.isMacintosh) { + app.dock.show(); + } - return new InstantiationService(services, true); -} + // Set the VSCODE_PID variable here when we are sure we are the first + // instance to startup. Otherwise we would wrongly overwrite the PID + process.env['VSCODE_PID'] = String(process.pid); -function initServices(environmentService: IEnvironmentService, stateService: StateService): Promise { + return server; + } - // Ensure paths for environment service exist - const environmentServiceInitialization = Promise.all([ - environmentService.extensionsPath, - environmentService.nodeCachedDataDir, - environmentService.logsPath, - environmentService.globalStorageHome, - environmentService.workspaceStorageHome, - environmentService.backupHome - ].map((path): undefined | Promise => path ? mkdirp(path) : undefined)); + private handleStartupDataDirError(environmentService: IEnvironmentService, error: NodeJS.ErrnoException): void { + if (error.code === 'EACCES' || error.code === 'EPERM') { + const directories = [environmentService.userDataPath]; - // State service - const stateServiceInitialization = stateService.init(); + if (environmentService.extensionsPath) { + directories.push(environmentService.extensionsPath); + } - return Promise.all([environmentServiceInitialization, stateServiceInitialization]); -} + if (xdgRuntimeDir) { + directories.push(xdgRuntimeDir); + } + + this.showStartupWarningDialog( + localize('startupDataDirError', "Unable to write program user data."), + localize('startupUserDataAndExtensionsDirErrorDetail', "Please make sure the following directories are writeable:\n\n{0}", directories.join('\n')) + ); + } + } -function main(): void { + private showStartupWarningDialog(message: string, detail: string): void { + dialog.showMessageBox({ + title: product.nameLong, + type: 'warning', + buttons: [mnemonicButtonLabel(localize({ key: 'close', comment: ['&& denotes a mnemonic'] }, "&&Close"))], + message, + detail, + noLink: true + }); + } - // Set the error handler early enough so that we are not getting the - // default electron error dialog popping up - setUnexpectedErrorHandler(err => console.error(err)); + private async windowsAllowSetForegroundWindow(client: LaunchChannelClient, logService: ILogService): Promise { + if (platform.isWindows) { + const processId = await client.getMainProcessId(); - // Parse arguments - let args: ParsedArgs; - try { - args = parseMainProcessArgv(process.argv); - args = validatePaths(args); - } catch (err) { - console.error(err.message); - app.exit(1); + logService.trace('Sending some foreground love to the running instance:', processId); - return undefined; + try { + (await import('windows-foreground-love')).allowSetForegroundWindow(processId); + } catch (error) { + logService.error(error); + } + } } - // If we are started with --wait create a random temporary file - // and pass it over to the starting instance. We can use this file - // to wait for it to be deleted to monitor that the edited file - // is closed and then exit the waiting process. - // - // Note: we are not doing this if the wait marker has been already - // added as argument. This can happen if Code was started from CLI. - if (args.wait && !args.waitMarkerFilePath) { - const waitMarkerFilePath = createWaitMarkerFile(args.verbose); - if (waitMarkerFilePath) { - addArg(process.argv, '--waitMarkerFilePath', waitMarkerFilePath); - args.waitMarkerFilePath = waitMarkerFilePath; + private quit(accessor: ServicesAccessor, reason?: ExpectedError | Error): void { + const logService = accessor.get(ILogService); + const lifecycleService = accessor.get(ILifecycleService); + + let exitCode = 0; + + if (reason) { + if ((reason as ExpectedError).isExpected) { + if (reason.message) { + logService.trace(reason.message); + } + } else { + exitCode = 1; // signal error to the outside + + if (reason.stack) { + logService.error(reason.stack); + } else { + logService.error(`Startup error: ${reason.toString()}`); + } + } } + + lifecycleService.kill(exitCode); } - startup(args); } -main(); +// Main Startup +const code = new CodeMain(); +code.main(); diff --git a/src/vs/code/electron-main/sharedProcess.ts b/src/vs/code/electron-main/sharedProcess.ts index 441277600..60926b0d1 100644 --- a/src/vs/code/electron-main/sharedProcess.ts +++ b/src/vs/code/electron-main/sharedProcess.ts @@ -11,9 +11,8 @@ import { ISharedProcess } from 'vs/platform/windows/electron-main/windows'; import { Barrier } from 'vs/base/common/async'; import { ILogService } from 'vs/platform/log/common/log'; import { ILifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; -import { IStateService } from 'vs/platform/state/common/state'; -import { getBackgroundColor } from 'vs/code/electron-main/theme'; -import { dispose, toDisposable, IDisposable } from 'vs/base/common/lifecycle'; +import { IThemeMainService } from 'vs/platform/theme/electron-main/themeMainService'; +import { toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; export class SharedProcess implements ISharedProcess { @@ -26,19 +25,20 @@ export class SharedProcess implements ISharedProcess { private userEnv: NodeJS.ProcessEnv, @IEnvironmentService private readonly environmentService: IEnvironmentService, @ILifecycleService private readonly lifecycleService: ILifecycleService, - @IStateService private readonly stateService: IStateService, - @ILogService private readonly logService: ILogService + @ILogService private readonly logService: ILogService, + @IThemeMainService private readonly themeMainService: IThemeMainService ) { } @memoize private get _whenReady(): Promise { this.window = new BrowserWindow({ show: false, - backgroundColor: getBackgroundColor(this.stateService), + backgroundColor: this.themeMainService.getBackgroundColor(), webPreferences: { images: false, webaudio: false, webgl: false, + nodeIntegration: true, disableBlinkFeatures: 'Auxclick' // do NOT change, allows us to identify this window as shared-process in the process explorer } }); @@ -67,10 +67,10 @@ export class SharedProcess implements ISharedProcess { this.window.on('close', onClose); - const disposables: IDisposable[] = []; + const disposables = new DisposableStore(); this.lifecycleService.onWillShutdown(() => { - dispose(disposables); + disposables.dispose(); // Shut the shared process down when we are quitting // @@ -104,7 +104,7 @@ export class SharedProcess implements ISharedProcess { logLevel: this.logService.getLevel() }); - disposables.push(toDisposable(() => sender.send('handshake:goodbye'))); + disposables.add(toDisposable(() => sender.send('handshake:goodbye'))); ipcMain.once('handshake:im ready', () => c(undefined)); }); }); diff --git a/src/vs/code/electron-main/theme.ts b/src/vs/code/electron-main/theme.ts deleted file mode 100644 index 5518c3840..000000000 --- a/src/vs/code/electron-main/theme.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 { isWindows, isMacintosh } from 'vs/base/common/platform'; -import { systemPreferences } from 'electron'; -import { IStateService } from 'vs/platform/state/common/state'; - -const DEFAULT_BG_LIGHT = '#FFFFFF'; -const DEFAULT_BG_DARK = '#1E1E1E'; -const DEFAULT_BG_HC_BLACK = '#000000'; - -const THEME_STORAGE_KEY = 'theme'; -const THEME_BG_STORAGE_KEY = 'themeBackground'; - -export function storeBackgroundColor(stateService: IStateService, data: { baseTheme: string, background: string }): void { - stateService.setItem(THEME_STORAGE_KEY, data.baseTheme); - stateService.setItem(THEME_BG_STORAGE_KEY, data.background); -} - -export function getBackgroundColor(stateService: IStateService): string { - if (isWindows && systemPreferences.isInvertedColorScheme()) { - return DEFAULT_BG_HC_BLACK; - } - - let background = stateService.getItem(THEME_BG_STORAGE_KEY, null); - if (!background) { - let baseTheme: string; - if (isWindows && systemPreferences.isInvertedColorScheme()) { - baseTheme = 'hc-black'; - } else { - baseTheme = stateService.getItem(THEME_STORAGE_KEY, 'vs-dark').split(' ')[0]; - } - - background = (baseTheme === 'hc-black') ? DEFAULT_BG_HC_BLACK : (baseTheme === 'vs' ? DEFAULT_BG_LIGHT : DEFAULT_BG_DARK); - } - - if (isMacintosh && background.toUpperCase() === DEFAULT_BG_DARK) { - background = '#171717'; // https://github.com/electron/electron/issues/5150 - } - - return background; -} \ No newline at end of file diff --git a/src/vs/code/electron-main/window.ts b/src/vs/code/electron-main/window.ts index fdfb2dcbc..48055ea90 100644 --- a/src/vs/code/electron-main/window.ts +++ b/src/vs/code/electron-main/window.ts @@ -7,14 +7,13 @@ import * as path from 'vs/base/common/path'; import * as objects from 'vs/base/common/objects'; import * as nls from 'vs/nls'; import { URI } from 'vs/base/common/uri'; -import { IStateService } from 'vs/platform/state/common/state'; -import { screen, BrowserWindow, systemPreferences, app, TouchBar, nativeImage } from 'electron'; +import { screen, BrowserWindow, systemPreferences, app, TouchBar, nativeImage, Rectangle, Display } from 'electron'; import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment'; import { ILogService } from 'vs/platform/log/common/log'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { parseArgs } from 'vs/platform/environment/node/argv'; import product from 'vs/platform/product/node/product'; -import { IWindowSettings, MenuBarVisibility, IWindowConfiguration, ReadyState, IRunActionInWindowRequest, getTitleBarStyle } from 'vs/platform/windows/common/windows'; +import { IWindowSettings, MenuBarVisibility, IWindowConfiguration, ReadyState, getTitleBarStyle } from 'vs/platform/windows/common/windows'; import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; import { isLinux, isMacintosh, isWindows } from 'vs/base/common/platform'; import { ICodeWindow, IWindowState, WindowMode } from 'vs/platform/windows/electron-main/windows'; @@ -22,11 +21,14 @@ import { IWorkspaceIdentifier, IWorkspacesMainService } from 'vs/platform/worksp import { IBackupMainService } from 'vs/platform/backup/common/backup'; import { ISerializableCommandAction } from 'vs/platform/actions/common/actions'; import * as perf from 'vs/base/common/performance'; -import { resolveMarketplaceHeaders } from 'vs/platform/extensionManagement/node/extensionGalleryService'; -import { getBackgroundColor } from 'vs/code/electron-main/theme'; -import { RunOnceScheduler } from 'vs/base/common/async'; -import { withNullAsUndefined } from 'vs/base/common/types'; +import { resolveMarketplaceHeaders } from 'vs/platform/extensionManagement/common/extensionGalleryService'; +import { IThemeMainService } from 'vs/platform/theme/electron-main/themeMainService'; import { endsWith } from 'vs/base/common/strings'; +import { RunOnceScheduler } from 'vs/base/common/async'; +import { IFileService } from 'vs/platform/files/common/files'; +import pkg from 'vs/platform/product/node/package'; + +const RUN_TEXTMATE_IN_WORKER = false; export interface IWindowCreationOptions { state: IWindowState; @@ -42,14 +44,6 @@ export const defaultWindowState = function (mode = WindowMode.Normal): IWindowSt }; }; -interface IWorkbenchEditorConfiguration { - workbench: { - editor: { - swipeToNavigate: boolean - } - }; -} - interface ITouchBarSegment extends Electron.SegmentedControlSegment { id: string; } @@ -80,14 +74,13 @@ export class CodeWindow extends Disposable implements ICodeWindow { private readonly touchBarGroups: Electron.TouchBarSegmentedControl[]; - private nodeless: boolean; - constructor( config: IWindowCreationOptions, @ILogService private readonly logService: ILogService, @IEnvironmentService private readonly environmentService: IEnvironmentService, + @IFileService private readonly fileService: IFileService, @IConfigurationService private readonly configurationService: IConfigurationService, - @IStateService private readonly stateService: IStateService, + @IThemeMainService private readonly themeMainService: IThemeMainService, @IWorkspacesMainService private readonly workspacesMainService: IWorkspacesMainService, @IBackupMainService private readonly backupMainService: IBackupMainService, ) { @@ -98,8 +91,6 @@ export class CodeWindow extends Disposable implements ICodeWindow { this._readyState = ReadyState.NONE; this.whenReadyCallbacks = []; - this.nodeless = !!(environmentService.args.nodeless && !environmentService.isBuilt); - // create browser window this.createBrowserWindow(config); @@ -119,7 +110,8 @@ export class CodeWindow extends Disposable implements ICodeWindow { private createBrowserWindow(config: IWindowCreationOptions): void { // Load window state - this.windowState = this.restoreWindowState(config.state); + const [state, hasMultipleDisplays] = this.restoreWindowState(config.state); + this.windowState = state; // in case we are maximized or fullscreen, only show later after the call to maximize/fullscreen (see below) const isFullscreenOrMaximized = (this.windowState.mode === WindowMode.Maximized || this.windowState.mode === WindowMode.Fullscreen); @@ -129,7 +121,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { height: this.windowState.height, x: this.windowState.x, y: this.windowState.y, - backgroundColor: this.nodeless ? undefined : getBackgroundColor(this.stateService), + backgroundColor: this.themeMainService.getBackgroundColor(), minWidth: CodeWindow.MIN_WIDTH, minHeight: CodeWindow.MIN_HEIGHT, show: !isFullscreenOrMaximized, @@ -139,14 +131,13 @@ export class CodeWindow extends Disposable implements ICodeWindow { // want to enforce that Code stays in the foreground. This triggers a disable_hidden_ // flag that Electron provides via patch: // https://github.com/electron/libchromiumcontent/blob/master/patches/common/chromium/disable_hidden.patch - backgroundThrottling: false + backgroundThrottling: false, + nodeIntegration: true, + nodeIntegrationInWorker: RUN_TEXTMATE_IN_WORKER, + webviewTag: true } }; - if (this.nodeless) { - options.webPreferences!.nodeIntegration = false; // simulate Electron 5 behaviour - } - if (isLinux) { options.icon = path.join(this.environmentService.appRoot, 'resources/linux/code.png'); // Windows and Mac are better off using the embedded icon(s) } @@ -165,7 +156,8 @@ export class CodeWindow extends Disposable implements ICodeWindow { } } - if (isMacintosh && windowConfig && windowConfig.nativeTabs === true) { + const useNativeTabs = isMacintosh && windowConfig && windowConfig.nativeTabs === true; + if (useNativeTabs) { options.tabbingIdentifier = product.nameShort; // this opts in to sierra tabs } @@ -186,6 +178,24 @@ export class CodeWindow extends Disposable implements ICodeWindow { this._win.setSheetOffset(22); // offset dialogs by the height of the custom title bar if we have any } + // TODO@Ben (Electron 4 regression): when running on multiple displays where the target display + // to open the window has a larger resolution than the primary display, the window will not size + // correctly unless we set the bounds again (https://github.com/microsoft/vscode/issues/74872) + // + // However, when running with native tabs with multiple windows we cannot use this workaround + // because there is a potential that the new window will be added as native tab instead of being + // a window on its own. In that case calling setBounds() would cause https://github.com/microsoft/vscode/issues/75830 + if (isMacintosh && hasMultipleDisplays && (!useNativeTabs || BrowserWindow.getAllWindows().length === 1)) { + if ([this.windowState.width, this.windowState.height, this.windowState.x, this.windowState.y].every(value => typeof value === 'number')) { + this._win.setBounds({ + width: this.windowState.width!, + height: this.windowState.height!, + x: this.windowState.x!, + y: this.windowState.y! + }); + } + } + if (isFullscreenOrMaximized) { this._win.maximize(); @@ -198,10 +208,6 @@ export class CodeWindow extends Disposable implements ICodeWindow { } } - if (this.nodeless) { - this._win.webContents.toggleDevTools(); - } - this._lastFocusTime = Date.now(); // since we show directly, we need to set the last focus time too } @@ -217,12 +223,6 @@ export class CodeWindow extends Disposable implements ICodeWindow { return !!this.config.extensionTestsPath; } - /* - get extensionDevelopmentPaths(): string | string[] | undefined { - return this.config.extensionDevelopmentPath; - } - */ - get config(): IWindowConfiguration { return this.currentConfig; } @@ -310,13 +310,13 @@ export class CodeWindow extends Disposable implements ICodeWindow { private handleMarketplaceRequests(): void { // Resolve marketplace headers - this.marketplaceHeadersPromise = resolveMarketplaceHeaders(this.environmentService); + this.marketplaceHeadersPromise = resolveMarketplaceHeaders(pkg.version, this.environmentService, this.fileService); // Inject headers when requests are incoming const urls = ['https://marketplace.visualstudio.com/*', 'https://*.vsassets.io/*']; this._win.webContents.session.webRequest.onBeforeSendHeaders({ urls }, (details, cb) => { this.marketplaceHeadersPromise.then(headers => { - const requestHeaders = objects.assign(details.requestHeaders, headers); + const requestHeaders = objects.assign(details.requestHeaders, headers) as { [key: string]: string | undefined }; if (!this.configurationService.getValue('extensions.disableExperimentalAzureSearch')) { requestHeaders['Cookie'] = `${requestHeaders['Cookie'] ? requestHeaders['Cookie'] + ';' : ''}EnableExternalSearchForVSCode=true`; } @@ -340,12 +340,14 @@ export class CodeWindow extends Disposable implements ICodeWindow { }); this._win.webContents.session.webRequest.onHeadersReceived(null!, (details, callback) => { - const contentType: string[] = (details.responseHeaders['content-type'] || details.responseHeaders['Content-Type']); + const responseHeaders = details.responseHeaders as { [key: string]: string[] }; + + const contentType: string[] = (responseHeaders['content-type'] || responseHeaders['Content-Type']); if (contentType && Array.isArray(contentType) && contentType.some(x => x.toLowerCase().indexOf('image/svg') >= 0)) { return callback({ cancel: true }); } - return callback({ cancel: false, responseHeaders: details.responseHeaders }); + return callback({ cancel: false, responseHeaders }); }); // Remember that we loaded @@ -371,9 +373,6 @@ export class CodeWindow extends Disposable implements ICodeWindow { } }); - // App commands support - this.registerNavigationListenerOn('app-command', 'browser-backward', 'browser-forward', false); - // Window Focus this._win.on('focus', () => { this._lastFocusTime = Date.now(); @@ -459,30 +458,6 @@ export class CodeWindow extends Disposable implements ICodeWindow { this.currentMenuBarVisibility = newMenuBarVisibility; this.setMenuBarVisibility(newMenuBarVisibility); } - - // Swipe command support (macOS) - if (isMacintosh) { - const config = this.configurationService.getValue(); - if (config && config.workbench && config.workbench.editor && config.workbench.editor.swipeToNavigate) { - this.registerNavigationListenerOn('swipe', 'left', 'right', true); - } else { - this._win.removeAllListeners('swipe'); - } - } - } - - private registerNavigationListenerOn(command: 'swipe' | 'app-command', back: 'left' | 'browser-backward', forward: 'right' | 'browser-forward', acrossEditors: boolean) { - this._win.on(command as 'swipe' /* | 'app-command' */, (e: Electron.Event, cmd: string) => { - if (!this.isReady) { - return; // window must be ready - } - - if (cmd === back) { - this.send('vscode:runAction', { id: acrossEditors ? 'workbench.action.openPreviousRecentlyUsedEditor' : 'workbench.action.navigateBack', from: 'mouse' } as IRunActionInWindowRequest); - } else if (cmd === forward) { - this.send('vscode:runAction', { id: acrossEditors ? 'workbench.action.openNextRecentlyUsedEditor' : 'workbench.action.navigateForward', from: 'mouse' } as IRunActionInWindowRequest); - } - }); } addTabbedWindow(window: ICodeWindow): void { @@ -612,9 +587,10 @@ export class CodeWindow extends Disposable implements ICodeWindow { // Config (combination of process.argv and window configuration) const environment = parseArgs(process.argv); const config = objects.assign(environment, windowConfiguration); - for (let key in config) { - if (config[key] === undefined || config[key] === null || config[key] === '' || config[key] === false) { - delete config[key]; // only send over properties that have a true value + for (const key in config) { + const configValue = (config as any)[key]; + if (configValue === undefined || configValue === null || configValue === '' || configValue === false) { + delete (config as any)[key]; // only send over properties that have a true value } } @@ -637,10 +613,6 @@ export class CodeWindow extends Disposable implements ICodeWindow { } private doGetUrl(config: object): string { - if (this.nodeless) { - return `${require.toUrl('vs/code/electron-browser/workbench/workbench.nodeless.html')}?config=${encodeURIComponent(JSON.stringify(config))}`; - } - return `${require.toUrl('vs/code/electron-browser/workbench/workbench.html')}?config=${encodeURIComponent(JSON.stringify(config))}`; } @@ -692,7 +664,12 @@ export class CodeWindow extends Disposable implements ICodeWindow { // only consider non-minimized window states if (mode === WindowMode.Normal || mode === WindowMode.Maximized) { - const bounds = this.getBounds(); + let bounds: Electron.Rectangle; + if (mode === WindowMode.Normal) { + bounds = this.getBounds(); + } else { + bounds = this._win.getNormalBounds(); // make sure to persist the normal bounds when maximized to be able to restore them + } state.x = bounds.x; state.y = bounds.y; @@ -703,76 +680,64 @@ export class CodeWindow extends Disposable implements ICodeWindow { return state; } - private restoreWindowState(state?: IWindowState): IWindowState { + private restoreWindowState(state?: IWindowState): [IWindowState, boolean? /* has multiple displays */] { + let hasMultipleDisplays = false; if (state) { try { - state = withNullAsUndefined(this.validateWindowState(state)); + const displays = screen.getAllDisplays(); + hasMultipleDisplays = displays.length > 1; + + state = this.validateWindowState(state, displays); } catch (err) { this.logService.warn(`Unexpected error validating window state: ${err}\n${err.stack}`); // somehow display API can be picky about the state to validate } } - if (!state) { - state = defaultWindowState(); - } - - return state; + return [state || defaultWindowState(), hasMultipleDisplays]; } - private validateWindowState(state: IWindowState): IWindowState | null { - if (!state) { - return null; - } - + private validateWindowState(state: IWindowState, displays: Display[]): IWindowState | undefined { if (typeof state.x !== 'number' || typeof state.y !== 'number' || typeof state.width !== 'number' || typeof state.height !== 'number' ) { - return null; + return undefined; } if (state.width <= 0 || state.height <= 0) { - return null; + return undefined; } - const displays = screen.getAllDisplays(); - // Single Monitor: be strict about x/y positioning if (displays.length === 1) { - const displayBounds = displays[0].bounds; - - // Careful with maximized: in that mode x/y can well be negative! - if (state.mode !== WindowMode.Maximized && displayBounds.width > 0 && displayBounds.height > 0 /* Linux X11 sessions sometimes report wrong display bounds */) { - if (state.x < displayBounds.x) { - state.x = displayBounds.x; // prevent window from falling out of the screen to the left + const displayWorkingArea = this.getWorkingArea(displays[0]); + if (displayWorkingArea) { + if (state.x < displayWorkingArea.x) { + state.x = displayWorkingArea.x; // prevent window from falling out of the screen to the left } - if (state.y < displayBounds.y) { - state.y = displayBounds.y; // prevent window from falling out of the screen to the top + if (state.y < displayWorkingArea.y) { + state.y = displayWorkingArea.y; // prevent window from falling out of the screen to the top } - if (state.x > (displayBounds.x + displayBounds.width)) { - state.x = displayBounds.x; // prevent window from falling out of the screen to the right + if (state.x > (displayWorkingArea.x + displayWorkingArea.width)) { + state.x = displayWorkingArea.x; // prevent window from falling out of the screen to the right } - if (state.y > (displayBounds.y + displayBounds.height)) { - state.y = displayBounds.y; // prevent window from falling out of the screen to the bottom + if (state.y > (displayWorkingArea.y + displayWorkingArea.height)) { + state.y = displayWorkingArea.y; // prevent window from falling out of the screen to the bottom } - if (state.width > displayBounds.width) { - state.width = displayBounds.width; // prevent window from exceeding display bounds width + if (state.width > displayWorkingArea.width) { + state.width = displayWorkingArea.width; // prevent window from exceeding display bounds width } - if (state.height > displayBounds.height) { - state.height = displayBounds.height; // prevent window from exceeding display bounds height + if (state.height > displayWorkingArea.height) { + state.height = displayWorkingArea.height; // prevent window from exceeding display bounds height } } - if (state.mode === WindowMode.Maximized) { - return defaultWindowState(WindowMode.Maximized); // when maximized, make sure we have good values when the user restores the window - } - return state; } @@ -791,25 +756,37 @@ export class CodeWindow extends Disposable 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); + const displayWorkingArea = this.getWorkingArea(display); 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 + display && // we have a display matching the desired bounds + displayWorkingArea && // we have valid working area bounds + bounds.x < displayWorkingArea.x + displayWorkingArea.width && // prevent window from falling out of the screen to the right + bounds.y < displayWorkingArea.y + displayWorkingArea.height && // prevent window from falling out of the screen to the bottom + bounds.x + bounds.width > displayWorkingArea.x && // prevent window from falling out of the screen to the left + bounds.y + bounds.height > displayWorkingArea.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 - defaults.y = state.y; + return state; + } - return defaults; - } + return undefined; + } - return state; + private getWorkingArea(display: Display): Rectangle | undefined { + + // Prefer the working area of the display to account for taskbars on the + // desktop being positioned somewhere (https://github.com/Microsoft/vscode/issues/50830). + // + // Linux X11 sessions sometimes report wrong display bounds, so we validate + // the reported sizes are positive. + if (display.workArea.width > 0 && display.workArea.height > 0) { + return display.workArea; + } + + if (display.bounds.width > 0 && display.bounds.height > 0) { + return display.bounds; } - return null; + return undefined; } getBounds(): Electron.Rectangle { @@ -861,16 +838,17 @@ export class CodeWindow extends Disposable implements ICodeWindow { } private useNativeFullScreen(): boolean { - const windowConfig = this.configurationService.getValue('window'); - if (!windowConfig || typeof windowConfig.nativeFullScreen !== 'boolean') { - return true; // default - } + return true; // TODO@ben enable simple fullscreen again (https://github.com/microsoft/vscode/issues/75054) + // const windowConfig = this.configurationService.getValue('window'); + // if (!windowConfig || typeof windowConfig.nativeFullScreen !== 'boolean') { + // return true; // default + // } - if (windowConfig.nativeTabs) { - return true; // https://github.com/electron/electron/issues/16142 - } + // if (windowConfig.nativeTabs) { + // return true; // https://github.com/electron/electron/issues/16142 + // } - return windowConfig.nativeFullScreen !== false; + // return windowConfig.nativeFullScreen !== false; } isMinimized(): boolean { diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index 26db33a6d..5e50acec4 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -15,7 +15,7 @@ import { CodeWindow, defaultWindowState } from 'vs/code/electron-main/window'; import { hasArgs, asArray } from 'vs/platform/environment/node/argv'; import { ipcMain as ipc, screen, BrowserWindow, dialog, systemPreferences, FileFilter } from 'electron'; import { parseLineAndColumnAware } from 'vs/code/node/paths'; -import { ILifecycleService, UnloadReason, LifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; +import { ILifecycleService, UnloadReason, LifecycleService, LifecycleMainPhase } 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, IPathsToWaitFor, IEnterWorkspaceResult, IMessageBoxResult, INewWindowOptions, IURIToOpen, isFileToOpen, isWorkspaceToOpen, isFolderToOpen } from 'vs/platform/windows/common/windows'; @@ -38,6 +38,8 @@ import { getComparisonKey, isEqual, normalizePath, basename as resourcesBasename import { getRemoteAuthority } from 'vs/platform/remote/common/remoteHosts'; import { restoreWindowsState, WindowsStateStorageData, getWindowsStateStoreData } from 'vs/code/electron-main/windowsStateStorage'; import { getWorkspaceIdentifier } from 'vs/platform/workspaces/electron-main/workspacesMainService'; +import { once } from 'vs/base/common/functional'; +import { Disposable } from 'vs/base/common/lifecycle'; const enum WindowError { UNRESPONSIVE = 1, @@ -153,15 +155,13 @@ interface IWorkspacePathToOpen { label?: string; } -export class WindowsManager implements IWindowsMainService { +export class WindowsManager extends Disposable implements IWindowsMainService { _serviceBrand: any; private static readonly windowsStateStorageKey = 'windowsState'; - private static WINDOWS: ICodeWindow[] = []; - - private initialUserEnv: IProcessEnvironment; + private static readonly WINDOWS: ICodeWindow[] = []; private readonly windowsState: IWindowsState; private lastClosedWindowState?: IWindowState; @@ -169,20 +169,21 @@ export class WindowsManager implements IWindowsMainService { private readonly dialogs: Dialogs; private readonly workspacesManager: WorkspacesManager; - private _onWindowReady = new Emitter(); - onWindowReady: CommonEvent = this._onWindowReady.event; + private readonly _onWindowReady = this._register(new Emitter()); + readonly onWindowReady: CommonEvent = this._onWindowReady.event; - private _onWindowClose = new Emitter(); - onWindowClose: CommonEvent = this._onWindowClose.event; + private readonly _onWindowClose = this._register(new Emitter()); + readonly onWindowClose: CommonEvent = this._onWindowClose.event; - private _onWindowLoad = new Emitter(); - onWindowLoad: CommonEvent = this._onWindowLoad.event; + private readonly _onWindowLoad = this._register(new Emitter()); + readonly onWindowLoad: CommonEvent = this._onWindowLoad.event; - private _onWindowsCountChanged = new Emitter(); - onWindowsCountChanged: CommonEvent = this._onWindowsCountChanged.event; + private readonly _onWindowsCountChanged = this._register(new Emitter()); + readonly onWindowsCountChanged: CommonEvent = this._onWindowsCountChanged.event; constructor( private readonly machineId: string, + private readonly initialUserEnv: IProcessEnvironment, @ILogService private readonly logService: ILogService, @IStateService private readonly stateService: IStateService, @IEnvironmentService private readonly environmentService: IEnvironmentService, @@ -194,6 +195,7 @@ export class WindowsManager implements IWindowsMainService { @IWorkspacesMainService private readonly workspacesMainService: IWorkspacesMainService, @IInstantiationService private readonly instantiationService: IInstantiationService ) { + super(); const windowsStateStoreData = this.stateService.getItem(WindowsManager.windowsStateStorageKey); this.windowsState = restoreWindowsState(windowsStateStoreData); @@ -203,12 +205,21 @@ export class WindowsManager implements IWindowsMainService { this.dialogs = new Dialogs(stateService, this); this.workspacesManager = new WorkspacesManager(workspacesMainService, backupMainService, this); - } - ready(initialUserEnv: IProcessEnvironment): void { - this.initialUserEnv = initialUserEnv; + this.lifecycleService.when(LifecycleMainPhase.Ready).then(() => this.registerListeners()); + this.lifecycleService.when(LifecycleMainPhase.AfterWindowOpen).then(() => this.installWindowsMutex()); + } - this.registerListeners(); + private installWindowsMutex(): void { + if (isWindows) { + try { + const WindowsMutex = (require.__$__nodeRequire('windows-mutex') as typeof import('windows-mutex')).Mutex; + const mutex = new WindowsMutex(product.win32MutexName); + once(this.lifecycleService.onWillShutdown)(() => mutex.release()); + } catch (e) { + this.logService.error(e); + } + } } private registerListeners(): void { @@ -543,6 +554,7 @@ export class WindowsManager implements IWindowsMainService { // Find suitable window or folder path to open files in const fileToCheck = fileInputs.filesToOpenOrCreate[0] || fileInputs.filesToDiff[0]; + // only look at the windows with correct authority const windows = WindowsManager.WINDOWS.filter(w => w.remoteAuthority === fileInputs!.remoteAuthority); @@ -639,7 +651,6 @@ export class WindowsManager implements IWindowsMainService { // Handle folders to open (instructed and to restore) const allFoldersToOpen = arrays.distinct(foldersToOpen, folder => getComparisonKey(folder.folderUri)); // prevent duplicates - if (allFoldersToOpen.length > 0) { // Check for existing instances @@ -713,7 +724,9 @@ export class WindowsManager implements IWindowsMainService { if (fileInputs && !emptyToOpen) { emptyToOpen++; } + const remoteAuthority = fileInputs ? fileInputs.remoteAuthority : (openConfig.cli && openConfig.cli.remote || undefined); + for (let i = 0; i < emptyToOpen; i++) { usedWindows.push(this.openInBrowserWindow({ userEnv: openConfig.userEnv, @@ -831,8 +844,7 @@ export class WindowsManager implements IWindowsMainService { private doExtractPathsFromAPI(openConfig: IOpenConfiguration): IPathToOpen[] { const pathsToOpen: IPathToOpen[] = []; - const cli = openConfig.cli; - const parseOptions: IPathParseOptions = { gotoLineMode: cli && cli.goto }; + const parseOptions: IPathParseOptions = { gotoLineMode: openConfig.gotoLineMode }; for (const pathToOpen of openConfig.urisToOpen || []) { if (!pathToOpen) { continue; @@ -1289,7 +1301,7 @@ export class WindowsManager implements IWindowsMainService { // For all other cases we first call into registerEmptyWindowBackupSync() to set it before // loading the window. if (options.emptyWindowBackupInfo) { - configuration.backupPath = join(this.environmentService.backupHome, options.emptyWindowBackupInfo.backupFolder); + configuration.backupPath = join(this.environmentService.backupHome.fsPath, options.emptyWindowBackupInfo.backupFolder); } let window: ICodeWindow | undefined; @@ -1536,14 +1548,13 @@ export class WindowsManager implements IWindowsMainService { return state; } - reload(win: ICodeWindow, cli?: ParsedArgs): void { + async reload(win: ICodeWindow, cli?: ParsedArgs): Promise { // Only reload when the window has not vetoed this - this.lifecycleService.unload(win, UnloadReason.RELOAD).then(veto => { - if (!veto) { - win.reload(undefined, cli); - } - }); + const veto = await this.lifecycleService.unload(win, UnloadReason.RELOAD); + if (!veto) { + win.reload(undefined, cli); + } } closeWorkspace(win: ICodeWindow): void { @@ -1554,8 +1565,10 @@ export class WindowsManager implements IWindowsMainService { }); } - enterWorkspace(win: ICodeWindow, path: URI): Promise { - return this.workspacesManager.enterWorkspace(win, path).then(result => result ? this.doEnterWorkspace(win, result) : undefined); + async enterWorkspace(win: ICodeWindow, path: URI): Promise { + const result = await this.workspacesManager.enterWorkspace(win, path); + + return result ? this.doEnterWorkspace(win, result) : undefined; } private doEnterWorkspace(win: ICodeWindow, result: IEnterWorkspaceResult): IEnterWorkspaceResult { @@ -1666,14 +1679,13 @@ export class WindowsManager implements IWindowsMainService { private onWindowError(window: ICodeWindow, error: WindowError): void { this.logService.error(error === WindowError.CRASHED ? '[VS Code]: render process crashed!' : '[VS Code]: detected unresponsive'); - - /* __GDPR__ - "windowerror" : { - "type" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true } - } - */ - this.telemetryService.publicLog('windowerror', { type: error }); - + type WindowErrorClassification = { + type: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; + }; + type WindowErrorEvent = { + type: WindowError; + }; + this.telemetryService.publicLog2('windowerror', { type: error }); // Unresponsive if (error === WindowError.UNRESPONSIVE) { if (window.isExtensionDevelopmentHost || window.isExtensionTestHost || (window.win && window.win.webContents && window.win.webContents.isDevToolsOpened())) { @@ -1751,8 +1763,10 @@ export class WindowsManager implements IWindowsMainService { const paths = await this.dialogs.pick({ ...options, pickFolders: true, pickFiles: true, title }); if (paths) { this.sendPickerTelemetry(paths, options.telemetryEventName || 'openFileFolder', options.telemetryExtraData); - const urisToOpen = await Promise.all(paths.map(path => { - return dirExists(path).then(isDir => isDir ? { folderUri: URI.file(path) } : { fileUri: URI.file(path) }); + const urisToOpen = await Promise.all(paths.map(async path => { + const isDir = await dirExists(path); + + return isDir ? { folderUri: URI.file(path) } : { fileUri: URI.file(path) }; })); this.open({ context: OpenContext.DIALOG, @@ -1880,7 +1894,7 @@ class Dialogs { this.noWindowDialogQueue = new Queue(); } - pick(options: IInternalNativeOpenDialogOptions): Promise { + async pick(options: IInternalNativeOpenDialogOptions): Promise { // Ensure dialog options const dialogOptions: Electron.OpenDialogOptions = { @@ -1913,16 +1927,16 @@ class Dialogs { // Show Dialog const focusedWindow = (typeof options.windowId === 'number' ? this.windowsMainService.getWindowById(options.windowId) : undefined) || this.windowsMainService.getFocusedWindow(); - return this.showOpenDialog(dialogOptions, focusedWindow).then(paths => { - if (paths && paths.length > 0) { + const paths = await this.showOpenDialog(dialogOptions, focusedWindow); + if (paths && paths.length > 0) { - // Remember path in storage for next time - this.stateService.setItem(Dialogs.workingDirPickerStorageKey, dirname(paths[0])); - return paths; - } + // Remember path in storage for next time + this.stateService.setItem(Dialogs.workingDirPickerStorageKey, dirname(paths[0])); - return undefined; - }); + return paths; + } + + return; } private getDialogQueue(window?: ICodeWindow): Queue { @@ -2028,28 +2042,26 @@ class WorkspacesManager { private readonly windowsMainService: IWindowsMainService, ) { } - enterWorkspace(window: ICodeWindow, path: URI): Promise { + async enterWorkspace(window: ICodeWindow, path: URI): Promise { if (!window || !window.win || !window.isReady) { - return Promise.resolve(null); // return early if the window is not ready or disposed + return null; // return early if the window is not ready or disposed } - return this.isValidTargetWorkspacePath(window, path).then(isValid => { - if (!isValid) { - return null; // return early if the workspace is not valid - } - const workspaceIdentifier = getWorkspaceIdentifier(path); - return this.doOpenWorkspace(window, workspaceIdentifier); - }); + const isValid = await this.isValidTargetWorkspacePath(window, path); + if (!isValid) { + return null; // return early if the workspace is not valid + } + return this.doOpenWorkspace(window, getWorkspaceIdentifier(path)); } - private isValidTargetWorkspacePath(window: ICodeWindow, path?: URI): Promise { + private async isValidTargetWorkspacePath(window: ICodeWindow, path?: URI): Promise { if (!path) { - return Promise.resolve(true); + return true; } if (window.openedWorkspace && isEqual(window.openedWorkspace.configPath, path)) { - return Promise.resolve(false); // window is already opened on a workspace with that path + return false; // window is already opened on a workspace with that path } // Prevent overwriting a workspace that is currently opened in another window @@ -2063,10 +2075,12 @@ class WorkspacesManager { noLink: true }; - return this.windowsMainService.showMessageBox(options, this.windowsMainService.getFocusedWindow()).then(() => false); + await this.windowsMainService.showMessageBox(options, this.windowsMainService.getFocusedWindow()); + + return false; } - return Promise.resolve(true); // OK + return true; // OK } private doOpenWorkspace(window: ICodeWindow, workspace: IWorkspaceIdentifier): IEnterWorkspaceResult { @@ -2090,14 +2104,16 @@ class WorkspacesManager { return { workspace, backupPath }; } - } -function resourceFromURIToOpen(u: IURIToOpen) { +function resourceFromURIToOpen(u: IURIToOpen): URI { if (isWorkspaceToOpen(u)) { return u.workspaceUri; - } else if (isFolderToOpen(u)) { + } + + if (isFolderToOpen(u)) { return u.folderUri; } + return u.fileUri; } \ No newline at end of file diff --git a/src/vs/code/node/cli.ts b/src/vs/code/node/cli.ts index 7b8222c7c..afa7acafa 100644 --- a/src/vs/code/node/cli.ts +++ b/src/vs/code/node/cli.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { spawn, ChildProcess } from 'child_process'; +import { spawn, ChildProcess, SpawnOptions } from 'child_process'; import { assign } from 'vs/base/common/objects'; import { buildHelpMessage, buildVersionMessage, addArg, createWaitMarkerFile } from 'vs/platform/environment/node/argv'; import { parseCLIProcessArgv } from 'vs/platform/environment/node/argvHelper'; @@ -19,13 +19,15 @@ import { resolveTerminalEncoding } from 'vs/base/node/encoding'; import * as iconv from 'iconv-lite'; import { isWindows } from 'vs/base/common/platform'; import { ProfilingSession, Target } from 'v8-inspect-profiler'; +import { isString } from 'vs/base/common/types'; function shouldSpawnCliProcess(argv: ParsedArgs): boolean { return !!argv['install-source'] || !!argv['list-extensions'] || !!argv['install-extension'] || !!argv['uninstall-extension'] - || !!argv['locate-extension']; + || !!argv['locate-extension'] + || !!argv['telemetry']; } interface IMainCli { @@ -57,6 +59,7 @@ export async function main(argv: string[]): Promise { else if (shouldSpawnCliProcess(args)) { const cli = await new Promise((c, e) => require(['vs/code/node/cliProcessMain'], c, e)); await cli.main(args); + return; } @@ -124,7 +127,7 @@ export async function main(argv: string[]): Promise { const processCallbacks: ((child: ChildProcess) => Promise)[] = []; - const verbose = args.verbose || args.status || typeof args['upload-logs'] !== 'undefined'; + const verbose = args.verbose || args.status; if (verbose) { env['ELECTRON_ENABLE_LOGGING'] = '1'; @@ -257,7 +260,7 @@ export async function main(argv: string[]): Promise { addArg(argv, `--prof-startup-prefix`, filenamePrefix); addArg(argv, `--no-cached-data`); - fs.writeFileSync(filenamePrefix, argv.slice(-6).join('|')); + writeFileSync(filenamePrefix, argv.slice(-6).join('|')); processCallbacks.push(async _child => { @@ -329,7 +332,7 @@ export async function main(argv: string[]): Promise { await extHost.stop(); // re-create the marker file to signal that profiling is done - fs.writeFileSync(filenamePrefix, ''); + writeFileSync(filenamePrefix, ''); } catch (e) { console.error('Failed to profile startup. Make sure to quit Code first.'); @@ -337,21 +340,20 @@ export async function main(argv: string[]): Promise { }); } - if (args['js-flags']) { - const match = /max_old_space_size=(\d+)/g.exec(args['js-flags']); + const jsFlags = args['js-flags']; + if (isString(jsFlags)) { + const match = /max_old_space_size=(\d+)/g.exec(jsFlags); if (match && !args['max-memory']) { addArg(argv, `--max-memory=${match[1]}`); } } - const options = { + const options: SpawnOptions = { detached: true, env }; - if (typeof args['upload-logs'] !== 'undefined') { - options['stdio'] = ['pipe', 'pipe', 'pipe']; - } else if (!verbose) { + if (!verbose) { options['stdio'] = 'ignore'; } diff --git a/src/vs/code/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts index 0e496be8a..d9ed94ff6 100644 --- a/src/vs/code/node/cliProcessMain.ts +++ b/src/vs/code/node/cliProcessMain.ts @@ -7,7 +7,7 @@ import { localize } from 'vs/nls'; import product from 'vs/platform/product/node/product'; import pkg from 'vs/platform/product/node/package'; import * as path from 'vs/base/common/path'; -import * as semver from 'semver'; +import * as semver from 'semver-umd'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; @@ -17,12 +17,12 @@ import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/ import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; import { IExtensionManagementService, IExtensionGalleryService, IGalleryExtension, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; -import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; +import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { combinedAppender, NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; import { TelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService'; import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProperties'; -import { IRequestService } from 'vs/platform/request/node/request'; +import { IRequestService } from 'vs/platform/request/common/request'; import { RequestService } from 'vs/platform/request/node/requestService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ConfigurationService } from 'vs/platform/configuration/node/configurationService'; @@ -31,21 +31,27 @@ import { mkdirp, writeFile } from 'vs/base/node/pfs'; import { getBaseLabel } from 'vs/base/common/labels'; import { IStateService } from 'vs/platform/state/common/state'; import { StateService } from 'vs/platform/state/node/stateService'; -import { createSpdLogService } from 'vs/platform/log/node/spdlogService'; import { ILogService, getLogLevel } from 'vs/platform/log/common/log'; import { isPromiseCanceledError } from 'vs/base/common/errors'; import { areSameExtensions, adoptToGalleryExtensionId, getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { URI } from 'vs/base/common/uri'; import { getManifest } from 'vs/platform/extensionManagement/node/extensionManagementUtil'; import { IExtensionManifest, ExtensionType, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions'; -import { isUIExtension } from 'vs/platform/extensions/node/extensionsUtil'; import { CancellationToken } from 'vs/base/common/cancellation'; import { LocalizationsService } from 'vs/platform/localizations/node/localizations'; import { Schemas } from 'vs/base/common/network'; +import { SpdLogService } from 'vs/platform/log/node/spdlogService'; +import { buildTelemetryMessage } from 'vs/platform/telemetry/node/telemetry'; +import { FileService } from 'vs/platform/files/common/fileService'; +import { IFileService } from 'vs/platform/files/common/files'; +import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; +import { DisposableStore } from 'vs/base/common/lifecycle'; +import { IProductService } from 'vs/platform/product/common/product'; +import { ProductService } from 'vs/platform/product/node/productService'; const notFound = (id: string) => localize('notFound', "Extension '{0}' not found.", id); const notInstalled = (id: string) => localize('notInstalled', "Extension '{0}' is not installed.", id); -const useId = localize('useId', "Make sure you use the full extension ID, including the publisher, eg: {0}", 'ms-vscode.csharp'); +const useId = localize('useId', "Make sure you use the full extension ID, including the publisher, e.g.: {0}", 'ms-vscode.csharp'); function getId(manifest: IExtensionManifest, withVersion?: boolean): string { if (withVersion) { @@ -69,10 +75,8 @@ export function getIdAndVersion(id: string): [string, string | undefined] { export class Main { constructor( - private readonly remote: boolean, @IInstantiationService private readonly instantiationService: IInstantiationService, @IEnvironmentService private readonly environmentService: IEnvironmentService, - @IConfigurationService private readonly configurationService: IConfigurationService, @IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService, @IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService ) { } @@ -82,12 +86,12 @@ export class Main { await this.setInstallSource(argv['install-source']); } else if (argv['list-extensions']) { - await this.listExtensions(!!argv['show-versions']); + await this.listExtensions(!!argv['show-versions'], argv['category']); } else if (argv['install-extension']) { const arg = argv['install-extension']; const args: string[] = typeof arg === 'string' ? [arg] : arg; - await this.installExtensions(args, argv['force']); + await this.installExtensions(args, !!argv['force']); } else if (argv['uninstall-extension']) { const arg = argv['uninstall-extension']; @@ -97,6 +101,8 @@ export class Main { const arg = argv['locate-extension']; const ids: string[] = typeof arg === 'string' ? [arg] : arg; await this.locateExtension(ids); + } else if (argv['telemetry']) { + console.log(buildTelemetryMessage(this.environmentService.appRoot, this.environmentService.extensionsPath ? this.environmentService.extensionsPath : undefined)); } } @@ -104,14 +110,39 @@ export class Main { return writeFile(this.environmentService.installSourcePath, installSource.slice(0, 30)); } - private async listExtensions(showVersions: boolean): Promise { - const extensions = await this.extensionManagementService.getInstalled(ExtensionType.User); + private async listExtensions(showVersions: boolean, category?: string): Promise { + let extensions = await this.extensionManagementService.getInstalled(ExtensionType.User); + // TODO: we should save this array in a common place so that the command and extensionQuery can use it that way changing it is easier + const categories = ['"programming languages"', 'snippets', 'linters', 'themes', 'debuggers', 'formatters', 'keymaps', '"scm providers"', 'other', '"extension packs"', '"language packs"']; + if (category && category !== '') { + if (categories.indexOf(category.toLowerCase()) < 0) { + console.log('Invalid category please enter a valid category. To list valid categories run --category without a category specified'); + return; + } + extensions = extensions.filter(e => { + if (e.manifest.categories) { + const lowerCaseCategories: string[] = e.manifest.categories.map(c => c.toLowerCase()); + return lowerCaseCategories.indexOf(category.toLowerCase()) > -1; + } + return false; + }); + } else if (category === '') { + console.log('Possible Categories: '); + categories.forEach(category => { + console.log(category); + }); + return; + } extensions.forEach(e => console.log(getId(e.manifest, showVersions))); } private async installExtensions(extensions: string[], force: boolean): Promise { const failed: string[] = []; const installedExtensionsManifests: IExtensionManifest[] = []; + if (extensions.length) { + console.log(localize('installingExtensions', "Installing extensions...")); + } + for (const extension of extensions) { try { const manifest = await this.installExtension(extension, force); @@ -134,19 +165,15 @@ export class Main { extension = path.isAbsolute(extension) ? extension : path.join(process.cwd(), extension); const manifest = await getManifest(extension); - if (this.remote && (!isLanguagePackExtension(manifest) && isUIExtension(manifest, [], this.configurationService))) { - console.log(localize('notSupportedUIExtension', "Can't install extension {0} since UI Extensions are not supported", getBaseLabel(extension))); - return null; - } const valid = await this.validate(manifest, force); if (valid) { return this.extensionManagementService.install(URI.file(extension)).then(id => { - console.log(localize('successVsixInstall', "Extension '{0}' was successfully installed!", getBaseLabel(extension))); + console.log(localize('successVsixInstall', "Extension '{0}' was successfully installed.", getBaseLabel(extension))); return manifest; }, error => { if (isPromiseCanceledError(error)) { - console.log(localize('cancelVsixInstall', "Cancelled installing Extension '{0}'.", getBaseLabel(extension))); + console.log(localize('cancelVsixInstall', "Cancelled installing extension '{0}'.", getBaseLabel(extension))); return null; } else { return Promise.reject(error); @@ -176,11 +203,6 @@ export class Main { } const manifest = await this.extensionGalleryService.getManifest(extension, CancellationToken.None); - if (this.remote && manifest && (!isLanguagePackExtension(manifest) && isUIExtension(manifest, [], this.configurationService))) { - console.log(localize('notSupportedUIExtension', "Can't install extension {0} since UI Extensions are not supported", extension.identifier.id)); - return null; - } - const [installedExtension] = installed.filter(e => areSameExtensions(e.identifier, { id })); if (installedExtension) { if (extension.version === installedExtension.manifest.version) { @@ -191,9 +213,7 @@ export class Main { console.log(localize('forceUpdate', "Extension '{0}' v{1} is already installed, but a newer version {2} is available in the marketplace. Use '--force' option to update to newer version.", id, installedExtension.manifest.version, extension.version)); return Promise.resolve(null); } - console.log(localize('updateMessage', "Updating the Extension '{0}' to the version {1}", id, extension.version)); - } else { - console.log(localize('foundExtension', "Found '{0}' in the marketplace.", id)); + console.log(localize('updateMessage', "Updating the extension '{0}' to the version {1}", id, extension.version)); } await this.installFromGallery(id, extension); return manifest; @@ -210,7 +230,7 @@ export class Main { const newer = installedExtensions.filter(local => areSameExtensions(extensionIdentifier, local.identifier) && semver.gt(local.manifest.version, manifest.version))[0]; if (newer && !force) { - console.log(localize('forceDowngrade', "A newer version of this extension '{0}' v{1} is already installed. Use '--force' option to downgrade to older version.", newer.identifier.id, newer.manifest.version, manifest.version)); + console.log(localize('forceDowngrade', "A newer version of extension '{0}' v{1} is already installed. Use '--force' option to downgrade to older version.", newer.identifier.id, newer.manifest.version, manifest.version)); return false; } @@ -218,14 +238,14 @@ export class Main { } private async installFromGallery(id: string, extension: IGalleryExtension): Promise { - console.log(localize('installing', "Installing...")); + console.log(localize('installing', "Installing extension '{0}' v{1}...", id, extension.version)); try { await this.extensionManagementService.installFromGallery(extension); - console.log(localize('successInstall', "Extension '{0}' v{1} was successfully installed!", id, extension.version)); + console.log(localize('successInstall', "Extension '{0}' v{1} was successfully installed.", id, extension.version)); } catch (error) { if (isPromiseCanceledError(error)) { - console.log(localize('cancelVsixInstall', "Cancelled installing Extension '{0}'.", id)); + console.log(localize('cancelVsixInstall', "Cancelled installing extension '{0}'.", id)); } else { throw error; } @@ -285,59 +305,80 @@ export class Main { const eventPrefix = 'monacoworkbench'; -export function main(argv: ParsedArgs): Promise { +export async function main(argv: ParsedArgs): Promise { const services = new ServiceCollection(); + const disposables = new DisposableStore(); const environmentService = new EnvironmentService(argv, process.execPath); - const logService = createSpdLogService('cli', getLogLevel(environmentService), environmentService.logsPath); + const logService: ILogService = new SpdLogService('cli', environmentService.logsPath, getLogLevel(environmentService)); process.once('exit', () => logService.dispose()); - logService.info('main', argv); + await Promise.all([environmentService.appSettingsHome.fsPath, environmentService.extensionsPath] + .map((path): undefined | Promise => path ? mkdirp(path) : undefined)); + + const configurationService = new ConfigurationService(environmentService.settingsResource); + disposables.add(configurationService); + await configurationService.initialize(); + services.set(IEnvironmentService, environmentService); services.set(ILogService, logService); + services.set(IConfigurationService, configurationService); services.set(IStateService, new SyncDescriptor(StateService)); + services.set(IProductService, new SyncDescriptor(ProductService)); + + // Files + const fileService = new FileService(logService); + disposables.add(fileService); + services.set(IFileService, fileService); + + const diskFileSystemProvider = new DiskFileSystemProvider(logService); + disposables.add(diskFileSystemProvider); + fileService.registerProvider(Schemas.file, diskFileSystemProvider); const instantiationService: IInstantiationService = new InstantiationService(services); - return instantiationService.invokeFunction(accessor => { + return instantiationService.invokeFunction(async accessor => { const envService = accessor.get(IEnvironmentService); const stateService = accessor.get(IStateService); - return Promise.all([envService.appSettingsHome, envService.extensionsPath].map(p => mkdirp(p))).then(() => { - const { appRoot, extensionsPath, extensionDevelopmentLocationURI: extensionDevelopmentLocationURI, isBuilt, installSourcePath } = envService; + const { appRoot, extensionsPath, extensionDevelopmentLocationURI: extensionDevelopmentLocationURI, isBuilt, installSourcePath } = envService; - const services = new ServiceCollection(); - services.set(IConfigurationService, new SyncDescriptor(ConfigurationService, [environmentService.appSettingsPath])); - services.set(IRequestService, new SyncDescriptor(RequestService)); - services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService, [false])); - services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService)); + const services = new ServiceCollection(); - const appenders: AppInsightsAppender[] = []; - if (isBuilt && !extensionDevelopmentLocationURI && !envService.args['disable-telemetry'] && product.enableTelemetry) { - if (product.aiConfig && product.aiConfig.asimovKey) { - appenders.push(new AppInsightsAppender(eventPrefix, null, product.aiConfig.asimovKey, logService)); - } + services.set(IRequestService, new SyncDescriptor(RequestService)); + services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService)); + services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService)); - const config: ITelemetryServiceConfig = { - appender: combinedAppender(...appenders), - commonProperties: resolveCommonProperties(product.commit, pkg.version, stateService.getItem('telemetry.machineId'), installSourcePath), - piiPaths: [appRoot, extensionsPath] - }; + const appenders: AppInsightsAppender[] = []; + if (isBuilt && !extensionDevelopmentLocationURI && !envService.args['disable-telemetry'] && product.enableTelemetry) { - services.set(ITelemetryService, new SyncDescriptor(TelemetryService, [config])); - } else { - services.set(ITelemetryService, NullTelemetryService); + if (product.aiConfig && product.aiConfig.asimovKey) { + appenders.push(new AppInsightsAppender(eventPrefix, null, product.aiConfig.asimovKey, logService)); } - const instantiationService2 = instantiationService.createChild(services); - const main = instantiationService2.createInstance(Main, false); + const config: ITelemetryServiceConfig = { + appender: combinedAppender(...appenders), + commonProperties: resolveCommonProperties(product.commit, pkg.version, stateService.getItem('telemetry.machineId'), installSourcePath), + piiPaths: extensionsPath ? [appRoot, extensionsPath] : [appRoot] + }; - return main.run(argv).then(() => { - // Dispose the AI adapter so that remaining data gets flushed. - return combinedAppender(...appenders).dispose(); - }); - }); + services.set(ITelemetryService, new SyncDescriptor(TelemetryService, [config])); + + } else { + services.set(ITelemetryService, NullTelemetryService); + } + + const instantiationService2 = instantiationService.createChild(services); + const main = instantiationService2.createInstance(Main); + + try { + await main.run(argv); + // Flush the remaining data in AI adapter. + await combinedAppender(...appenders).flush(); + } finally { + disposables.dispose(); + } }); -} \ No newline at end of file +} diff --git a/src/vs/code/node/shellEnv.ts b/src/vs/code/node/shellEnv.ts index 75c486306..fee0648ea 100644 --- a/src/vs/code/node/shellEnv.ts +++ b/src/vs/code/node/shellEnv.ts @@ -7,11 +7,17 @@ import * as cp from 'child_process'; import { assign } from 'vs/base/common/objects'; import { generateUuid } from 'vs/base/common/uuid'; import { isWindows } from 'vs/base/common/platform'; +import { ILogService } from 'vs/platform/log/common/log'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -function getUnixShellEnvironment(): Promise { +function getUnixShellEnvironment(logService: ILogService): Promise { const promise = new Promise((resolve, reject) => { const runAsNode = process.env['ELECTRON_RUN_AS_NODE']; + logService.trace('getUnixShellEnvironment#runAsNode', runAsNode); + const noAttach = process.env['ELECTRON_NO_ATTACH_CONSOLE']; + logService.trace('getUnixShellEnvironment#noAttach', noAttach); + const mark = generateUuid().replace(/-/g, '').substr(0, 12); const regex = new RegExp(mark + '(.*)' + mark); @@ -21,6 +27,9 @@ function getUnixShellEnvironment(): Promise { }); const command = `'${process.execPath}' -p '"${mark}" + JSON.stringify(process.env) + "${mark}"'`; + logService.trace('getUnixShellEnvironment#env', env); + logService.trace('getUnixShellEnvironment#spawn', command); + const child = cp.spawn(process.env.SHELL!, ['-ilc', command], { detached: true, stdio: ['ignore', 'pipe', process.stderr], @@ -37,6 +46,8 @@ function getUnixShellEnvironment(): Promise { } const raw = Buffer.concat(buffers).toString('utf8'); + logService.trace('getUnixShellEnvironment#raw', raw); + const match = regex.exec(raw); const rawStripped = match ? match[1] : '{}'; @@ -58,8 +69,10 @@ function getUnixShellEnvironment(): Promise { // https://github.com/Microsoft/vscode/issues/22593#issuecomment-336050758 delete env['XDG_RUNTIME_DIR']; + logService.trace('getUnixShellEnvironment#result', env); resolve(env); } catch (err) { + logService.error('getUnixShellEnvironment#error', err); reject(err); } }); @@ -77,14 +90,20 @@ let _shellEnv: Promise; * This should only be done when Code itself is not launched * from within a shell. */ -export function getShellEnvironment(): Promise { +export function getShellEnvironment(logService: ILogService, environmentService: IEnvironmentService): Promise { if (_shellEnv === undefined) { - if (isWindows) { + if (environmentService.args['disable-user-env-probe']) { + logService.trace('getShellEnvironment: disable-user-env-probe set, skipping'); + _shellEnv = Promise.resolve({}); + } else if (isWindows) { + logService.trace('getShellEnvironment: running on Windows, skipping'); _shellEnv = Promise.resolve({}); } else if (process.env['VSCODE_CLI'] === '1') { + logService.trace('getShellEnvironment: running on CLI, skipping'); _shellEnv = Promise.resolve({}); } else { - _shellEnv = getUnixShellEnvironment(); + logService.trace('getShellEnvironment: running on Unix'); + _shellEnv = getUnixShellEnvironment(logService); } } diff --git a/src/vs/code/test/electron-main/nativeHelpers.test.ts b/src/vs/code/test/electron-main/nativeHelpers.test.ts new file mode 100644 index 000000000..ff0f589d5 --- /dev/null +++ b/src/vs/code/test/electron-main/nativeHelpers.test.ts @@ -0,0 +1,28 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import { isWindows } from 'vs/base/common/platform'; + +suite('Windows Native Helpers', () => { + test('windows-mutex', async () => { + if (!isWindows) { + return; + } + + const mutex = await import('windows-mutex'); + assert.ok(mutex, 'Unable to load windows-mutex dependency.'); + assert.ok(typeof mutex.isActive === 'function', 'Unable to load windows-mutex dependency.'); + }); + + test('windows-foreground-love', async () => { + if (!isWindows) { + return; + } + + const foregroundLove = await import('windows-foreground-love'); + assert.ok(foregroundLove, 'Unable to load windows-foreground-love dependency.'); + }); +}); \ No newline at end of file diff --git a/src/vs/code/test/node/argv.test.ts b/src/vs/code/test/node/argv.test.ts index 6ce5684fa..6ac49bc99 100644 --- a/src/vs/code/test/node/argv.test.ts +++ b/src/vs/code/test/node/argv.test.ts @@ -4,10 +4,11 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; import { formatOptions, Option, addArg } from 'vs/platform/environment/node/argv'; +import { ParsedArgs } from 'vs/platform/environment/common/environment'; suite('formatOptions', () => { - function o(id: string, description: string): Option { + function o(id: keyof ParsedArgs, description: string): Option { return { id, description, type: 'string' }; @@ -16,30 +17,30 @@ suite('formatOptions', () => { test('Text should display small columns correctly', () => { assert.deepEqual( formatOptions([ - o('foo', 'bar') + o('add', 'bar') ], 80), - [' --foo bar'] + [' --add bar'] ); assert.deepEqual( formatOptions([ - o('f', 'bar'), - o('fo', 'ba'), - o('foo', 'b') + o('add', 'bar'), + o('wait', 'ba'), + o('trace', 'b') ], 80), [ - ' --f bar', - ' --fo ba', - ' --foo b' + ' --add bar', + ' --wait ba', + ' --trace b' ]); }); test('Text should wrap', () => { assert.deepEqual( formatOptions([ - o('foo', ('bar ').repeat(9)) + o('add', ('bar ').repeat(9)) ], 40), [ - ' --foo bar bar bar bar bar bar bar bar', + ' --add bar bar bar bar bar bar bar bar', ' bar' ]); }); @@ -47,10 +48,10 @@ suite('formatOptions', () => { test('Text should revert to the condensed view when the terminal is too narrow', () => { assert.deepEqual( formatOptions([ - o('foo', ('bar ').repeat(9)) + o('add', ('bar ').repeat(9)) ], 30), [ - ' --foo', + ' --add', ' bar bar bar bar bar bar bar bar bar ' ]); }); diff --git a/src/vs/css.build.js b/src/vs/css.build.js index 146ebe332..69c624089 100644 --- a/src/vs/css.build.js +++ b/src/vs/css.build.js @@ -17,7 +17,7 @@ var _cssPluginGlobal = this; var CSSBuildLoaderPlugin; (function (CSSBuildLoaderPlugin) { - var global = _cssPluginGlobal || {}; + var global = (_cssPluginGlobal || {}); /** * Known issue: * - In IE there is no way to know if the CSS file loaded successfully or not. @@ -319,7 +319,7 @@ var CSSBuildLoaderPlugin; global.cssInlinedResources = global.cssInlinedResources || []; var normalizedFSPath = fsPath.replace(/\\/g, '/'); if (global.cssInlinedResources.indexOf(normalizedFSPath) >= 0) { - // console.warn('CSS INLINING IMAGE AT ' + fsPath + ' MORE THAN ONCE. CONSIDER CONSOLIDATING CSS RULES'); + console.warn('CSS INLINING IMAGE AT ' + fsPath + ' MORE THAN ONCE. CONSIDER CONSOLIDATING CSS RULES'); } global.cssInlinedResources.push(normalizedFSPath); var MIME = /\.svg$/.test(url) ? 'image/svg+xml' : 'image/png'; diff --git a/src/vs/editor/browser/config/configuration.ts b/src/vs/editor/browser/config/configuration.ts index f97a692dd..cdb50af8b 100644 --- a/src/vs/editor/browser/config/configuration.ts +++ b/src/vs/editor/browser/config/configuration.ts @@ -14,7 +14,6 @@ import { CommonEditorConfiguration, IEnvConfiguration } from 'vs/editor/common/c import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { BareFontInfo, FontInfo } from 'vs/editor/common/config/fontInfo'; import { IDimension } from 'vs/editor/common/editorCommon'; -import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; class CSSBasedConfigurationCache { @@ -62,28 +61,17 @@ export function readFontInfo(bareFontInfo: BareFontInfo): FontInfo { return CSSBasedConfiguration.INSTANCE.readConfiguration(bareFontInfo); } -export function restoreFontInfo(storageService: IStorageService): void { - const strStoredFontInfo = storageService.get('editorFontInfo', StorageScope.GLOBAL); - if (typeof strStoredFontInfo !== 'string') { - return; - } - let storedFontInfo: ISerializedFontInfo[] | null = null; - try { - storedFontInfo = JSON.parse(strStoredFontInfo); - } catch (err) { - return; - } - if (!Array.isArray(storedFontInfo)) { - return; - } - CSSBasedConfiguration.INSTANCE.restoreFontInfo(storedFontInfo); +export function restoreFontInfo(fontInfo: ISerializedFontInfo[]): void { + CSSBasedConfiguration.INSTANCE.restoreFontInfo(fontInfo); } -export function saveFontInfo(storageService: IStorageService): void { - const knownFontInfo = CSSBasedConfiguration.INSTANCE.saveFontInfo(); - if (knownFontInfo.length > 0) { - storageService.store('editorFontInfo', JSON.stringify(knownFontInfo), StorageScope.GLOBAL); +export function serializeFontInfo(): ISerializedFontInfo[] | null { + const fontInfo = CSSBasedConfiguration.INSTANCE.saveFontInfo(); + if (fontInfo.length > 0) { + return fontInfo; } + + return null; } export interface ISerializedFontInfo { diff --git a/src/vs/editor/browser/controller/coreCommands.ts b/src/vs/editor/browser/controller/coreCommands.ts index f1abe319f..193ff840a 100644 --- a/src/vs/editor/browser/controller/coreCommands.ts +++ b/src/vs/editor/browser/controller/coreCommands.ts @@ -301,13 +301,13 @@ export namespace CoreNavigationCommands { export const MoveTo: CoreEditorCommand = registerEditorCommand(new BaseMoveToCommand({ id: '_moveTo', inSelectionMode: false, - precondition: null + precondition: undefined })); export const MoveToSelect: CoreEditorCommand = registerEditorCommand(new BaseMoveToCommand({ id: '_moveToSelect', inSelectionMode: true, - precondition: null + precondition: undefined })); abstract class ColumnSelectCommand extends CoreEditorCommand { @@ -316,6 +316,9 @@ export namespace CoreNavigationCommands { const result = this._getColumnSelectResult(cursors.context, cursors.getPrimaryCursor(), cursors.getColumnSelectData(), args); cursors.setStates(args.source, CursorChangeReason.Explicit, result.viewStates.map((viewState) => CursorState.fromViewState(viewState))); cursors.setColumnSelectData({ + isReal: true, + fromViewLineNumber: result.fromLineNumber, + fromViewVisualColumn: result.fromVisualColumn, toViewLineNumber: result.toLineNumber, toViewVisualColumn: result.toVisualColumn }); @@ -330,7 +333,7 @@ export namespace CoreNavigationCommands { constructor() { super({ id: 'columnSelect', - precondition: null + precondition: undefined }); } @@ -338,15 +341,15 @@ export namespace CoreNavigationCommands { // validate `args` const validatedPosition = context.model.validatePosition(args.position); + const validatedViewPosition = context.validateViewPosition(new Position(args.viewPosition.lineNumber, args.viewPosition.column), validatedPosition); - let validatedViewPosition: Position; - if (args.viewPosition) { - validatedViewPosition = context.validateViewPosition(new Position(args.viewPosition.lineNumber, args.viewPosition.column), validatedPosition); - } else { - validatedViewPosition = context.convertModelPositionToViewPosition(validatedPosition); + let fromViewLineNumber = prevColumnSelectData.fromViewLineNumber; + let fromViewVisualColumn = prevColumnSelectData.fromViewVisualColumn; + if (!prevColumnSelectData.isReal && args.setAnchorIfNotSet) { + fromViewLineNumber = validatedViewPosition.lineNumber; + fromViewVisualColumn = args.mouseColumn - 1; } - - return ColumnSelection.columnSelect(context.config, context.viewModel, primary.viewState.selection, validatedViewPosition.lineNumber, args.mouseColumn - 1); + return ColumnSelection.columnSelect(context.config, context.viewModel, fromViewLineNumber, fromViewVisualColumn, validatedViewPosition.lineNumber, args.mouseColumn - 1); } }); @@ -354,7 +357,7 @@ export namespace CoreNavigationCommands { constructor() { super({ id: 'cursorColumnSelectLeft', - precondition: null, + precondition: undefined, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -365,7 +368,7 @@ export namespace CoreNavigationCommands { } protected _getColumnSelectResult(context: CursorContext, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: any): IColumnSelectResult { - return ColumnSelection.columnSelectLeft(context.config, context.viewModel, primary.viewState, prevColumnSelectData.toViewLineNumber, prevColumnSelectData.toViewVisualColumn); + return ColumnSelection.columnSelectLeft(context.config, context.viewModel, prevColumnSelectData); } }); @@ -373,7 +376,7 @@ export namespace CoreNavigationCommands { constructor() { super({ id: 'cursorColumnSelectRight', - precondition: null, + precondition: undefined, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -384,7 +387,7 @@ export namespace CoreNavigationCommands { } protected _getColumnSelectResult(context: CursorContext, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: any): IColumnSelectResult { - return ColumnSelection.columnSelectRight(context.config, context.viewModel, primary.viewState, prevColumnSelectData.toViewLineNumber, prevColumnSelectData.toViewVisualColumn); + return ColumnSelection.columnSelectRight(context.config, context.viewModel, prevColumnSelectData); } }); @@ -398,14 +401,14 @@ export namespace CoreNavigationCommands { } protected _getColumnSelectResult(context: CursorContext, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: any): IColumnSelectResult { - return ColumnSelection.columnSelectUp(context.config, context.viewModel, primary.viewState, this._isPaged, prevColumnSelectData.toViewLineNumber, prevColumnSelectData.toViewVisualColumn); + return ColumnSelection.columnSelectUp(context.config, context.viewModel, prevColumnSelectData, this._isPaged); } } export const CursorColumnSelectUp: CoreEditorCommand = registerEditorCommand(new ColumnSelectUpCommand({ isPaged: false, id: 'cursorColumnSelectUp', - precondition: null, + precondition: undefined, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -417,7 +420,7 @@ export namespace CoreNavigationCommands { export const CursorColumnSelectPageUp: CoreEditorCommand = registerEditorCommand(new ColumnSelectUpCommand({ isPaged: true, id: 'cursorColumnSelectPageUp', - precondition: null, + precondition: undefined, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -436,14 +439,14 @@ export namespace CoreNavigationCommands { } protected _getColumnSelectResult(context: CursorContext, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: any): IColumnSelectResult { - return ColumnSelection.columnSelectDown(context.config, context.viewModel, primary.viewState, this._isPaged, prevColumnSelectData.toViewLineNumber, prevColumnSelectData.toViewVisualColumn); + return ColumnSelection.columnSelectDown(context.config, context.viewModel, prevColumnSelectData, this._isPaged); } } export const CursorColumnSelectDown: CoreEditorCommand = registerEditorCommand(new ColumnSelectDownCommand({ isPaged: false, id: 'cursorColumnSelectDown', - precondition: null, + precondition: undefined, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -455,7 +458,7 @@ export namespace CoreNavigationCommands { export const CursorColumnSelectPageDown: CoreEditorCommand = registerEditorCommand(new ColumnSelectDownCommand({ isPaged: true, id: 'cursorColumnSelectPageDown', - precondition: null, + precondition: undefined, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -468,7 +471,7 @@ export namespace CoreNavigationCommands { constructor() { super({ id: 'cursorMove', - precondition: null, + precondition: undefined, description: CursorMove_.description }); } @@ -531,7 +534,7 @@ export namespace CoreNavigationCommands { value: 1 }, id: 'cursorLeft', - precondition: null, + precondition: undefined, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -548,7 +551,7 @@ export namespace CoreNavigationCommands { value: 1 }, id: 'cursorLeftSelect', - precondition: null, + precondition: undefined, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -564,7 +567,7 @@ export namespace CoreNavigationCommands { value: 1 }, id: 'cursorRight', - precondition: null, + precondition: undefined, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -581,7 +584,7 @@ export namespace CoreNavigationCommands { value: 1 }, id: 'cursorRightSelect', - precondition: null, + precondition: undefined, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -597,7 +600,7 @@ export namespace CoreNavigationCommands { value: 1 }, id: 'cursorUp', - precondition: null, + precondition: undefined, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -614,7 +617,7 @@ export namespace CoreNavigationCommands { value: 1 }, id: 'cursorUpSelect', - precondition: null, + precondition: undefined, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -633,7 +636,7 @@ export namespace CoreNavigationCommands { value: Constants.PAGE_SIZE_MARKER }, id: 'cursorPageUp', - precondition: null, + precondition: undefined, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -649,7 +652,7 @@ export namespace CoreNavigationCommands { value: Constants.PAGE_SIZE_MARKER }, id: 'cursorPageUpSelect', - precondition: null, + precondition: undefined, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -665,7 +668,7 @@ export namespace CoreNavigationCommands { value: 1 }, id: 'cursorDown', - precondition: null, + precondition: undefined, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -682,7 +685,7 @@ export namespace CoreNavigationCommands { value: 1 }, id: 'cursorDownSelect', - precondition: null, + precondition: undefined, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -701,7 +704,7 @@ export namespace CoreNavigationCommands { value: Constants.PAGE_SIZE_MARKER }, id: 'cursorPageDown', - precondition: null, + precondition: undefined, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -717,7 +720,7 @@ export namespace CoreNavigationCommands { value: Constants.PAGE_SIZE_MARKER }, id: 'cursorPageDownSelect', - precondition: null, + precondition: undefined, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -729,7 +732,7 @@ export namespace CoreNavigationCommands { constructor() { super({ id: 'createCursor', - precondition: null + precondition: undefined }); } @@ -790,7 +793,7 @@ export namespace CoreNavigationCommands { constructor() { super({ id: '_lastCursorMoveToSelect', - precondition: null + precondition: undefined }); } @@ -835,7 +838,7 @@ export namespace CoreNavigationCommands { export const CursorHome: CoreEditorCommand = registerEditorCommand(new HomeCommand({ inSelectionMode: false, id: 'cursorHome', - precondition: null, + precondition: undefined, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -847,7 +850,7 @@ export namespace CoreNavigationCommands { export const CursorHomeSelect: CoreEditorCommand = registerEditorCommand(new HomeCommand({ inSelectionMode: true, id: 'cursorHomeSelect', - precondition: null, + precondition: undefined, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -860,7 +863,7 @@ export namespace CoreNavigationCommands { constructor() { super({ id: 'cursorLineStart', - precondition: null, + precondition: undefined, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -914,7 +917,7 @@ export namespace CoreNavigationCommands { export const CursorEnd: CoreEditorCommand = registerEditorCommand(new EndCommand({ inSelectionMode: false, id: 'cursorEnd', - precondition: null, + precondition: undefined, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -926,7 +929,7 @@ export namespace CoreNavigationCommands { export const CursorEndSelect: CoreEditorCommand = registerEditorCommand(new EndCommand({ inSelectionMode: true, id: 'cursorEndSelect', - precondition: null, + precondition: undefined, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -939,7 +942,7 @@ export namespace CoreNavigationCommands { constructor() { super({ id: 'cursorLineEnd', - precondition: null, + precondition: undefined, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -994,7 +997,7 @@ export namespace CoreNavigationCommands { export const CursorTop: CoreEditorCommand = registerEditorCommand(new TopCommand({ inSelectionMode: false, id: 'cursorTop', - precondition: null, + precondition: undefined, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -1006,7 +1009,7 @@ export namespace CoreNavigationCommands { export const CursorTopSelect: CoreEditorCommand = registerEditorCommand(new TopCommand({ inSelectionMode: true, id: 'cursorTopSelect', - precondition: null, + precondition: undefined, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -1038,7 +1041,7 @@ export namespace CoreNavigationCommands { export const CursorBottom: CoreEditorCommand = registerEditorCommand(new BottomCommand({ inSelectionMode: false, id: 'cursorBottom', - precondition: null, + precondition: undefined, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -1050,7 +1053,7 @@ export namespace CoreNavigationCommands { export const CursorBottomSelect: CoreEditorCommand = registerEditorCommand(new BottomCommand({ inSelectionMode: true, id: 'cursorBottomSelect', - precondition: null, + precondition: undefined, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -1063,7 +1066,7 @@ export namespace CoreNavigationCommands { constructor() { super({ id: 'editorScroll', - precondition: null, + precondition: undefined, description: EditorScroll_.description }); } @@ -1134,7 +1137,7 @@ export namespace CoreNavigationCommands { constructor() { super({ id: 'scrollLineUp', - precondition: null, + precondition: undefined, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -1159,7 +1162,7 @@ export namespace CoreNavigationCommands { constructor() { super({ id: 'scrollPageUp', - precondition: null, + precondition: undefined, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -1185,7 +1188,7 @@ export namespace CoreNavigationCommands { constructor() { super({ id: 'scrollLineDown', - precondition: null, + precondition: undefined, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -1210,7 +1213,7 @@ export namespace CoreNavigationCommands { constructor() { super({ id: 'scrollPageDown', - precondition: null, + precondition: undefined, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -1257,20 +1260,20 @@ export namespace CoreNavigationCommands { export const WordSelect: CoreEditorCommand = registerEditorCommand(new WordCommand({ inSelectionMode: false, id: '_wordSelect', - precondition: null + precondition: undefined })); export const WordSelectDrag: CoreEditorCommand = registerEditorCommand(new WordCommand({ inSelectionMode: true, id: '_wordSelectDrag', - precondition: null + precondition: undefined })); export const LastCursorWordSelect: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { constructor() { super({ id: 'lastCursorWordSelect', - precondition: null + precondition: undefined }); } @@ -1317,13 +1320,13 @@ export namespace CoreNavigationCommands { export const LineSelect: CoreEditorCommand = registerEditorCommand(new LineCommand({ inSelectionMode: false, id: '_lineSelect', - precondition: null + precondition: undefined })); export const LineSelectDrag: CoreEditorCommand = registerEditorCommand(new LineCommand({ inSelectionMode: true, id: '_lineSelectDrag', - precondition: null + precondition: undefined })); class LastCursorLineCommand extends CoreEditorCommand { @@ -1353,20 +1356,20 @@ export namespace CoreNavigationCommands { export const LastCursorLineSelect: CoreEditorCommand = registerEditorCommand(new LastCursorLineCommand({ inSelectionMode: false, id: 'lastCursorLineSelect', - precondition: null + precondition: undefined })); export const LastCursorLineSelectDrag: CoreEditorCommand = registerEditorCommand(new LastCursorLineCommand({ inSelectionMode: true, id: 'lastCursorLineSelectDrag', - precondition: null + precondition: undefined })); export const ExpandLineSelection: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand { constructor() { super({ id: 'expandLineSelection', - precondition: null, + precondition: undefined, kbOpts: { weight: CORE_WEIGHT, kbExpr: EditorContextKeys.textInputFocus, @@ -1445,7 +1448,7 @@ export namespace CoreNavigationCommands { constructor() { super({ id: 'revealLine', - precondition: null, + precondition: undefined, description: RevealLine_.description }); } @@ -1493,7 +1496,7 @@ export namespace CoreNavigationCommands { constructor() { super({ id: 'selectAll', - precondition: null + precondition: undefined }); } @@ -1513,7 +1516,7 @@ export namespace CoreNavigationCommands { constructor() { super({ id: 'setSelection', - precondition: null + precondition: undefined }); } @@ -1728,7 +1731,7 @@ class EditorHandlerCommand extends Command { constructor(id: string, handlerId: string, description?: ICommandHandlerDescription) { super({ id: id, - precondition: null, + precondition: undefined, description: description }); this._handlerId = handlerId; diff --git a/src/vs/editor/browser/controller/mouseHandler.ts b/src/vs/editor/browser/controller/mouseHandler.ts index 4a2dc7661..06d4b2f53 100644 --- a/src/vs/editor/browser/controller/mouseHandler.ts +++ b/src/vs/editor/browser/controller/mouseHandler.ts @@ -123,7 +123,7 @@ export class MouseHandler extends ViewEventHandler { e.stopPropagation(); } }; - this._register(dom.addDisposableListener(this.viewHelper.viewDomNode, 'mousewheel', onMouseWheel, true)); + this._register(dom.addDisposableListener(this.viewHelper.viewDomNode, browser.isEdgeOrIE ? 'mousewheel' : 'wheel', onMouseWheel, true)); this._context.addEventHandler(this); } diff --git a/src/vs/editor/browser/controller/mouseTarget.ts b/src/vs/editor/browser/controller/mouseTarget.ts index 8d69b3dff..9a37d5120 100644 --- a/src/vs/editor/browser/controller/mouseTarget.ts +++ b/src/vs/editor/browser/controller/mouseTarget.ts @@ -407,7 +407,12 @@ class HitTestRequest extends BareHitTestRequest { } public fulfill(type: MouseTargetType, position: Position | null = null, range: EditorRange | null = null, detail: any = null): MouseTarget { - return new MouseTarget(this.target, type, this.mouseColumn, position, range, detail); + let mouseColumn = this.mouseColumn; + if (position && position.column < this._ctx.model.getLineMaxColumn(position.lineNumber)) { + // Most likely, the line contains foreign decorations... + mouseColumn = position.column; + } + return new MouseTarget(this.target, type, mouseColumn, position, range, detail); } public withTarget(target: Element | null): HitTestRequest { diff --git a/src/vs/editor/browser/controller/pointerHandler.ts b/src/vs/editor/browser/controller/pointerHandler.ts index f744847b4..e4a4a0314 100644 --- a/src/vs/editor/browser/controller/pointerHandler.ts +++ b/src/vs/editor/browser/controller/pointerHandler.ts @@ -5,7 +5,7 @@ import * as dom from 'vs/base/browser/dom'; import { EventType, Gesture, GestureEvent } from 'vs/base/browser/touch'; -import { IDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; import { IPointerHandlerHelper, MouseHandler } from 'vs/editor/browser/controller/mouseHandler'; import { IMouseTarget } from 'vs/editor/browser/editorBrowser'; import { EditorMouseEvent } from 'vs/editor/browser/editorDom'; @@ -195,11 +195,6 @@ class TouchHandler extends MouseHandler { this._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Tap, (e) => this.onTap(e))); this._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Change, (e) => this.onChange(e))); this._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Contextmenu, (e: MouseEvent) => this._onContextMenu(new EditorMouseEvent(e, this.viewHelper.viewDomNode), false))); - - } - - public dispose(): void { - super.dispose(); } private onTap(event: GestureEvent): void { @@ -219,26 +214,23 @@ class TouchHandler extends MouseHandler { } } -export class PointerHandler implements IDisposable { +export class PointerHandler extends Disposable { private readonly handler: MouseHandler; constructor(context: ViewContext, viewController: ViewController, viewHelper: IPointerHandlerHelper) { + super(); if (window.navigator.msPointerEnabled) { - this.handler = new MsPointerHandler(context, viewController, viewHelper); + this.handler = this._register(new MsPointerHandler(context, viewController, viewHelper)); } else if ((window).TouchEvent) { - this.handler = new TouchHandler(context, viewController, viewHelper); + this.handler = this._register(new TouchHandler(context, viewController, viewHelper)); } else if (window.navigator.pointerEnabled || (window).PointerEvent) { - this.handler = new StandardPointerHandler(context, viewController, viewHelper); + this.handler = this._register(new StandardPointerHandler(context, viewController, viewHelper)); } else { - this.handler = new MouseHandler(context, viewController, viewHelper); + this.handler = this._register(new MouseHandler(context, viewController, viewHelper)); } } public getTargetAtClientPoint(clientX: number, clientY: number): IMouseTarget | null { return this.handler.getTargetAtClientPoint(clientX, clientY); } - - public dispose(): void { - this.handler.dispose(); - } } diff --git a/src/vs/editor/browser/core/editorState.ts b/src/vs/editor/browser/core/editorState.ts index e39a282d1..9b244cd77 100644 --- a/src/vs/editor/browser/core/editorState.ts +++ b/src/vs/editor/browser/core/editorState.ts @@ -8,8 +8,9 @@ import { ICodeEditor, IActiveCodeEditor } from 'vs/editor/browser/editorBrowser' import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { ITextModel } from 'vs/editor/common/model'; +import { EditorKeybindingCancellationTokenSource } from 'vs/editor/browser/core/keybindingCancellation'; export const enum CodeEditorStateFlag { Value = 1, @@ -78,30 +79,30 @@ export class EditorState { * A cancellation token source that cancels when the editor changes as expressed * by the provided flags */ -export class EditorStateCancellationTokenSource extends CancellationTokenSource { +export class EditorStateCancellationTokenSource extends EditorKeybindingCancellationTokenSource implements IDisposable { - private readonly _listener: IDisposable[] = []; + private readonly _listener = new DisposableStore(); constructor(readonly editor: IActiveCodeEditor, flags: CodeEditorStateFlag, parent?: CancellationToken) { - super(parent); + super(editor, parent); if (flags & CodeEditorStateFlag.Position) { - this._listener.push(editor.onDidChangeCursorPosition(_ => this.cancel())); + this._listener.add(editor.onDidChangeCursorPosition(_ => this.cancel())); } if (flags & CodeEditorStateFlag.Selection) { - this._listener.push(editor.onDidChangeCursorSelection(_ => this.cancel())); + this._listener.add(editor.onDidChangeCursorSelection(_ => this.cancel())); } if (flags & CodeEditorStateFlag.Scroll) { - this._listener.push(editor.onDidScrollChange(_ => this.cancel())); + this._listener.add(editor.onDidScrollChange(_ => this.cancel())); } if (flags & CodeEditorStateFlag.Value) { - this._listener.push(editor.onDidChangeModel(_ => this.cancel())); - this._listener.push(editor.onDidChangeModelContent(_ => this.cancel())); + this._listener.add(editor.onDidChangeModel(_ => this.cancel())); + this._listener.add(editor.onDidChangeModelContent(_ => this.cancel())); } } dispose() { - dispose(this._listener); + this._listener.dispose(); super.dispose(); } } @@ -109,7 +110,7 @@ export class EditorStateCancellationTokenSource extends CancellationTokenSource /** * A cancellation token source that cancels when the provided model changes */ -export class TextModelCancellationTokenSource extends CancellationTokenSource { +export class TextModelCancellationTokenSource extends CancellationTokenSource implements IDisposable { private _listener: IDisposable; diff --git a/src/vs/editor/browser/core/keybindingCancellation.ts b/src/vs/editor/browser/core/keybindingCancellation.ts new file mode 100644 index 000000000..54ed2852a --- /dev/null +++ b/src/vs/editor/browser/core/keybindingCancellation.ts @@ -0,0 +1,105 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyCode } from 'vs/base/common/keyCodes'; +import { EditorCommand, registerEditorCommand } from 'vs/editor/browser/editorExtensions'; +import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { IContextKeyService, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation'; +import { LinkedList } from 'vs/base/common/linkedList'; +import { createDecorator, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; + + +const IEditorCancellationTokens = createDecorator('IEditorCancelService'); + +interface IEditorCancellationTokens { + _serviceBrand: any; + add(editor: ICodeEditor, cts: CancellationTokenSource): () => void; + cancel(editor: ICodeEditor): void; +} + +const ctxCancellableOperation = new RawContextKey('cancellableOperation', false); + +registerSingleton(IEditorCancellationTokens, class implements IEditorCancellationTokens { + + _serviceBrand: any; + + private readonly _tokens = new WeakMap, tokens: LinkedList }>(); + + add(editor: ICodeEditor, cts: CancellationTokenSource): () => void { + let data = this._tokens.get(editor); + if (!data) { + data = editor.invokeWithinContext(accessor => { + const key = ctxCancellableOperation.bindTo(accessor.get(IContextKeyService)); + const tokens = new LinkedList(); + return { key, tokens }; + }); + this._tokens.set(editor, data); + } + + let removeFn: Function | undefined; + + data.key.set(true); + removeFn = data.tokens.push(cts); + + return () => { + // remove w/o cancellation + if (removeFn) { + removeFn(); + data!.key.set(!data!.tokens.isEmpty()); + removeFn = undefined; + } + }; + } + + cancel(editor: ICodeEditor): void { + const data = this._tokens.get(editor); + if (!data) { + return; + } + // remove with cancellation + const cts = data.tokens.pop(); + if (cts) { + cts.cancel(); + data.key.set(!data.tokens.isEmpty()); + } + } + +}, true); + +export class EditorKeybindingCancellationTokenSource extends CancellationTokenSource { + + private readonly _unregister: Function; + + constructor(readonly editor: ICodeEditor, parent?: CancellationToken) { + super(parent); + this._unregister = editor.invokeWithinContext(accessor => accessor.get(IEditorCancellationTokens).add(editor, this)); + } + + dispose(): void { + this._unregister(); + super.dispose(); + } +} + +registerEditorCommand(new class extends EditorCommand { + + constructor() { + super({ + id: 'editor.cancelOperation', + kbOpts: { + weight: KeybindingWeight.EditorContrib, + primary: KeyCode.Escape + }, + precondition: ctxCancellableOperation + }); + } + + runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor): void { + accessor.get(IEditorCancellationTokens).cancel(editor); + } +}); diff --git a/src/vs/editor/browser/editorExtensions.ts b/src/vs/editor/browser/editorExtensions.ts index ac0a7331d..e7494cc7a 100644 --- a/src/vs/editor/browser/editorExtensions.ts +++ b/src/vs/editor/browser/editorExtensions.ts @@ -24,6 +24,10 @@ import { withNullAsUndefined } from 'vs/base/common/types'; export type ServicesAccessor = ServicesAccessor; export type IEditorContributionCtor = IConstructorSignature1; +export type EditorTelemetryDataFragment = { + target: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + snippet: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; +}; //#region Command @@ -40,17 +44,17 @@ export interface ICommandMenubarOptions { } export interface ICommandOptions { id: string; - precondition: ContextKeyExpr | null; - kbOpts?: ICommandKeybindingsOptions | null; + precondition: ContextKeyExpr | undefined; + kbOpts?: ICommandKeybindingsOptions; description?: ICommandHandlerDescription; menubarOpts?: ICommandMenubarOptions; } export abstract class Command { public readonly id: string; - public readonly precondition: ContextKeyExpr | null; - private readonly _kbOpts: ICommandKeybindingsOptions | null | undefined; - private readonly _menubarOpts: ICommandMenubarOptions | null | undefined; - private readonly _description: ICommandHandlerDescription | null | undefined; + public readonly precondition: ContextKeyExpr | undefined; + private readonly _kbOpts: ICommandKeybindingsOptions | undefined; + private readonly _menubarOpts: ICommandMenubarOptions | undefined; + private readonly _description: ICommandHandlerDescription | undefined; constructor(opts: ICommandOptions) { this.id = opts.id; @@ -219,16 +223,15 @@ export abstract class EditorAction extends EditorCommand { } protected reportTelemetry(accessor: ServicesAccessor, editor: ICodeEditor) { - /* __GDPR__ - "editorActionInvoked" : { - "name" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "id": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "${include}": [ - "${EditorTelemetryData}" - ] - } - */ - accessor.get(ITelemetryService).publicLog('editorActionInvoked', { name: this.label, id: this.id, ...editor.getTelemetryData() }); + type EditorActionInvokedClassification = { + name: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + id: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + }; + type EditorActionInvokedEvent = { + name: string; + id: string; + }; + accessor.get(ITelemetryService).publicLog2('editorActionInvoked', { name: this.label, id: this.id }); } public abstract run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void | Promise; diff --git a/src/vs/editor/browser/services/bulkEditService.ts b/src/vs/editor/browser/services/bulkEditService.ts index 9411568fc..1bbda5bf6 100644 --- a/src/vs/editor/browser/services/bulkEditService.ts +++ b/src/vs/editor/browser/services/bulkEditService.ts @@ -6,14 +6,14 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { WorkspaceEdit } from 'vs/editor/common/modes'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { IProgressRunner } from 'vs/platform/progress/common/progress'; +import { IProgress, IProgressStep } from 'vs/platform/progress/common/progress'; export const IBulkEditService = createDecorator('IWorkspaceEditService'); export interface IBulkEditOptions { editor?: ICodeEditor; - progress?: IProgressRunner; + progress?: IProgress; } export interface IBulkEditResult { diff --git a/src/vs/editor/browser/services/codeEditorServiceImpl.ts b/src/vs/editor/browser/services/codeEditorServiceImpl.ts index 7ad0bcc40..f439007c4 100644 --- a/src/vs/editor/browser/services/codeEditorServiceImpl.ts +++ b/src/vs/editor/browser/services/codeEditorServiceImpl.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as dom from 'vs/base/browser/dom'; -import { IDisposable, dispose as disposeAll } from 'vs/base/common/lifecycle'; +import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import * as strings from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; @@ -17,18 +17,17 @@ import { ITheme, IThemeService, ThemeColor } from 'vs/platform/theme/common/them export abstract class CodeEditorServiceImpl extends AbstractCodeEditorService { private readonly _styleSheet: HTMLStyleElement; - private readonly _decorationOptionProviders: { [key: string]: IModelDecorationOptionsProvider }; + private readonly _decorationOptionProviders = new Map(); private readonly _themeService: IThemeService; constructor(@IThemeService themeService: IThemeService, styleSheet = dom.createStyleSheet()) { super(); this._styleSheet = styleSheet; - this._decorationOptionProviders = Object.create(null); this._themeService = themeService; } public registerDecorationType(key: string, options: IDecorationRenderOptions, parentTypeKey?: string): void { - let provider = this._decorationOptionProviders[key]; + let provider = this._decorationOptionProviders.get(key); if (!provider) { const providerArgs: ProviderArguments = { styleSheet: this._styleSheet, @@ -41,17 +40,17 @@ export abstract class CodeEditorServiceImpl extends AbstractCodeEditorService { } else { provider = new DecorationSubTypeOptionsProvider(this._themeService, providerArgs); } - this._decorationOptionProviders[key] = provider; + this._decorationOptionProviders.set(key, provider); } provider.refCount++; } public removeDecorationType(key: string): void { - const provider = this._decorationOptionProviders[key]; + const provider = this._decorationOptionProviders.get(key); if (provider) { provider.refCount--; if (provider.refCount <= 0) { - delete this._decorationOptionProviders[key]; + this._decorationOptionProviders.delete(key); provider.dispose(); this.listCodeEditors().forEach((ed) => ed.removeDecorations(key)); } @@ -59,7 +58,7 @@ export abstract class CodeEditorServiceImpl extends AbstractCodeEditorService { } public resolveDecorationOptions(decorationTypeKey: string, writable: boolean): IModelDecorationOptions { - const provider = this._decorationOptionProviders[decorationTypeKey]; + const provider = this._decorationOptionProviders.get(decorationTypeKey); if (!provider) { throw new Error('Unknown decoration type key: ' + decorationTypeKey); } @@ -124,7 +123,7 @@ interface ProviderArguments { class DecorationTypeOptionsProvider implements IModelDecorationOptionsProvider { - private _disposables: IDisposable[]; + private readonly _disposables = new DisposableStore(); public refCount: number; public className: string | undefined; @@ -139,11 +138,10 @@ class DecorationTypeOptionsProvider implements IModelDecorationOptionsProvider { constructor(themeService: IThemeService, providerArgs: ProviderArguments) { this.refCount = 0; - this._disposables = []; const createCSSRules = (type: ModelDecorationCSSRuleType) => { const rules = new DecorationCSSRules(type, providerArgs, themeService); - this._disposables.push(rules); + this._disposables.add(rules); if (rules.hasContent) { return rules.className; } @@ -151,7 +149,7 @@ class DecorationTypeOptionsProvider implements IModelDecorationOptionsProvider { }; const createInlineCSSRules = (type: ModelDecorationCSSRuleType) => { const rules = new DecorationCSSRules(type, providerArgs, themeService); - this._disposables.push(rules); + this._disposables.add(rules); if (rules.hasContent) { return { className: rules.className, hasLetterSpacing: rules.hasLetterSpacing }; } @@ -203,7 +201,7 @@ class DecorationTypeOptionsProvider implements IModelDecorationOptionsProvider { } public dispose(): void { - this._disposables = disposeAll(this._disposables); + this._disposables.dispose(); } } @@ -401,7 +399,7 @@ class DecorationCSSRules { if (typeof opts !== 'undefined') { this.collectBorderSettingsCSSText(opts, cssTextArr); if (typeof opts.contentIconPath !== 'undefined') { - cssTextArr.push(strings.format(_CSS_MAP.contentIconPath, URI.revive(opts.contentIconPath).toString(true).replace(/'/g, '%27'))); + cssTextArr.push(strings.format(_CSS_MAP.contentIconPath, dom.asDomUri(URI.revive(opts.contentIconPath)).toString(true).replace(/'/g, '%27'))); } if (typeof opts.contentText === 'string') { const truncated = opts.contentText.match(/^.*$/m)![0]; // only take first line @@ -428,7 +426,7 @@ class DecorationCSSRules { const cssTextArr: string[] = []; if (typeof opts.gutterIconPath !== 'undefined') { - cssTextArr.push(strings.format(_CSS_MAP.gutterIconPath, URI.revive(opts.gutterIconPath).toString(true).replace(/'/g, '%27'))); + cssTextArr.push(strings.format(_CSS_MAP.gutterIconPath, dom.asDomUri(URI.revive(opts.gutterIconPath)).toString(true).replace(/'/g, '%27'))); if (typeof opts.gutterIconSize !== 'undefined') { cssTextArr.push(strings.format(_CSS_MAP.gutterIconSize, opts.gutterIconSize)); } diff --git a/src/vs/editor/browser/view/viewController.ts b/src/vs/editor/browser/view/viewController.ts index d23899950..10fb2e1aa 100644 --- a/src/vs/editor/browser/view/viewController.ts +++ b/src/vs/editor/browser/view/viewController.ts @@ -133,7 +133,7 @@ export class ViewController { public dispatchMouse(data: IMouseDispatchData): void { if (data.middleButton) { if (data.inSelectionMode) { - this._columnSelect(data.position, data.mouseColumn); + this._columnSelect(data.position, data.mouseColumn, true); } else { this.moveTo(data.position); } @@ -182,7 +182,7 @@ export class ViewController { if (this._hasMulticursorModifier(data)) { if (!this._hasNonMulticursorModifier(data)) { if (data.shiftKey) { - this._columnSelect(data.position, data.mouseColumn); + this._columnSelect(data.position, data.mouseColumn, false); } else { // Do multi-cursor operations only when purely alt is pressed if (data.inSelectionMode) { @@ -195,7 +195,7 @@ export class ViewController { } else { if (data.inSelectionMode) { if (data.altKey) { - this._columnSelect(data.position, data.mouseColumn); + this._columnSelect(data.position, data.mouseColumn, true); } else { this._moveToSelect(data.position); } @@ -222,12 +222,13 @@ export class ViewController { this._execMouseCommand(CoreNavigationCommands.MoveToSelect, this._usualArgs(viewPosition)); } - private _columnSelect(viewPosition: Position, mouseColumn: number): void { + private _columnSelect(viewPosition: Position, mouseColumn: number, setAnchorIfNotSet: boolean): void { viewPosition = this._validateViewColumn(viewPosition); this._execMouseCommand(CoreNavigationCommands.ColumnSelect, { position: this._convertViewToModelPosition(viewPosition), viewPosition: viewPosition, - mouseColumn: mouseColumn + mouseColumn: mouseColumn, + setAnchorIfNotSet: setAnchorIfNotSet }); } diff --git a/src/vs/editor/browser/view/viewImpl.ts b/src/vs/editor/browser/view/viewImpl.ts index b6240b274..41afb8404 100644 --- a/src/vs/editor/browser/view/viewImpl.ts +++ b/src/vs/editor/browser/view/viewImpl.ts @@ -132,7 +132,7 @@ export class View extends ViewEventHandler { this._setLayout(); // Pointer handler - this.pointerHandler = new PointerHandler(this._context, viewController, this.createPointerHandlerHelper()); + this.pointerHandler = this._register(new PointerHandler(this._context, viewController, this.createPointerHandlerHelper())); this._register(model.addEventListener((events: viewEvents.ViewEvent[]) => { this.eventDispatcher.emitMany(events); @@ -342,8 +342,6 @@ export class View extends ViewEventHandler { this.eventDispatcher.removeEventHandler(this); this.outgoingEvents.dispose(); - this.pointerHandler.dispose(); - this.viewLines.dispose(); // Destroy view parts diff --git a/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts b/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts index ac0621d64..c275168cc 100644 --- a/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts +++ b/src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts @@ -324,11 +324,6 @@ class Widget { const aboveLeft0 = topLeft.left - ctx.scrollLeft; const belowLeft0 = bottomLeft.left - ctx.scrollLeft; - if (aboveLeft0 < 0 || aboveLeft0 > this._contentWidth) { - // Don't render if position is scrolled outside viewport - return null; - } - let aboveTop = topLeft.top - height; let belowTop = bottomLeft.top + this._lineHeight; let aboveLeft = aboveLeft0 + this._contentLeft; diff --git a/src/vs/editor/browser/viewParts/lines/rangeUtil.ts b/src/vs/editor/browser/viewParts/lines/rangeUtil.ts index 1561687a3..5344effa7 100644 --- a/src/vs/editor/browser/viewParts/lines/rangeUtil.ts +++ b/src/vs/editor/browser/viewParts/lines/rangeUtil.ts @@ -126,7 +126,7 @@ export class RangeUtil { if (startChildIndex !== endChildIndex) { if (endChildIndex > 0 && endOffset === 0) { endChildIndex--; - endOffset = Number.MAX_VALUE; + endOffset = Constants.MAX_SAFE_SMALL_INTEGER; } } diff --git a/src/vs/editor/browser/viewParts/lines/viewLine.ts b/src/vs/editor/browser/viewParts/lines/viewLine.ts index e23972497..00b684e7e 100644 --- a/src/vs/editor/browser/viewParts/lines/viewLine.ts +++ b/src/vs/editor/browser/viewParts/lines/viewLine.ts @@ -12,7 +12,7 @@ import { IStringBuilder } from 'vs/editor/common/core/stringBuilder'; import { IConfiguration } from 'vs/editor/common/editorCommon'; import { HorizontalRange } from 'vs/editor/common/view/renderingContext'; import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations'; -import { CharacterMapping, ForeignElementType, RenderLineInput, renderViewLine } from 'vs/editor/common/viewLayout/viewLineRenderer'; +import { CharacterMapping, ForeignElementType, RenderLineInput, renderViewLine, LineRange } from 'vs/editor/common/viewLayout/viewLineRenderer'; import { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData'; import { InlineDecorationType } from 'vs/editor/common/viewModel/viewModel'; import { HIGH_CONTRAST, ThemeType } from 'vs/platform/theme/common/themeService'; @@ -69,7 +69,7 @@ export class DomReadingContext { export class ViewLineOptions { public readonly themeType: ThemeType; - public readonly renderWhitespace: 'none' | 'boundary' | 'all'; + public readonly renderWhitespace: 'none' | 'boundary' | 'selection' | 'all'; public readonly renderControlCharacters: boolean; public readonly spaceWidth: number; public readonly useMonospaceOptimizations: boolean; @@ -152,7 +152,7 @@ export class ViewLine implements IVisibleLine { this._options = newOptions; } public onSelectionChanged(): boolean { - if (alwaysRenderInlineSelection || this._options.themeType === HIGH_CONTRAST) { + if (alwaysRenderInlineSelection || this._options.themeType === HIGH_CONTRAST || this._options.renderWhitespace === 'selection') { this._isMaybeInvalid = true; return true; } @@ -171,7 +171,9 @@ export class ViewLine implements IVisibleLine { const options = this._options; const actualInlineDecorations = LineDecoration.filter(lineData.inlineDecorations, lineNumber, lineData.minColumn, lineData.maxColumn); - if (alwaysRenderInlineSelection || options.themeType === HIGH_CONTRAST) { + // Only send selection information when needed for rendering whitespace + let selectionsOnLine: LineRange[] | null = null; + if (alwaysRenderInlineSelection || options.themeType === HIGH_CONTRAST || this._options.renderWhitespace === 'selection') { const selections = viewportData.selections; for (const selection of selections) { @@ -184,7 +186,15 @@ export class ViewLine implements IVisibleLine { const endColumn = (selection.endLineNumber === lineNumber ? selection.endColumn : lineData.maxColumn); if (startColumn < endColumn) { - actualInlineDecorations.push(new LineDecoration(startColumn, endColumn, 'inline-selected-text', InlineDecorationType.Regular)); + if (this._options.renderWhitespace !== 'selection') { + actualInlineDecorations.push(new LineDecoration(startColumn, endColumn, 'inline-selected-text', InlineDecorationType.Regular)); + } else { + if (!selectionsOnLine) { + selectionsOnLine = []; + } + + selectionsOnLine.push(new LineRange(startColumn - 1, endColumn - 1)); + } } } } @@ -204,7 +214,8 @@ export class ViewLine implements IVisibleLine { options.stopRenderingLineAfter, options.renderWhitespace, options.renderControlCharacters, - options.fontLigatures + options.fontLigatures, + selectionsOnLine ); if (this._renderedViewLine && this._renderedViewLine.input.equals(renderLineInput)) { diff --git a/src/vs/editor/browser/viewParts/minimap/minimap.ts b/src/vs/editor/browser/viewParts/minimap/minimap.ts index 259708594..c883223ae 100644 --- a/src/vs/editor/browser/viewParts/minimap/minimap.ts +++ b/src/vs/editor/browser/viewParts/minimap/minimap.ts @@ -23,9 +23,10 @@ import { RenderingContext, RestrictedRenderingContext } from 'vs/editor/common/v import { getOrCreateMinimapCharRenderer } from 'vs/editor/common/view/runtimeMinimapCharRenderer'; import { ViewContext } from 'vs/editor/common/view/viewContext'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; -import { ViewLineData } from 'vs/editor/common/viewModel/viewModel'; +import { ViewLineData, ViewModelDecoration } from 'vs/editor/common/viewModel/viewModel'; import { scrollbarShadow, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground } from 'vs/platform/theme/common/colorRegistry'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { ModelDecorationMinimapOptions } from 'vs/editor/common/model/textModel'; function getMinimapLineHeight(renderMinimap: RenderMinimap): number { if (renderMinimap === RenderMinimap.Large) { @@ -257,7 +258,12 @@ class MinimapLayout { const computedSliderRatio = (maxMinimapSliderTop) / (scrollHeight - viewportHeight); const sliderTop = (scrollTop * computedSliderRatio); - if (minimapLinesFitting >= lineCount) { + let extraLinesAtTheBottom = 0; + if (options.scrollBeyondLastLine) { + const expectedViewportLineCount = viewportHeight / lineHeight; + extraLinesAtTheBottom = expectedViewportLineCount; + } + if (minimapLinesFitting >= lineCount + extraLinesAtTheBottom) { // All lines fit in the minimap const startLineNumber = 1; const endLineNumber = lineCount; @@ -330,10 +336,7 @@ class RenderData { * Check if the current RenderData matches accurately the new desired layout and no painting is needed. */ public linesEquals(layout: MinimapLayout): boolean { - if (this.renderedLayout.startLineNumber !== layout.startLineNumber) { - return false; - } - if (this.renderedLayout.endLineNumber !== layout.endLineNumber) { + if (!this.scrollEquals(layout)) { return false; } @@ -349,6 +352,14 @@ class RenderData { return true; } + /** + * Check if the current RenderData matches the new layout's scroll position + */ + public scrollEquals(layout: MinimapLayout): boolean { + return this.renderedLayout.startLineNumber === layout.startLineNumber + && this.renderedLayout.endLineNumber === layout.endLineNumber; + } + _get(): { imageData: ImageData; rendLineNumberStart: number; lines: MinimapLine[]; } { const tmp = this._renderedLines._get(); return { @@ -430,6 +441,7 @@ export class Minimap extends ViewPart { private readonly _domNode: FastDomNode; private readonly _shadow: FastDomNode; private readonly _canvas: FastDomNode; + private readonly _decorationsCanvas: FastDomNode; private readonly _slider: FastDomNode; private readonly _sliderHorizontal: FastDomNode; private readonly _tokensColorTracker: MinimapTokensColorTracker; @@ -439,6 +451,8 @@ export class Minimap extends ViewPart { private _options: MinimapOptions; private _lastRenderData: RenderData | null; + private _lastDecorations: ViewModelDecoration[] | undefined; + private _renderDecorations: boolean = false; private _buffers: MinimapBuffers | null; constructor(context: ViewContext) { @@ -464,6 +478,12 @@ export class Minimap extends ViewPart { this._canvas.setLeft(0); this._domNode.appendChild(this._canvas); + this._decorationsCanvas = createFastDomNode(document.createElement('canvas')); + this._decorationsCanvas.setPosition('absolute'); + this._decorationsCanvas.setClassName('minimap-decorations-layer'); + this._decorationsCanvas.setLeft(0); + this._domNode.appendChild(this._decorationsCanvas); + this._slider = createFastDomNode(document.createElement('div')); this._slider.setPosition('absolute'); this._slider.setClassName('minimap-slider'); @@ -479,7 +499,7 @@ export class Minimap extends ViewPart { this._applyLayout(); - this._mouseDownListener = dom.addStandardDisposableListener(this._canvas.domNode, 'mousedown', (e) => { + this._mouseDownListener = dom.addStandardDisposableListener(this._domNode.domNode, 'mousedown', (e) => { e.preventDefault(); const renderMinimap = this._options.renderMinimap; @@ -508,6 +528,7 @@ export class Minimap extends ViewPart { this._sliderMouseDownListener = dom.addStandardDisposableListener(this._slider.domNode, 'mousedown', (e) => { e.preventDefault(); + e.stopPropagation(); if (e.leftButton && this._lastRenderData) { const initialMousePosition = e.posy; @@ -564,10 +585,17 @@ export class Minimap extends ViewPart { this._domNode.setWidth(this._options.minimapWidth); this._domNode.setHeight(this._options.minimapHeight); this._shadow.setHeight(this._options.minimapHeight); + this._canvas.setWidth(this._options.canvasOuterWidth); this._canvas.setHeight(this._options.canvasOuterHeight); this._canvas.domNode.width = this._options.canvasInnerWidth; this._canvas.domNode.height = this._options.canvasInnerHeight; + + this._decorationsCanvas.setWidth(this._options.canvasOuterWidth); + this._decorationsCanvas.setHeight(this._options.canvasOuterHeight); + this._decorationsCanvas.domNode.width = this._options.canvasInnerWidth; + this._decorationsCanvas.domNode.height = this._options.canvasInnerHeight; + this._slider.setWidth(this._options.minimapWidth); } @@ -624,6 +652,7 @@ export class Minimap extends ViewPart { return true; } public onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean { + this._renderDecorations = true; return true; } public onTokensChanged(e: viewEvents.ViewTokensChangedEvent): boolean { @@ -642,6 +671,18 @@ export class Minimap extends ViewPart { return true; } + public onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean { + this._renderDecorations = true; + return true; + } + + public onThemeChanged(e: viewEvents.ViewThemeChangedEvent): boolean { + this._context.model.invalidateMinimapColorCache(); + // Only bother calling render if decorations are currently shown + this._renderDecorations = !!this._lastDecorations; + return !!this._lastDecorations; + } + // --- end event handlers public prepareRender(ctx: RenderingContext): void { @@ -684,9 +725,107 @@ export class Minimap extends ViewPart { this._sliderHorizontal.setTop(0); this._sliderHorizontal.setHeight(layout.sliderHeight); + this.renderDecorations(layout); this._lastRenderData = this.renderLines(layout); } + private renderDecorations(layout: MinimapLayout) { + if (this._renderDecorations) { + this._renderDecorations = false; + const decorations = this._context.model.getDecorationsInViewport(new Range(layout.startLineNumber, 1, layout.endLineNumber, this._context.model.getLineMaxColumn(layout.endLineNumber))); + + const { renderMinimap, canvasInnerWidth, canvasInnerHeight } = this._options; + const lineHeight = getMinimapLineHeight(renderMinimap); + const characterWidth = getMinimapCharWidth(renderMinimap); + const tabSize = this._context.model.getOptions().tabSize; + const canvasContext = this._decorationsCanvas.domNode.getContext('2d')!; + + canvasContext.clearRect(0, 0, canvasInnerWidth, canvasInnerHeight); + + // If the minimap is rendered using blocks, text takes up half the line height + const lineHeightRatio = renderMinimap === RenderMinimap.LargeBlocks || renderMinimap === RenderMinimap.SmallBlocks ? 0.5 : 1; + const height = lineHeight * lineHeightRatio; + + // Loop over decorations, ignoring those that don't have the minimap property set and rendering rectangles for each line the decoration spans + const lineOffsetMap = new Map(); + for (let i = 0; i < decorations.length; i++) { + const decoration = decorations[i]; + + if (!decoration.options.minimap) { + continue; + } + + for (let line = decoration.range.startLineNumber; line <= decoration.range.endLineNumber; line++) { + this.renderDecorationOnLine(canvasContext, lineOffsetMap, decoration, layout, line, height, lineHeight, tabSize, characterWidth); + } + } + + this._lastDecorations = decorations; + } + } + + private renderDecorationOnLine(canvasContext: CanvasRenderingContext2D, + lineOffsetMap: Map, + decoration: ViewModelDecoration, + layout: MinimapLayout, + lineNumber: number, + height: number, + lineHeight: number, + tabSize: number, + charWidth: number): void { + const y = (lineNumber - layout.startLineNumber) * lineHeight; + + // Cache line offset data so that it is only read once per line + let lineIndexToXOffset = lineOffsetMap.get(lineNumber); + const isFirstDecorationForLine = !lineIndexToXOffset; + if (!lineIndexToXOffset) { + const lineData = this._context.model.getLineContent(lineNumber); + lineIndexToXOffset = [0]; + for (let i = 1; i < lineData.length + 1; i++) { + const charCode = lineData.charCodeAt(i - 1); + const dx = charCode === CharCode.Tab + ? tabSize * charWidth + : strings.isFullWidthCharacter(charCode) + ? 2 * charWidth + : charWidth; + + lineIndexToXOffset[i] = lineIndexToXOffset[i - 1] + dx; + } + + lineOffsetMap.set(lineNumber, lineIndexToXOffset); + } + + const { startColumn, endColumn, startLineNumber, endLineNumber } = decoration.range; + const x = startLineNumber === lineNumber ? lineIndexToXOffset[startColumn - 1] : 0; + + const endColumnForLine = endLineNumber > lineNumber ? lineIndexToXOffset.length - 1 : endColumn - 1; + + if (endColumnForLine > 0) { + // If the decoration starts at the last character of the column and spans over it, ensure it has a width + const width = lineIndexToXOffset[endColumnForLine] - x || 2; + + this.renderDecoration(canvasContext, decoration.options.minimap, x, y, width, height); + } + + if (isFirstDecorationForLine) { + this.renderLineHighlight(canvasContext, decoration.options.minimap, y, height); + } + + } + + private renderLineHighlight(canvasContext: CanvasRenderingContext2D, minimapOptions: ModelDecorationMinimapOptions, y: number, height: number): void { + const decorationColor = minimapOptions.getColor(this._context.theme); + canvasContext.fillStyle = decorationColor && decorationColor.transparent(0.5).toString() || ''; + canvasContext.fillRect(0, y, canvasContext.canvas.width, height); + } + + private renderDecoration(canvasContext: CanvasRenderingContext2D, minimapOptions: ModelDecorationMinimapOptions, x: number, y: number, width: number, height: number) { + const decorationColor = minimapOptions.getColor(this._context.theme); + + canvasContext.fillStyle = decorationColor && decorationColor.toString() || ''; + canvasContext.fillRect(x, y, width, height); + } + private renderLines(layout: MinimapLayout): RenderData { const renderMinimap = this._options.renderMinimap; const startLineNumber = layout.startLineNumber; diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index adaf6b71b..d83f185fd 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -38,7 +38,8 @@ import { ClassName } from 'vs/editor/common/model/intervalTree'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; import { IModelContentChangedEvent, IModelDecorationsChangedEvent, IModelLanguageChangedEvent, IModelLanguageConfigurationChangedEvent, IModelOptionsChangedEvent } from 'vs/editor/common/model/textModelEvents'; import * as modes from 'vs/editor/common/modes'; -import { editorErrorBorder, editorErrorForeground, editorHintBorder, editorHintForeground, editorInfoBorder, editorInfoForeground, editorUnnecessaryCodeBorder, editorUnnecessaryCodeOpacity, editorWarningBorder, editorWarningForeground } from 'vs/editor/common/view/editorColorRegistry'; +import { editorUnnecessaryCodeBorder, editorUnnecessaryCodeOpacity } from 'vs/editor/common/view/editorColorRegistry'; +import { editorErrorBorder, editorErrorForeground, editorHintBorder, editorHintForeground, editorInfoBorder, editorInfoForeground, editorWarningBorder, editorWarningForeground, editorForeground } from 'vs/platform/theme/common/colorRegistry'; import { VerticalRevealType } from 'vs/editor/common/view/viewEvents'; import { IEditorWhitespace } from 'vs/editor/common/viewLayout/whitespaceComputer'; import { ViewModel } from 'vs/editor/common/viewModel/viewModelImpl'; @@ -1507,9 +1508,6 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE return this._codeEditorService.resolveDecorationOptions(typeKey, writable); } - /* __GDPR__FRAGMENT__ - "EditorTelemetryData" : {} - */ public getTelemetryData(): { [key: string]: any; } | undefined { return this._telemetryData; } @@ -1850,4 +1848,7 @@ registerThemingParticipant((theme, collector) => { if (unnecessaryBorder) { collector.addRule(`.${SHOW_UNUSED_ENABLED_CLASS} .monaco-editor .${ClassName.EditorUnnecessaryDecoration} { border-bottom: 2px dashed ${unnecessaryBorder}; }`); } + + const deprecatedForeground = theme.getColor(editorForeground) || 'inherit'; + collector.addRule(`.monaco-editor .${ClassName.EditorDeprecatedInlineDecoration} { text-decoration: line-through; text-decoration-color: ${deprecatedForeground}}`); }); diff --git a/src/vs/editor/browser/widget/diffEditorWidget.ts b/src/vs/editor/browser/widget/diffEditorWidget.ts index d8ee01053..9c3c0df63 100644 --- a/src/vs/editor/browser/widget/diffEditorWidget.ts +++ b/src/vs/editor/browser/widget/diffEditorWidget.ts @@ -316,9 +316,9 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE } if (this._renderSideBySide) { - this._setStrategy(new DiffEdtorWidgetSideBySide(this._createDataSource(), this._enableSplitViewResizing)); + this._setStrategy(new DiffEditorWidgetSideBySide(this._createDataSource(), this._enableSplitViewResizing)); } else { - this._setStrategy(new DiffEdtorWidgetInline(this._createDataSource(), this._enableSplitViewResizing)); + this._setStrategy(new DiffEditorWidgetInline(this._createDataSource(), this._enableSplitViewResizing)); } this._register(themeService.onThemeChange(t => { @@ -590,9 +590,9 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE // renderSideBySide if (renderSideBySideChanged) { if (this._renderSideBySide) { - this._setStrategy(new DiffEdtorWidgetSideBySide(this._createDataSource(), this._enableSplitViewResizing)); + this._setStrategy(new DiffEditorWidgetSideBySide(this._createDataSource(), this._enableSplitViewResizing)); } else { - this._setStrategy(new DiffEdtorWidgetInline(this._createDataSource(), this._enableSplitViewResizing)); + this._setStrategy(new DiffEditorWidgetInline(this._createDataSource(), this._enableSplitViewResizing)); } // Update class name this._containerDomElement.className = DiffEditorWidget._getClassName(this._themeService.getTheme(), this._renderSideBySide); @@ -1527,7 +1527,7 @@ const DECORATIONS = { }; -class DiffEdtorWidgetSideBySide extends DiffEditorWidgetStyle implements IDiffEditorWidgetStyle, IVerticalSashLayoutProvider { +class DiffEditorWidgetSideBySide extends DiffEditorWidgetStyle implements IDiffEditorWidgetStyle, IVerticalSashLayoutProvider { static MINIMUM_EDITOR_WIDTH = 100; @@ -1572,13 +1572,13 @@ class DiffEdtorWidgetSideBySide extends DiffEditorWidgetStyle implements IDiffEd sashPosition = this._disableSash ? midPoint : sashPosition || midPoint; - if (contentWidth > DiffEdtorWidgetSideBySide.MINIMUM_EDITOR_WIDTH * 2) { - if (sashPosition < DiffEdtorWidgetSideBySide.MINIMUM_EDITOR_WIDTH) { - sashPosition = DiffEdtorWidgetSideBySide.MINIMUM_EDITOR_WIDTH; + if (contentWidth > DiffEditorWidgetSideBySide.MINIMUM_EDITOR_WIDTH * 2) { + if (sashPosition < DiffEditorWidgetSideBySide.MINIMUM_EDITOR_WIDTH) { + sashPosition = DiffEditorWidgetSideBySide.MINIMUM_EDITOR_WIDTH; } - if (sashPosition > contentWidth - DiffEdtorWidgetSideBySide.MINIMUM_EDITOR_WIDTH) { - sashPosition = contentWidth - DiffEdtorWidgetSideBySide.MINIMUM_EDITOR_WIDTH; + if (sashPosition > contentWidth - DiffEditorWidgetSideBySide.MINIMUM_EDITOR_WIDTH) { + sashPosition = contentWidth - DiffEditorWidgetSideBySide.MINIMUM_EDITOR_WIDTH; } } else { sashPosition = midPoint; @@ -1787,7 +1787,7 @@ class SideBySideViewZonesComputer extends ViewZonesComputer { } } -class DiffEdtorWidgetInline extends DiffEditorWidgetStyle implements IDiffEditorWidgetStyle { +class DiffEditorWidgetInline extends DiffEditorWidgetStyle implements IDiffEditorWidgetStyle { private decorationsLeft: number; @@ -2027,7 +2027,8 @@ class InlineViewZonesComputer extends ViewZonesComputer { config.viewInfo.stopRenderingLineAfter, config.viewInfo.renderWhitespace, config.viewInfo.renderControlCharacters, - config.viewInfo.fontLigatures + config.viewInfo.fontLigatures, + null // Send no selections, original line cannot be selected ), sb); sb.appendASCIIString(''); diff --git a/src/vs/editor/browser/widget/diffNavigator.ts b/src/vs/editor/browser/widget/diffNavigator.ts index 29afe7ec6..1c941ed0f 100644 --- a/src/vs/editor/browser/widget/diffNavigator.ts +++ b/src/vs/editor/browser/widget/diffNavigator.ts @@ -5,7 +5,7 @@ import * as assert from 'vs/base/common/assert'; import { Emitter, Event } from 'vs/base/common/event'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { Disposable } from 'vs/base/common/lifecycle'; import * as objects from 'vs/base/common/objects'; import { IDiffEditor } from 'vs/editor/browser/editorBrowser'; import { ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; @@ -33,12 +33,11 @@ const defaultOptions: Options = { /** * Create a new diff navigator for the provided diff editor. */ -export class DiffNavigator { +export class DiffNavigator extends Disposable { private readonly _editor: IDiffEditor; private readonly _options: Options; - private readonly _disposables: IDisposable[]; - private readonly _onDidUpdate = new Emitter(); + private readonly _onDidUpdate = this._register(new Emitter()); readonly onDidUpdate: Event = this._onDidUpdate.event; @@ -49,11 +48,11 @@ export class DiffNavigator { private ignoreSelectionChange: boolean; constructor(editor: IDiffEditor, options: Options = {}) { + super(); this._editor = editor; this._options = objects.mixin(options, defaultOptions, false); this.disposed = false; - this._disposables = []; this.nextIdx = -1; this.ranges = []; @@ -61,11 +60,11 @@ export class DiffNavigator { this.revealFirst = Boolean(this._options.alwaysRevealFirst); // hook up to diff editor for diff, disposal, and caret move - this._disposables.push(this._editor.onDidDispose(() => this.dispose())); - this._disposables.push(this._editor.onDidUpdateDiff(() => this._onDiffUpdated())); + this._register(this._editor.onDidDispose(() => this.dispose())); + this._register(this._editor.onDidUpdateDiff(() => this._onDiffUpdated())); if (this._options.followsCaret) { - this._disposables.push(this._editor.getModifiedEditor().onDidChangeCursorPosition((e: ICursorPositionChangedEvent) => { + this._register(this._editor.getModifiedEditor().onDidChangeCursorPosition((e: ICursorPositionChangedEvent) => { if (this.ignoreSelectionChange) { return; } @@ -73,7 +72,7 @@ export class DiffNavigator { })); } if (this._options.alwaysRevealFirst) { - this._disposables.push(this._editor.getModifiedEditor().onDidChangeModel((e) => { + this._register(this._editor.getModifiedEditor().onDidChangeModel((e) => { this.revealFirst = true; })); } @@ -216,9 +215,7 @@ export class DiffNavigator { } dispose(): void { - dispose(this._disposables); - this._disposables.length = 0; - this._onDidUpdate.dispose(); + super.dispose(); this.ranges = []; this.disposed = true; } diff --git a/src/vs/editor/browser/widget/diffReview.ts b/src/vs/editor/browser/widget/diffReview.ts index beb608e6d..037883dd5 100644 --- a/src/vs/editor/browser/widget/diffReview.ts +++ b/src/vs/editor/browser/widget/diffReview.ts @@ -780,7 +780,8 @@ export class DiffReview extends Disposable { config.viewInfo.stopRenderingLineAfter, config.viewInfo.renderWhitespace, config.viewInfo.renderControlCharacters, - config.viewInfo.fontLigatures + config.viewInfo.fontLigatures, + null )); return r.html; diff --git a/src/vs/editor/browser/widget/media/addition-dark.svg b/src/vs/editor/browser/widget/media/addition-dark.svg new file mode 100644 index 000000000..4d9389336 --- /dev/null +++ b/src/vs/editor/browser/widget/media/addition-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/browser/widget/media/addition-inverse.svg b/src/vs/editor/browser/widget/media/addition-inverse.svg deleted file mode 100644 index 3475c1e19..000000000 --- a/src/vs/editor/browser/widget/media/addition-inverse.svg +++ /dev/null @@ -1 +0,0 @@ -Layer 1 \ No newline at end of file diff --git a/src/vs/editor/browser/widget/media/addition-light.svg b/src/vs/editor/browser/widget/media/addition-light.svg new file mode 100644 index 000000000..01a9de7d5 --- /dev/null +++ b/src/vs/editor/browser/widget/media/addition-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/browser/widget/media/addition.svg b/src/vs/editor/browser/widget/media/addition.svg deleted file mode 100644 index bdecdb0e4..000000000 --- a/src/vs/editor/browser/widget/media/addition.svg +++ /dev/null @@ -1 +0,0 @@ -Layer 1 \ No newline at end of file diff --git a/src/vs/editor/browser/widget/media/close-dark.svg b/src/vs/editor/browser/widget/media/close-dark.svg new file mode 100644 index 000000000..6d16d212a --- /dev/null +++ b/src/vs/editor/browser/widget/media/close-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/browser/widget/media/close-inverse.svg b/src/vs/editor/browser/widget/media/close-inverse.svg deleted file mode 100644 index 751e89b3b..000000000 --- a/src/vs/editor/browser/widget/media/close-inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/browser/widget/media/close-light.svg b/src/vs/editor/browser/widget/media/close-light.svg new file mode 100644 index 000000000..742fcae4a --- /dev/null +++ b/src/vs/editor/browser/widget/media/close-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/browser/widget/media/close.svg b/src/vs/editor/browser/widget/media/close.svg deleted file mode 100644 index fde34404d..000000000 --- a/src/vs/editor/browser/widget/media/close.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/browser/widget/media/deletion-dark.svg b/src/vs/editor/browser/widget/media/deletion-dark.svg new file mode 100644 index 000000000..4c5a9c1e3 --- /dev/null +++ b/src/vs/editor/browser/widget/media/deletion-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/browser/widget/media/deletion-inverse.svg b/src/vs/editor/browser/widget/media/deletion-inverse.svg deleted file mode 100644 index 2de46fcf5..000000000 --- a/src/vs/editor/browser/widget/media/deletion-inverse.svg +++ /dev/null @@ -1 +0,0 @@ -Layer 1 \ No newline at end of file diff --git a/src/vs/editor/browser/widget/media/deletion-light.svg b/src/vs/editor/browser/widget/media/deletion-light.svg new file mode 100644 index 000000000..d12a8ee31 --- /dev/null +++ b/src/vs/editor/browser/widget/media/deletion-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/browser/widget/media/deletion.svg b/src/vs/editor/browser/widget/media/deletion.svg deleted file mode 100644 index f5d128b2d..000000000 --- a/src/vs/editor/browser/widget/media/deletion.svg +++ /dev/null @@ -1 +0,0 @@ -Layer 1 \ No newline at end of file diff --git a/src/vs/editor/browser/widget/media/diffEditor.css b/src/vs/editor/browser/widget/media/diffEditor.css index 5e71f38a9..d70b8b880 100644 --- a/src/vs/editor/browser/widget/media/diffEditor.css +++ b/src/vs/editor/browser/widget/media/diffEditor.css @@ -40,8 +40,7 @@ background-size: 60%; opacity: 0.7; background-repeat: no-repeat; - background-position: 50% 50%; - background-position: center; + background-position: 75% center; background-size: 11px 11px; } .monaco-editor.hc-black .insert-sign, @@ -52,24 +51,24 @@ } .monaco-editor .insert-sign, .monaco-diff-editor .insert-sign { - background-image: url('addition.svg'); + background-image: url('addition-light.svg'); } .monaco-editor .delete-sign, .monaco-diff-editor .delete-sign { - background-image: url('deletion.svg'); + background-image: url('deletion-light.svg'); } .monaco-editor.vs-dark .insert-sign, .monaco-diff-editor.vs-dark .insert-sign, .monaco-editor.hc-black .insert-sign, .monaco-diff-editor.hc-black .insert-sign { - background-image: url('addition-inverse.svg'); + background-image: url('addition-dark.svg'); } .monaco-editor.vs-dark .delete-sign, .monaco-diff-editor.vs-dark .delete-sign, .monaco-editor.hc-black .delete-sign, .monaco-diff-editor.hc-black .delete-sign { - background-image: url('deletion-inverse.svg'); + background-image: url('deletion-dark.svg'); } .monaco-editor .inline-deleted-margin-view-zone { diff --git a/src/vs/editor/browser/widget/media/diffReview.css b/src/vs/editor/browser/widget/media/diffReview.css index edb9317dd..4cf9f7b83 100644 --- a/src/vs/editor/browser/widget/media/diffReview.css +++ b/src/vs/editor/browser/widget/media/diffReview.css @@ -62,9 +62,9 @@ margin: 2px 0; } .monaco-diff-editor .action-label.icon.close-diff-review { - background: url('close.svg') center center no-repeat; + background: url('close-light.svg') center center no-repeat; } .monaco-diff-editor.hc-black .action-label.icon.close-diff-review, .monaco-diff-editor.vs-dark .action-label.icon.close-diff-review { - background: url('close-inverse.svg') center center no-repeat; + background: url('close-dark.svg') center center no-repeat; } \ No newline at end of file diff --git a/src/vs/editor/browser/widget/media/editor.css b/src/vs/editor/browser/widget/media/editor.css index 3266ae963..fb9e5f5e8 100644 --- a/src/vs/editor/browser/widget/media/editor.css +++ b/src/vs/editor/browser/widget/media/editor.css @@ -39,4 +39,10 @@ .monaco-editor .view-overlays { position: absolute; top: 0; -} \ No newline at end of file +} + +/* +.monaco-editor .auto-closed-character { + opacity: 0.3; +} +*/ diff --git a/src/vs/editor/common/config/commonEditorConfig.ts b/src/vs/editor/common/config/commonEditorConfig.ts index 7571c594a..5d1818712 100644 --- a/src/vs/editor/common/config/commonEditorConfig.ts +++ b/src/vs/editor/common/config/commonEditorConfig.ts @@ -153,8 +153,8 @@ export abstract class CommonEditorConfiguration extends Disposable implements ed return true; } - private static _subsetEquals(base: object, subset: object): boolean { - for (let key in subset) { + private static _subsetEquals(base: { [key: string]: any }, subset: { [key: string]: any }): boolean { + for (const key in subset) { if (hasOwnProperty.call(subset, key)) { const subsetValue = subset[key]; const baseValue = base[key]; @@ -460,7 +460,7 @@ const editorConfiguration: IConfigurationNode = { 'editor.fastScrollSensitivity': { 'type': 'number', 'default': EDITOR_DEFAULTS.viewInfo.scrollbar.fastScrollSensitivity, - 'markdownDescription': nls.localize('fastScrollSensitivity', "Scrolling speed mulitiplier when pressing `Alt`.") + 'markdownDescription': nls.localize('fastScrollSensitivity', "Scrolling speed multiplier when pressing `Alt`.") }, 'editor.multiCursorModifier': { 'type': 'string', @@ -696,7 +696,7 @@ const editorConfiguration: IConfigurationNode = { }, 'editor.suggest.filteredTypes': { type: 'object', - default: { keyword: true }, + default: { keyword: true, snippet: true }, markdownDescription: nls.localize('suggest.filtered', "Controls whether some suggestion types should be filtered from IntelliSense. A list of suggestion types can be found here: https://code.visualstudio.com/docs/editor/intellisense#_types-of-completions."), properties: { method: { @@ -839,7 +839,7 @@ const editorConfiguration: IConfigurationNode = { enumDescriptions: [ nls.localize('editor.gotoLocation.multiple.peek', 'Show peek view of the results (default)'), nls.localize('editor.gotoLocation.multiple.gotoAndPeek', 'Go to the primary result and show a peek view'), - nls.localize('editor.gotoLocation.multiple.goto', 'Go to the primary result and ignore others') + nls.localize('editor.gotoLocation.multiple.goto', 'Go to the primary result and enable peek-less navigation to others') ] }, 'editor.selectionHighlight': { @@ -901,10 +901,11 @@ const editorConfiguration: IConfigurationNode = { }, 'editor.renderWhitespace': { 'type': 'string', - 'enum': ['none', 'boundary', 'all'], + 'enum': ['none', 'boundary', 'selection', 'all'], 'enumDescriptions': [ '', - nls.localize('renderWhiteSpace.boundary', "Render whitespace characters except for single spaces between words."), + nls.localize('renderWhitespace.boundary', "Render whitespace characters except for single spaces between words."), + nls.localize('renderWhitespace.selection', "Render whitespace characters only on selected text."), '' ], default: EDITOR_DEFAULTS.viewInfo.renderWhitespace, diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index 6c010edc1..79ba4dc83 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -664,7 +664,7 @@ export interface IEditorOptions { * Enable rendering of whitespace. * Defaults to none. */ - renderWhitespace?: 'none' | 'boundary' | 'all'; + renderWhitespace?: 'none' | 'boundary' | 'selection' | 'all'; /** * Enable rendering of control characters. * Defaults to false. @@ -999,7 +999,7 @@ export interface InternalEditorViewOptions { readonly scrollBeyondLastColumn: number; readonly smoothScrolling: boolean; readonly stopRenderingLineAfter: number; - readonly renderWhitespace: 'none' | 'boundary' | 'all'; + readonly renderWhitespace: 'none' | 'boundary' | 'selection' | 'all'; readonly renderControlCharacters: boolean; readonly fontLigatures: boolean; readonly renderIndentGuides: boolean; @@ -2017,7 +2017,7 @@ export class EditorOptionsValidator { } else if (renderWhitespace === false) { renderWhitespace = 'none'; } - renderWhitespace = _stringSet<'none' | 'boundary' | 'all'>(renderWhitespace, defaults.renderWhitespace, ['none', 'boundary', 'all']); + renderWhitespace = _stringSet<'none' | 'boundary' | 'selection' | 'all'>(renderWhitespace, defaults.renderWhitespace, ['none', 'boundary', 'selection', 'all']); } let renderLineHighlight = opts.renderLineHighlight; diff --git a/src/vs/editor/common/controller/cursor.ts b/src/vs/editor/common/controller/cursor.ts index 81493777b..789d3a97b 100644 --- a/src/vs/editor/common/controller/cursor.ts +++ b/src/vs/editor/common/controller/cursor.ts @@ -10,15 +10,16 @@ import { CursorCollection } from 'vs/editor/common/controller/cursorCollection'; import { CursorColumns, CursorConfiguration, CursorContext, CursorState, EditOperationResult, EditOperationType, IColumnSelectData, ICursors, PartialCursorState, RevealTarget } from 'vs/editor/common/controller/cursorCommon'; import { DeleteOperations } from 'vs/editor/common/controller/cursorDeleteOperations'; import { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents'; -import { TypeOperations } from 'vs/editor/common/controller/cursorTypeOperations'; +import { TypeOperations, TypeWithAutoClosingCommand } from 'vs/editor/common/controller/cursorTypeOperations'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { ISelection, Selection, SelectionDirection } from 'vs/editor/common/core/selection'; import * as editorCommon from 'vs/editor/common/editorCommon'; -import { IIdentifiedSingleEditOperation, ITextModel, TrackedRangeStickiness } from 'vs/editor/common/model'; +import { IIdentifiedSingleEditOperation, ITextModel, TrackedRangeStickiness, IModelDeltaDecoration } from 'vs/editor/common/model'; import { RawContentChangedType } from 'vs/editor/common/model/textModelEvents'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { IViewModel } from 'vs/editor/common/viewModel/viewModel'; +import { dispose } from 'vs/base/common/lifecycle'; function containsLineMappingChanged(events: viewEvents.ViewEvent[]): boolean { for (let i = 0, len = events.length; i < len; i++) { @@ -83,6 +84,64 @@ export class CursorModelState { } } +class AutoClosedAction { + + private readonly _model: ITextModel; + + private _autoClosedCharactersDecorations: string[]; + private _autoClosedEnclosingDecorations: string[]; + + constructor(model: ITextModel, autoClosedCharactersDecorations: string[], autoClosedEnclosingDecorations: string[]) { + this._model = model; + this._autoClosedCharactersDecorations = autoClosedCharactersDecorations; + this._autoClosedEnclosingDecorations = autoClosedEnclosingDecorations; + } + + public dispose(): void { + this._autoClosedCharactersDecorations = this._model.deltaDecorations(this._autoClosedCharactersDecorations, []); + this._autoClosedEnclosingDecorations = this._model.deltaDecorations(this._autoClosedEnclosingDecorations, []); + } + + public getAutoClosedCharactersRanges(): Range[] { + let result: Range[] = []; + for (let i = 0; i < this._autoClosedCharactersDecorations.length; i++) { + const decorationRange = this._model.getDecorationRange(this._autoClosedCharactersDecorations[i]); + if (decorationRange) { + result.push(decorationRange); + } + } + return result; + } + + public isValid(selections: Range[]): boolean { + let enclosingRanges: Range[] = []; + for (let i = 0; i < this._autoClosedEnclosingDecorations.length; i++) { + const decorationRange = this._model.getDecorationRange(this._autoClosedEnclosingDecorations[i]); + if (decorationRange) { + enclosingRanges.push(decorationRange); + if (decorationRange.startLineNumber !== decorationRange.endLineNumber) { + // Stop tracking if the range becomes multiline... + return false; + } + } + } + enclosingRanges.sort(Range.compareRangesUsingStarts); + + selections.sort(Range.compareRangesUsingStarts); + + for (let i = 0; i < selections.length; i++) { + if (i >= enclosingRanges.length) { + return false; + } + if (!enclosingRanges[i].strictContainsRange(selections[i])) { + return false; + } + } + + return true; + } +} + export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { public static MAX_CURSOR_COUNT = 10000; @@ -106,6 +165,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { private _isHandling: boolean; private _isDoingComposition: boolean; private _columnSelectData: IColumnSelectData | null; + private _autoClosedActions: AutoClosedAction[]; private _prevEditOperationType: EditOperationType; constructor(configuration: editorCommon.IConfiguration, model: ITextModel, viewModel: IViewModel) { @@ -120,6 +180,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { this._isHandling = false; this._isDoingComposition = false; this._columnSelectData = null; + this._autoClosedActions = []; this._prevEditOperationType = EditOperationType.Other; this._register(this._model.onDidChangeRawContent((e) => { @@ -173,9 +234,24 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { public dispose(): void { this._cursors.dispose(); + this._autoClosedActions = dispose(this._autoClosedActions); super.dispose(); } + private _validateAutoClosedActions(): void { + if (this._autoClosedActions.length > 0) { + let selections: Range[] = this._cursors.getSelections(); + for (let i = 0; i < this._autoClosedActions.length; i++) { + const autoClosedAction = this._autoClosedActions[i]; + if (!autoClosedAction.isValid(selections)) { + autoClosedAction.dispose(); + this._autoClosedActions.splice(i, 1); + i--; + } + } + } + } + // ------ some getters/setters public getPrimaryCursor(): CursorState { @@ -202,6 +278,8 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { this._cursors.normalize(); this._columnSelectData = null; + this._validateAutoClosedActions(); + this._emitStateChangedIfNecessary(source, reason, oldState); } @@ -296,7 +374,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { // a model.setValue() was called this._cursors.dispose(); this._cursors = new CursorCollection(this.context); - + this._validateAutoClosedActions(); this._emitStateChangedIfNecessary('model', CursorChangeReason.ContentFlush, null); } else { const selectionsFromMarkers = this._cursors.readSelectionFromMarkers(); @@ -314,9 +392,14 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { } const primaryCursor = this._cursors.getPrimaryCursor(); const primaryPos = primaryCursor.viewState.position; + const viewLineNumber = primaryPos.lineNumber; + const viewVisualColumn = CursorColumns.visibleColumnFromColumn2(this.context.config, this.context.viewModel, primaryPos); return { - toViewLineNumber: primaryPos.lineNumber, - toViewVisualColumn: CursorColumns.visibleColumnFromColumn2(this.context.config, this.context.viewModel, primaryPos) + isReal: false, + fromViewLineNumber: viewLineNumber, + fromViewVisualColumn: viewVisualColumn, + toViewLineNumber: viewLineNumber, + toViewVisualColumn: viewVisualColumn, }; } @@ -362,6 +445,35 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { // The commands were applied correctly this._interpretCommandResult(result); + // Check for auto-closing closed characters + let autoClosedCharactersRanges: IModelDeltaDecoration[] = []; + let autoClosedEnclosingRanges: IModelDeltaDecoration[] = []; + + for (let i = 0; i < opResult.commands.length; i++) { + const command = opResult.commands[i]; + if (command instanceof TypeWithAutoClosingCommand && command.enclosingRange && command.closeCharacterRange) { + autoClosedCharactersRanges.push({ + range: command.closeCharacterRange, + options: { + inlineClassName: 'auto-closed-character', + stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges + } + }); + autoClosedEnclosingRanges.push({ + range: command.enclosingRange, + options: { + stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges + } + }); + } + } + + if (autoClosedCharactersRanges.length > 0) { + const autoClosedCharactersDecorations = this._model.deltaDecorations([], autoClosedCharactersRanges); + const autoClosedEnclosingDecorations = this._model.deltaDecorations([], autoClosedEnclosingRanges); + this._autoClosedActions.push(new AutoClosedAction(this._model, autoClosedCharactersDecorations, autoClosedEnclosingDecorations)); + } + this._prevEditOperationType = opResult.type; } @@ -535,6 +647,8 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { this._cursors.startTrackingSelections(); } + this._validateAutoClosedActions(); + if (this._emitStateChangedIfNecessary(source, cursorChangeReason, oldState)) { this._revealRange(RevealTarget.Primary, viewEvents.VerticalRevealType.Simple, true, editorCommon.ScrollType.Smooth); } @@ -561,8 +675,15 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { chr = text.charAt(i); } + let autoClosedCharacters: Range[] = []; + if (this._autoClosedActions.length > 0) { + for (let i = 0, len = this._autoClosedActions.length; i < len; i++) { + autoClosedCharacters = autoClosedCharacters.concat(this._autoClosedActions[i].getAutoClosedCharactersRanges()); + } + } + // Here we must interpret each typed character individually, that's why we create a new context - this._executeEditOperation(TypeOperations.typeWithInterceptors(this._prevEditOperationType, this.context.config, this.context.model, this.getSelections(), chr)); + this._executeEditOperation(TypeOperations.typeWithInterceptors(this._prevEditOperationType, this.context.config, this.context.model, this.getSelections(), autoClosedCharacters, chr)); } } else { diff --git a/src/vs/editor/common/controller/cursorColumnSelection.ts b/src/vs/editor/common/controller/cursorColumnSelection.ts index efa35ca08..cb89e0efc 100644 --- a/src/vs/editor/common/controller/cursorColumnSelection.ts +++ b/src/vs/editor/common/controller/cursorColumnSelection.ts @@ -3,21 +3,22 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { CursorColumns, CursorConfiguration, ICursorSimpleModel, SingleCursorState } from 'vs/editor/common/controller/cursorCommon'; +import { CursorColumns, CursorConfiguration, ICursorSimpleModel, SingleCursorState, IColumnSelectData } from 'vs/editor/common/controller/cursorCommon'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; -import { Selection } from 'vs/editor/common/core/selection'; export interface IColumnSelectResult { viewStates: SingleCursorState[]; reversed: boolean; + fromLineNumber: number; + fromVisualColumn: number; toLineNumber: number; toVisualColumn: number; } export class ColumnSelection { - private static _columnSelect(config: CursorConfiguration, model: ICursorSimpleModel, fromLineNumber: number, fromVisibleColumn: number, toLineNumber: number, toVisibleColumn: number): IColumnSelectResult { + public static columnSelect(config: CursorConfiguration, model: ICursorSimpleModel, fromLineNumber: number, fromVisibleColumn: number, toLineNumber: number, toVisibleColumn: number): IColumnSelectResult { let lineCount = Math.abs(toLineNumber - fromLineNumber) + 1; let reversed = (fromLineNumber > toLineNumber); let isRTL = (fromVisibleColumn > toVisibleColumn); @@ -61,64 +62,65 @@ export class ColumnSelection { )); } + if (result.length === 0) { + // We are after all the lines, so add cursor at the end of each line + for (let i = 0; i < lineCount; i++) { + const lineNumber = fromLineNumber + (reversed ? -i : i); + const maxColumn = model.getLineMaxColumn(lineNumber); + + result.push(new SingleCursorState( + new Range(lineNumber, maxColumn, lineNumber, maxColumn), 0, + new Position(lineNumber, maxColumn), 0 + )); + } + } + return { viewStates: result, reversed: reversed, + fromLineNumber: fromLineNumber, + fromVisualColumn: fromVisibleColumn, toLineNumber: toLineNumber, toVisualColumn: toVisibleColumn }; } - public static columnSelect(config: CursorConfiguration, model: ICursorSimpleModel, fromViewSelection: Selection, toViewLineNumber: number, toViewVisualColumn: number): IColumnSelectResult { - const fromViewPosition = new Position(fromViewSelection.selectionStartLineNumber, fromViewSelection.selectionStartColumn); - const fromViewVisibleColumn = CursorColumns.visibleColumnFromColumn2(config, model, fromViewPosition); - return ColumnSelection._columnSelect(config, model, fromViewPosition.lineNumber, fromViewVisibleColumn, toViewLineNumber, toViewVisualColumn); - } - - public static columnSelectLeft(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, toViewLineNumber: number, toViewVisualColumn: number): IColumnSelectResult { + public static columnSelectLeft(config: CursorConfiguration, model: ICursorSimpleModel, prevColumnSelectData: IColumnSelectData): IColumnSelectResult { + let toViewVisualColumn = prevColumnSelectData.toViewVisualColumn; if (toViewVisualColumn > 1) { toViewVisualColumn--; } - return this.columnSelect(config, model, cursor.selection, toViewLineNumber, toViewVisualColumn); + return ColumnSelection.columnSelect(config, model, prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.fromViewVisualColumn, prevColumnSelectData.toViewLineNumber, toViewVisualColumn); } - public static columnSelectRight(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, toViewLineNumber: number, toViewVisualColumn: number): IColumnSelectResult { + public static columnSelectRight(config: CursorConfiguration, model: ICursorSimpleModel, prevColumnSelectData: IColumnSelectData): IColumnSelectResult { let maxVisualViewColumn = 0; - let minViewLineNumber = Math.min(cursor.position.lineNumber, toViewLineNumber); - let maxViewLineNumber = Math.max(cursor.position.lineNumber, toViewLineNumber); + const minViewLineNumber = Math.min(prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.toViewLineNumber); + const maxViewLineNumber = Math.max(prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.toViewLineNumber); for (let lineNumber = minViewLineNumber; lineNumber <= maxViewLineNumber; lineNumber++) { - let lineMaxViewColumn = model.getLineMaxColumn(lineNumber); - let lineMaxVisualViewColumn = CursorColumns.visibleColumnFromColumn2(config, model, new Position(lineNumber, lineMaxViewColumn)); + const lineMaxViewColumn = model.getLineMaxColumn(lineNumber); + const lineMaxVisualViewColumn = CursorColumns.visibleColumnFromColumn2(config, model, new Position(lineNumber, lineMaxViewColumn)); maxVisualViewColumn = Math.max(maxVisualViewColumn, lineMaxVisualViewColumn); } + let toViewVisualColumn = prevColumnSelectData.toViewVisualColumn; if (toViewVisualColumn < maxVisualViewColumn) { toViewVisualColumn++; } - return this.columnSelect(config, model, cursor.selection, toViewLineNumber, toViewVisualColumn); + return this.columnSelect(config, model, prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.fromViewVisualColumn, prevColumnSelectData.toViewLineNumber, toViewVisualColumn); } - public static columnSelectUp(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, isPaged: boolean, toViewLineNumber: number, toViewVisualColumn: number): IColumnSelectResult { - let linesCount = isPaged ? config.pageSize : 1; - - toViewLineNumber -= linesCount; - if (toViewLineNumber < 1) { - toViewLineNumber = 1; - } - - return this.columnSelect(config, model, cursor.selection, toViewLineNumber, toViewVisualColumn); + public static columnSelectUp(config: CursorConfiguration, model: ICursorSimpleModel, prevColumnSelectData: IColumnSelectData, isPaged: boolean): IColumnSelectResult { + const linesCount = isPaged ? config.pageSize : 1; + const toViewLineNumber = Math.max(1, prevColumnSelectData.toViewLineNumber - linesCount); + return this.columnSelect(config, model, prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.fromViewVisualColumn, toViewLineNumber, prevColumnSelectData.toViewVisualColumn); } - public static columnSelectDown(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, isPaged: boolean, toViewLineNumber: number, toViewVisualColumn: number): IColumnSelectResult { - let linesCount = isPaged ? config.pageSize : 1; - - toViewLineNumber += linesCount; - if (toViewLineNumber > model.getLineCount()) { - toViewLineNumber = model.getLineCount(); - } - - return this.columnSelect(config, model, cursor.selection, toViewLineNumber, toViewVisualColumn); + public static columnSelectDown(config: CursorConfiguration, model: ICursorSimpleModel, prevColumnSelectData: IColumnSelectData, isPaged: boolean): IColumnSelectResult { + const linesCount = isPaged ? config.pageSize : 1; + const toViewLineNumber = Math.min(model.getLineCount(), prevColumnSelectData.toViewLineNumber + linesCount); + return this.columnSelect(config, model, prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.fromViewVisualColumn, toViewLineNumber, prevColumnSelectData.toViewVisualColumn); } } diff --git a/src/vs/editor/common/controller/cursorCommon.ts b/src/vs/editor/common/controller/cursorCommon.ts index d6a64206e..844387516 100644 --- a/src/vs/editor/common/controller/cursorCommon.ts +++ b/src/vs/editor/common/controller/cursorCommon.ts @@ -21,6 +21,9 @@ import { VerticalRevealType } from 'vs/editor/common/view/viewEvents'; import { IViewModel } from 'vs/editor/common/viewModel/viewModel'; export interface IColumnSelectData { + isReal: boolean; + fromViewLineNumber: number; + fromViewVisualColumn: number; toViewLineNumber: number; toViewVisualColumn: number; } diff --git a/src/vs/editor/common/controller/cursorTypeOperations.ts b/src/vs/editor/common/controller/cursorTypeOperations.ts index c18d08137..73d984cfb 100644 --- a/src/vs/editor/common/controller/cursorTypeOperations.ts +++ b/src/vs/editor/common/controller/cursorTypeOperations.ts @@ -13,7 +13,7 @@ import { CursorColumns, CursorConfiguration, EditOperationResult, EditOperationT import { WordCharacterClass, getMapForWordSeparators } from 'vs/editor/common/controller/wordCharacterClassifier'; import { Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; -import { ICommand } from 'vs/editor/common/editorCommon'; +import { ICommand, ICursorStateComputerData } from 'vs/editor/common/editorCommon'; import { ITextModel } from 'vs/editor/common/model'; import { EnterAction, IndentAction } from 'vs/editor/common/modes/languageConfiguration'; import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; @@ -430,7 +430,7 @@ export class TypeOperations { return null; } - private static _isAutoClosingCloseCharType(config: CursorConfiguration, model: ITextModel, selections: Selection[], ch: string): boolean { + private static _isAutoClosingCloseCharType(config: CursorConfiguration, model: ITextModel, selections: Selection[], autoClosedCharacters: Range[], ch: string): boolean { const autoCloseConfig = isQuote(ch) ? config.autoClosingQuotes : config.autoClosingBrackets; if (autoCloseConfig === 'never' || !config.autoClosingPairsClose.hasOwnProperty(ch)) { @@ -461,6 +461,19 @@ export class TypeOperations { return false; } } + + // Must over-type a closing character typed by the editor + let found = false; + for (let j = 0, lenJ = autoClosedCharacters.length; j < lenJ; j++) { + const autoClosedCharacter = autoClosedCharacters[j]; + if (position.lineNumber === autoClosedCharacter.startLineNumber && position.column === autoClosedCharacter.startColumn) { + found = true; + break; + } + } + if (!found) { + return false; + } } return true; @@ -573,7 +586,7 @@ export class TypeOperations { for (let i = 0, len = selections.length; i < len; i++) { const selection = selections[i]; const closeCharacter = config.autoClosingPairsOpen[ch]; - commands[i] = new ReplaceCommandWithOffsetCursorState(selection, ch + closeCharacter, 0, -closeCharacter.length); + commands[i] = new TypeWithAutoClosingCommand(selection, ch, closeCharacter); } return new EditOperationResult(EditOperationType.Typing, commands, { shouldPushStackElementBefore: true, @@ -802,7 +815,7 @@ export class TypeOperations { }); } - public static typeWithInterceptors(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selections: Selection[], ch: string): EditOperationResult { + public static typeWithInterceptors(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selections: Selection[], autoClosedCharacters: Range[], ch: string): EditOperationResult { if (ch === '\n') { let commands: ICommand[] = []; @@ -833,7 +846,7 @@ export class TypeOperations { } } - if (this._isAutoClosingCloseCharType(config, model, selections, ch)) { + if (this._isAutoClosingCloseCharType(config, model, selections, autoClosedCharacters, ch)) { return this._runAutoClosingCloseCharType(prevEditOperationType, config, model, selections, ch); } @@ -923,3 +936,24 @@ export class TypeOperations { return commands; } } + +export class TypeWithAutoClosingCommand extends ReplaceCommandWithOffsetCursorState { + + private _closeCharacter: string; + public closeCharacterRange: Range | null; + public enclosingRange: Range | null; + + constructor(selection: Selection, openCharacter: string, closeCharacter: string) { + super(selection, openCharacter + closeCharacter, 0, -closeCharacter.length); + this._closeCharacter = closeCharacter; + this.closeCharacterRange = null; + } + + public computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection { + let inverseEditOperations = helper.getInverseEditOperations(); + let range = inverseEditOperations[0].range; + this.closeCharacterRange = new Range(range.startLineNumber, range.endColumn - this._closeCharacter.length, range.endLineNumber, range.endColumn); + this.enclosingRange = range; + return super.computeCursorState(model, helper); + } +} diff --git a/src/vs/editor/common/core/position.ts b/src/vs/editor/common/core/position.ts index 4c711e914..e9f64d97b 100644 --- a/src/vs/editor/common/core/position.ts +++ b/src/vs/editor/common/core/position.ts @@ -36,7 +36,7 @@ export class Position { } /** - * Create a new postion from this position. + * Create a new position from this position. * * @param newLineNumber new line number * @param newColumn new column diff --git a/src/vs/editor/common/core/range.ts b/src/vs/editor/common/core/range.ts index c84b5df9d..e212e757d 100644 --- a/src/vs/editor/common/core/range.ts +++ b/src/vs/editor/common/core/range.ts @@ -126,6 +126,32 @@ export class Range { return true; } + /** + * Test if `range` is strictly in this range. `range` must start after and end before this range for the result to be true. + */ + public strictContainsRange(range: IRange): boolean { + return Range.strictContainsRange(this, range); + } + + /** + * Test if `otherRange` is strinctly in `range` (must start after, and end before). If the ranges are equal, will return false. + */ + public static strictContainsRange(range: IRange, otherRange: IRange): boolean { + if (otherRange.startLineNumber < range.startLineNumber || otherRange.endLineNumber < range.startLineNumber) { + return false; + } + if (otherRange.startLineNumber > range.endLineNumber || otherRange.endLineNumber > range.endLineNumber) { + return false; + } + if (otherRange.startLineNumber === range.startLineNumber && otherRange.startColumn <= range.startColumn) { + return false; + } + if (otherRange.endLineNumber === range.endLineNumber && otherRange.endColumn >= range.endColumn) { + return false; + } + return true; + } + /** * A reunion of the two ranges. * The smallest position will be used as the start point, and the largest one as the end point. diff --git a/src/vs/editor/common/core/uint.ts b/src/vs/editor/common/core/uint.ts index d89c80435..00e3b8729 100644 --- a/src/vs/editor/common/core/uint.ts +++ b/src/vs/editor/common/core/uint.ts @@ -10,7 +10,7 @@ export class Uint8Matrix { public readonly cols: number; constructor(rows: number, cols: number, defaultValue: number) { - let data = new Uint8Array(rows * cols); + const data = new Uint8Array(rows * cols); for (let i = 0, len = rows * cols; i < len; i++) { data[i] = defaultValue; } @@ -85,8 +85,8 @@ export function toUint32(v: number): number { } export function toUint32Array(arr: number[]): Uint32Array { - let len = arr.length; - let r = new Uint32Array(len); + const len = arr.length; + const r = new Uint32Array(len); for (let i = 0; i < len; i++) { r[i] = toUint32(arr[i]); } diff --git a/src/vs/editor/common/model.ts b/src/vs/editor/common/model.ts index ebc34ca22..3037589c7 100644 --- a/src/vs/editor/common/model.ts +++ b/src/vs/editor/common/model.ts @@ -14,6 +14,7 @@ import { IModelContentChange, IModelContentChangedEvent, IModelDecorationsChange import { SearchData } from 'vs/editor/common/model/textModelSearch'; import { LanguageId, LanguageIdentifier, FormattingOptions } from 'vs/editor/common/modes'; import { ThemeColor } from 'vs/platform/theme/common/themeService'; +import { MultilineTokens } from 'vs/editor/common/model/tokensStore'; /** * Vertical Lane in the overview ruler of the editor. @@ -26,25 +27,45 @@ export enum OverviewRulerLane { } /** - * Options for rendering a model decoration in the overview ruler. + * Position in the minimap to render the decoration. */ -export interface IModelDecorationOverviewRulerOptions { +export enum MinimapPosition { + Inline = 1 +} + +export interface IDecorationOptions { /** - * CSS color to render in the overview ruler. + * CSS color to render. * e.g.: rgba(100, 100, 100, 0.5) or a color from the color registry */ color: string | ThemeColor | undefined; /** - * CSS color to render in the overview ruler. + * CSS color to render. * e.g.: rgba(100, 100, 100, 0.5) or a color from the color registry */ darkColor?: string | ThemeColor; +} + +/** + * Options for rendering a model decoration in the overview ruler. + */ +export interface IModelDecorationOverviewRulerOptions extends IDecorationOptions { /** * The position in the overview ruler. */ position: OverviewRulerLane; } +/** + * Options for rendering a model decoration in the overview ruler. + */ +export interface IModelDecorationMinimapOptions extends IDecorationOptions { + /** + * The position in the overview ruler. + */ + position: MinimapPosition; +} + /** * Options for a model decoration. */ @@ -89,6 +110,10 @@ export interface IModelDecorationOptions { * If set, render this decoration in the overview ruler. */ overviewRuler?: IModelDecorationOverviewRulerOptions | null; + /** + * If set, render this decoration in the minimap. + */ + minimap?: IModelDecorationMinimapOptions | null; /** * If set, the decoration will be rendered in the glyph margin with this CSS class name. */ @@ -755,11 +780,16 @@ export interface ITextModel { */ findPreviousMatch(searchString: string, searchStart: IPosition, isRegex: boolean, matchCase: boolean, wordSeparators: string | null, captureMatches: boolean): FindMatch | null; + /** + * @internal + */ + setTokens(tokens: MultilineTokens[]): void; + /** * Flush all tokenization state. * @internal */ - flushTokens(): void; + resetTokenization(): void; /** * Force tokenization information for `lineNumber` to be accurate. @@ -1092,6 +1122,12 @@ export interface ITextModel { * @internal */ onDidChangeTokens(listener: (e: IModelTokensChangedEvent) => void): IDisposable; + /** + * An event emitted when the model has been attached to the first editor or detached from the last editor. + * @event + * @internal + */ + onDidChangeAttached(listener: () => void): IDisposable; /** * An event emitted right before disposing the model. * @event diff --git a/src/vs/editor/common/model/indentationGuesser.ts b/src/vs/editor/common/model/indentationGuesser.ts index e5fc19ba1..24c449c60 100644 --- a/src/vs/editor/common/model/indentationGuesser.ts +++ b/src/vs/editor/common/model/indentationGuesser.ts @@ -177,22 +177,26 @@ export function guessIndentation(source: ITextBuffer, defaultTabSize: number, de } let tabSize = defaultTabSize; - let tabSizeScore = (insertSpaces ? 0 : 0.1 * linesCount); - // console.log("score threshold: " + tabSizeScore); + // Guess tabSize only if inserting spaces... + if (insertSpaces) { + let tabSizeScore = (insertSpaces ? 0 : 0.1 * linesCount); - ALLOWED_TAB_SIZE_GUESSES.forEach((possibleTabSize) => { - let possibleTabSizeScore = spacesDiffCount[possibleTabSize]; - if (possibleTabSizeScore > tabSizeScore) { - tabSizeScore = possibleTabSizeScore; - tabSize = possibleTabSize; - } - }); + // console.log("score threshold: " + tabSizeScore); + + ALLOWED_TAB_SIZE_GUESSES.forEach((possibleTabSize) => { + let possibleTabSizeScore = spacesDiffCount[possibleTabSize]; + if (possibleTabSizeScore > tabSizeScore) { + tabSizeScore = possibleTabSizeScore; + tabSize = possibleTabSize; + } + }); - // Let a tabSize of 2 win even if it is not the maximum - // (only in case 4 was guessed) - if (tabSize === 4 && spacesDiffCount[4] > 0 && spacesDiffCount[2] > 0 && spacesDiffCount[2] >= spacesDiffCount[4] / 2) { - tabSize = 2; + // Let a tabSize of 2 win even if it is not the maximum + // (only in case 4 was guessed) + if (tabSize === 4 && spacesDiffCount[4] > 0 && spacesDiffCount[2] > 0 && spacesDiffCount[2] >= spacesDiffCount[4] / 2) { + tabSize = 2; + } } diff --git a/src/vs/editor/common/model/intervalTree.ts b/src/vs/editor/common/model/intervalTree.ts index 496e77b9e..d400024e7 100644 --- a/src/vs/editor/common/model/intervalTree.ts +++ b/src/vs/editor/common/model/intervalTree.ts @@ -17,7 +17,8 @@ export const enum ClassName { EditorWarningDecoration = 'squiggly-warning', EditorErrorDecoration = 'squiggly-error', EditorUnnecessaryDecoration = 'squiggly-unnecessary', - EditorUnnecessaryInlineDecoration = 'squiggly-inline-unnecessary' + EditorUnnecessaryInlineDecoration = 'squiggly-inline-unnecessary', + EditorDeprecatedInlineDecoration = 'squiggly-inline-deprecated' } export const enum NodeColor { diff --git a/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase.ts b/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase.ts index 04de0bc01..445ddde97 100644 --- a/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase.ts +++ b/src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase.ts @@ -611,25 +611,25 @@ export class PieceTreeBase { let resultLen = 0; const searcher = new Searcher(searchData.wordSeparators, searchData.regex); - let startPostion = this.nodeAt2(searchRange.startLineNumber, searchRange.startColumn); - if (startPostion === null) { + let startPosition = this.nodeAt2(searchRange.startLineNumber, searchRange.startColumn); + if (startPosition === null) { return []; } let endPosition = this.nodeAt2(searchRange.endLineNumber, searchRange.endColumn); if (endPosition === null) { return []; } - let start = this.positionInBuffer(startPostion.node, startPostion.remainder); + let start = this.positionInBuffer(startPosition.node, startPosition.remainder); let end = this.positionInBuffer(endPosition.node, endPosition.remainder); - if (startPostion.node === endPosition.node) { - this.findMatchesInNode(startPostion.node, searcher, searchRange.startLineNumber, searchRange.startColumn, start, end, searchData, captureMatches, limitResultCount, resultLen, result); + if (startPosition.node === endPosition.node) { + this.findMatchesInNode(startPosition.node, searcher, searchRange.startLineNumber, searchRange.startColumn, start, end, searchData, captureMatches, limitResultCount, resultLen, result); return result; } let startLineNumber = searchRange.startLineNumber; - let currentNode = startPostion.node; + let currentNode = startPosition.node; while (currentNode !== endPosition.node) { let lineBreakCnt = this.getLineFeedCnt(currentNode.piece.bufferIndex, start, currentNode.piece.end); @@ -663,9 +663,9 @@ export class PieceTreeBase { } startLineNumber++; - startPostion = this.nodeAt2(startLineNumber, 1); - currentNode = startPostion.node; - start = this.positionInBuffer(startPostion.node, startPostion.remainder); + startPosition = this.nodeAt2(startLineNumber, 1); + currentNode = startPosition.node; + start = this.positionInBuffer(startPosition.node, startPosition.remainder); } if (startLineNumber === searchRange.endLineNumber) { diff --git a/src/vs/editor/common/model/textModel.ts b/src/vs/editor/common/model/textModel.ts index 2a640ac9d..e73183b0b 100644 --- a/src/vs/editor/common/model/textModel.ts +++ b/src/vs/editor/common/model/textModel.ts @@ -8,7 +8,6 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; import { IMarkdownString } from 'vs/base/common/htmlContent'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; -import { StopWatch } from 'vs/base/common/stopwatch'; import * as strings from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; import { EDITOR_MODEL_DEFAULTS } from 'vs/editor/common/config/editorOptions'; @@ -23,9 +22,9 @@ import { IntervalNode, IntervalTree, getNodeIsInOverviewRuler, recomputeMaxEnd } import { PieceTreeTextBufferBuilder } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBufferBuilder'; import { IModelContentChangedEvent, IModelDecorationsChangedEvent, IModelLanguageChangedEvent, IModelLanguageConfigurationChangedEvent, IModelOptionsChangedEvent, IModelTokensChangedEvent, InternalModelContentChangeEvent, ModelRawChange, ModelRawContentChangedEvent, ModelRawEOLChanged, ModelRawFlush, ModelRawLineChanged, ModelRawLinesDeleted, ModelRawLinesInserted } from 'vs/editor/common/model/textModelEvents'; import { SearchData, SearchParams, TextModelSearch } from 'vs/editor/common/model/textModelSearch'; -import { ModelLinesTokens, ModelTokensChangedEventBuilder } from 'vs/editor/common/model/textModelTokens'; +import { TextModelTokenization } from 'vs/editor/common/model/textModelTokens'; import { getWordAtText } from 'vs/editor/common/model/wordHelper'; -import { IState, LanguageId, LanguageIdentifier, TokenizationRegistry, FormattingOptions } from 'vs/editor/common/modes'; +import { LanguageId, LanguageIdentifier, FormattingOptions } from 'vs/editor/common/modes'; import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; import { NULL_LANGUAGE_IDENTIFIER } from 'vs/editor/common/modes/nullMode'; import { ignoreBracketsInToken } from 'vs/editor/common/modes/supports'; @@ -33,8 +32,8 @@ import { BracketsUtils, RichEditBracket, RichEditBrackets } from 'vs/editor/comm import { ITheme, ThemeColor } from 'vs/platform/theme/common/themeService'; import { withUndefinedAsNull } from 'vs/base/common/types'; import { VSBufferReadableStream, VSBuffer } from 'vs/base/common/buffer'; - -const CHEAP_TOKENIZATION_LENGTH_LIMIT = 2048; +import { TokensStore, MultilineTokens, countEOL } from 'vs/editor/common/model/tokensStore'; +import { Color } from 'vs/base/common/color'; function createTextBufferBuilder() { return new PieceTreeTextBufferBuilder(); @@ -235,6 +234,9 @@ export class TextModel extends Disposable implements model.ITextModel { private readonly _onDidChangeOptions: Emitter = this._register(new Emitter()); public readonly onDidChangeOptions: Event = this._onDidChangeOptions.event; + private readonly _onDidChangeAttached: Emitter = this._register(new Emitter()); + public readonly onDidChangeAttached: Event = this._onDidChangeAttached.event; + private readonly _eventEmitter: DidChangeContentEmitter = this._register(new DidChangeContentEmitter()); public onDidChangeRawContentFast(listener: (e: ModelRawContentChangedEvent) => void): IDisposable { return this._eventEmitter.fastEvent((e: InternalModelContentChangeEvent) => listener(e.rawContentChangedEvent)); @@ -242,6 +244,9 @@ export class TextModel extends Disposable implements model.ITextModel { public onDidChangeRawContent(listener: (e: ModelRawContentChangedEvent) => void): IDisposable { return this._eventEmitter.slowEvent((e: InternalModelContentChangeEvent) => listener(e.rawContentChangedEvent)); } + public onDidChangeContentFast(listener: (e: IModelContentChangedEvent) => void): IDisposable { + return this._eventEmitter.fastEvent((e: InternalModelContentChangeEvent) => listener(e.contentChangedEvent)); + } public onDidChangeContent(listener: (e: IModelContentChangedEvent) => void): IDisposable { return this._eventEmitter.slowEvent((e: InternalModelContentChangeEvent) => listener(e.contentChangedEvent)); } @@ -284,10 +289,9 @@ export class TextModel extends Disposable implements model.ITextModel { //#region Tokenization private _languageIdentifier: LanguageIdentifier; - private readonly _tokenizationListener: IDisposable; private readonly _languageRegistryListener: IDisposable; - private _revalidateTokensTimeout: any; - /*private*/_tokens: ModelLinesTokens; + private readonly _tokens: TokensStore; + private readonly _tokenization: TextModelTokenization; //#endregion constructor(source: string | model.ITextBufferFactory, creationOptions: model.ITextModelCreationOptions, languageIdentifier: LanguageIdentifier | null, associatedResource: URI | null = null) { @@ -330,31 +334,12 @@ export class TextModel extends Disposable implements model.ITextModel { this._isDisposing = false; this._languageIdentifier = languageIdentifier || NULL_LANGUAGE_IDENTIFIER; - this._tokenizationListener = TokenizationRegistry.onDidChange((e) => { - if (e.changedLanguages.indexOf(this._languageIdentifier.language) === -1) { - return; - } - - this._resetTokenizationState(); - this.emitModelTokensChangedEvent({ - tokenizationSupportChanged: true, - ranges: [{ - fromLineNumber: 1, - toLineNumber: this.getLineCount() - }] - }); - if (this._shouldAutoTokenize()) { - this._warmUpTokens(); - } - }); - this._revalidateTokensTimeout = -1; this._languageRegistryListener = LanguageConfigurationRegistry.onDidChange((e) => { if (e.languageIdentifier.id === this._languageIdentifier.id) { this._onDidChangeLanguageConfiguration.fire({}); } }); - this._resetTokenizationState(); this._instanceId = singleLetter(MODEL_ID); this._lastDecorationId = 0; @@ -365,16 +350,17 @@ export class TextModel extends Disposable implements model.ITextModel { this._isUndoing = false; this._isRedoing = false; this._trimAutoWhitespaceLines = null; + + this._tokens = new TokensStore(); + this._tokenization = new TextModelTokenization(this); } public dispose(): void { this._isDisposing = true; this._onWillDispose.fire(); - this._tokenizationListener.dispose(); this._languageRegistryListener.dispose(); - this._clearTimers(); + this._tokenization.dispose(); this._isDisposed = true; - // Null out members, such that any use of a disposed model will throw exceptions sooner rather than later super.dispose(); this._isDisposing = false; } @@ -439,8 +425,8 @@ export class TextModel extends Disposable implements model.ITextModel { this._buffer = textBuffer; this._increaseVersionId(); - // Cancel tokenization, clear all tokens and begin tokenizing - this._resetTokenizationState(); + // Flush all tokens + this._tokens.flush(); // Destroy all my decorations this._decorations = Object.create(null); @@ -524,36 +510,18 @@ export class TextModel extends Disposable implements model.ITextModel { } } - private _resetTokenizationState(): void { - this._clearTimers(); - let tokenizationSupport = ( - this._isTooLargeForTokenization - ? null - : TokenizationRegistry.get(this._languageIdentifier.language) - ); - this._tokens = new ModelLinesTokens(this._languageIdentifier, tokenizationSupport); - this._beginBackgroundTokenization(); - } - - private _clearTimers(): void { - if (this._revalidateTokensTimeout !== -1) { - clearTimeout(this._revalidateTokensTimeout); - this._revalidateTokensTimeout = -1; - } - } - public onBeforeAttached(): void { this._attachedEditorCount++; - // Warm up tokens for the editor - this._warmUpTokens(); + if (this._attachedEditorCount === 1) { + this._onDidChangeAttached.fire(undefined); + } } public onBeforeDetached(): void { this._attachedEditorCount--; - } - - private _shouldAutoTokenize(): boolean { - return this.isAttachedToEditor(); + if (this._attachedEditorCount === 0) { + this._onDidChangeAttached.fire(undefined); + } } public isAttachedToEditor(): boolean { @@ -1292,36 +1260,6 @@ export class TextModel extends Disposable implements model.ITextModel { } } - private static _eolCount(text: string): [number, number] { - let eolCount = 0; - let firstLineLength = 0; - for (let i = 0, len = text.length; i < len; i++) { - const chr = text.charCodeAt(i); - - if (chr === CharCode.CarriageReturn) { - if (eolCount === 0) { - firstLineLength = i; - } - eolCount++; - if (i + 1 < len && text.charCodeAt(i + 1) === CharCode.LineFeed) { - // \r\n... case - i++; // skip \n - } else { - // \r... case - } - } else if (chr === CharCode.LineFeed) { - if (eolCount === 0) { - firstLineLength = i; - } - eolCount++; - } - } - if (eolCount === 0) { - firstLineLength = text.length; - } - return [eolCount, firstLineLength]; - } - private _applyEdits(rawOperations: model.IIdentifiedSingleEditOperation[]): model.IIdentifiedSingleEditOperation[] { for (let i = 0, len = rawOperations.length; i < len; i++) { rawOperations[i].range = this.validateRange(rawOperations[i].range); @@ -1340,13 +1278,8 @@ export class TextModel extends Disposable implements model.ITextModel { let lineCount = oldLineCount; for (let i = 0, len = contentChanges.length; i < len; i++) { const change = contentChanges[i]; - const [eolCount, firstLineLength] = TextModel._eolCount(change.text); - try { - this._tokens.applyEdits(change.range, eolCount, firstLineLength); - } catch (err) { - // emergency recovery => reset tokens - this._tokens = new ModelLinesTokens(this._tokens.languageIdentifier, this._tokens.tokenizationSupport); - } + const [eolCount, firstLineLength] = countEOL(change.text); + this._tokens.acceptEdit(change.range, eolCount, firstLineLength); this._onDidChangeDecorations.fire(); this._decorationsTree.acceptReplace(change.rangeOffset, change.rangeLength, change.text.length, change.forceMoveMarkers); @@ -1407,10 +1340,6 @@ export class TextModel extends Disposable implements model.ITextModel { ); } - if (this._tokens.hasLinesToTokenize(this._buffer)) { - this._beginBackgroundTokenization(); - } - return result.reverseEdits; } @@ -1775,124 +1704,72 @@ export class TextModel extends Disposable implements model.ITextModel { //#region Tokenization - public tokenizeViewport(startLineNumber: number, endLineNumber: number): void { - if (!this._tokens.tokenizationSupport) { - // nothing to do - return; + public setLineTokens(lineNumber: number, tokens: Uint32Array | ArrayBuffer | null): void { + if (lineNumber < 1 || lineNumber > this.getLineCount()) { + throw new Error('Illegal value for lineNumber'); } - startLineNumber = Math.max(1, startLineNumber); - endLineNumber = Math.min(this.getLineCount(), endLineNumber); - - if (endLineNumber <= this._tokens.inValidLineStartIndex) { - // nothing to do - return; - } + this._tokens.setTokens(this._languageIdentifier.id, lineNumber - 1, this._buffer.getLineLength(lineNumber), tokens); + } - if (startLineNumber <= this._tokens.inValidLineStartIndex) { - // tokenization has reached the viewport start... - this.forceTokenization(endLineNumber); + public setTokens(tokens: MultilineTokens[]): void { + if (tokens.length === 0) { return; } - let nonWhitespaceColumn = this.getLineFirstNonWhitespaceColumn(startLineNumber); - let fakeLines: string[] = []; - let initialState: IState | null = null; - for (let i = startLineNumber - 1; nonWhitespaceColumn > 0 && i >= 1; i--) { - let newNonWhitespaceIndex = this.getLineFirstNonWhitespaceColumn(i); - - if (newNonWhitespaceIndex === 0) { - continue; - } + let ranges: { fromLineNumber: number; toLineNumber: number; }[] = []; - if (newNonWhitespaceIndex < nonWhitespaceColumn) { - initialState = this._tokens._getState(i - 1); - if (initialState) { - break; - } - fakeLines.push(this.getLineContent(i)); - nonWhitespaceColumn = newNonWhitespaceIndex; + for (let i = 0, len = tokens.length; i < len; i++) { + const element = tokens[i]; + ranges.push({ fromLineNumber: element.startLineNumber, toLineNumber: element.startLineNumber + element.tokens.length - 1 }); + for (let j = 0, lenJ = element.tokens.length; j < lenJ; j++) { + this.setLineTokens(element.startLineNumber + j, element.tokens[j]); } } - if (!initialState) { - initialState = this._tokens.tokenizationSupport.getInitialState(); - } - - let state = initialState.clone(); - for (let i = fakeLines.length - 1; i >= 0; i--) { - let r = this._tokens._tokenizeText(this._buffer, fakeLines[i], state); - if (r) { - state = r.endState.clone(); - } else { - state = initialState.clone(); - } - } - - const eventBuilder = new ModelTokensChangedEventBuilder(); - for (let i = startLineNumber; i <= endLineNumber; i++) { - let text = this.getLineContent(i); - let r = this._tokens._tokenizeText(this._buffer, text, state); - if (r) { - this._tokens._setTokens(this._tokens.languageIdentifier.id, i - 1, text.length, r.tokens); - - // We cannot trust these states/tokens to be valid! - // (see https://github.com/Microsoft/vscode/issues/67607) - this._tokens._setIsInvalid(i - 1, true); - this._tokens._setState(i - 1, state); - state = r.endState.clone(); - eventBuilder.registerChangedTokens(i); - } else { - state = initialState.clone(); - } - } + this._emitModelTokensChangedEvent({ + tokenizationSupportChanged: false, + ranges: ranges + }); + } - const e = eventBuilder.build(); - if (e) { - this._onDidChangeTokens.fire(e); - } + public tokenizeViewport(startLineNumber: number, endLineNumber: number): void { + startLineNumber = Math.max(1, startLineNumber); + endLineNumber = Math.min(this._buffer.getLineCount(), endLineNumber); + this._tokenization.tokenizeViewport(startLineNumber, endLineNumber); } - public flushTokens(): void { - this._resetTokenizationState(); - this.emitModelTokensChangedEvent({ - tokenizationSupportChanged: false, + public clearTokens(): void { + this._tokens.flush(); + this._emitModelTokensChangedEvent({ + tokenizationSupportChanged: true, ranges: [{ fromLineNumber: 1, - toLineNumber: this.getLineCount() + toLineNumber: this._buffer.getLineCount() }] }); } - public forceTokenization(lineNumber: number): void { - if (lineNumber < 1 || lineNumber > this.getLineCount()) { - throw new Error('Illegal value for lineNumber'); - } - - const eventBuilder = new ModelTokensChangedEventBuilder(); - - this._tokens._updateTokensUntilLine(this._buffer, eventBuilder, lineNumber); - - const e = eventBuilder.build(); - if (e) { + private _emitModelTokensChangedEvent(e: IModelTokensChangedEvent): void { + if (!this._isDisposing) { this._onDidChangeTokens.fire(e); } } - public isCheapToTokenize(lineNumber: number): boolean { - if (!this._tokens.isCheapToTokenize(lineNumber)) { - return false; - } + public resetTokenization(): void { + this._tokenization.reset(); + } - if (lineNumber < this._tokens.inValidLineStartIndex + 1) { - return true; + public forceTokenization(lineNumber: number): void { + if (lineNumber < 1 || lineNumber > this.getLineCount()) { + throw new Error('Illegal value for lineNumber'); } - if (this.getLineLength(lineNumber) < CHEAP_TOKENIZATION_LENGTH_LIMIT) { - return true; - } + this._tokenization.forceTokenization(lineNumber); + } - return false; + public isCheapToTokenize(lineNumber: number): boolean { + return this._tokenization.isCheapToTokenize(lineNumber); } public tokenizeIfCheap(lineNumber: number): void { @@ -1910,7 +1787,7 @@ export class TextModel extends Disposable implements model.ITextModel { } private _getLineTokens(lineNumber: number): LineTokens { - const lineText = this._buffer.getLineContent(lineNumber); + const lineText = this.getLineContent(lineNumber); return this._tokens.getTokens(this._languageIdentifier.id, lineNumber - 1, lineText); } @@ -1935,81 +1812,14 @@ export class TextModel extends Disposable implements model.ITextModel { this._languageIdentifier = languageIdentifier; - // Cancel tokenization, clear all tokens and begin tokenizing - this._resetTokenizationState(); - - this.emitModelTokensChangedEvent({ - tokenizationSupportChanged: true, - ranges: [{ - fromLineNumber: 1, - toLineNumber: this.getLineCount() - }] - }); this._onDidChangeLanguage.fire(e); this._onDidChangeLanguageConfiguration.fire({}); } - public getLanguageIdAtPosition(_lineNumber: number, _column: number): LanguageId { - if (!this._tokens.tokenizationSupport) { - return this._languageIdentifier.id; - } - let { lineNumber, column } = this.validatePosition({ lineNumber: _lineNumber, column: _column }); - - let lineTokens = this._getLineTokens(lineNumber); - return lineTokens.getLanguageId(lineTokens.findTokenIndexAtOffset(column - 1)); - } - - private _beginBackgroundTokenization(): void { - if (this._shouldAutoTokenize() && this._revalidateTokensTimeout === -1) { - this._revalidateTokensTimeout = setTimeout(() => { - this._revalidateTokensTimeout = -1; - this._revalidateTokensNow(); - }, 0); - } - } - - _warmUpTokens(): void { - // Warm up first 100 lines (if it takes less than 50ms) - const maxLineNumber = Math.min(100, this.getLineCount()); - this._revalidateTokensNow(maxLineNumber); - - if (this._tokens.hasLinesToTokenize(this._buffer)) { - this._beginBackgroundTokenization(); - } - } - - private _revalidateTokensNow(toLineNumber: number = this._buffer.getLineCount()): void { - const MAX_ALLOWED_TIME = 20; - const eventBuilder = new ModelTokensChangedEventBuilder(); - const sw = StopWatch.create(false); - - while (this._tokens.hasLinesToTokenize(this._buffer)) { - if (sw.elapsed() > MAX_ALLOWED_TIME) { - // Stop if MAX_ALLOWED_TIME is reached - break; - } - - const tokenizedLineNumber = this._tokens._tokenizeOneLine(this._buffer, eventBuilder); - - if (tokenizedLineNumber >= toLineNumber) { - break; - } - } - - if (this._tokens.hasLinesToTokenize(this._buffer)) { - this._beginBackgroundTokenization(); - } - - const e = eventBuilder.build(); - if (e) { - this._onDidChangeTokens.fire(e); - } - } - - private emitModelTokensChangedEvent(e: IModelTokensChangedEvent): void { - if (!this._isDisposing) { - this._onDidChangeTokens.fire(e); - } + public getLanguageIdAtPosition(lineNumber: number, column: number): LanguageId { + const position = this.validatePosition(new Position(lineNumber, column)); + const lineTokens = this.getLineTokens(position.lineNumber); + return lineTokens.getLanguageId(lineTokens.findTokenIndexAtOffset(position.column - 1)); } // Having tokens allows implementing additional helper methods @@ -2823,17 +2633,25 @@ function cleanClassName(className: string): string { return className.replace(/[^a-z0-9\-_]/gi, ' '); } -export class ModelDecorationOverviewRulerOptions implements model.IModelDecorationOverviewRulerOptions { +class DecorationOptions implements model.IDecorationOptions { readonly color: string | ThemeColor; readonly darkColor: string | ThemeColor; + + constructor(options: model.IDecorationOptions) { + this.color = options.color || strings.empty; + this.darkColor = options.darkColor || strings.empty; + + } +} + +export class ModelDecorationOverviewRulerOptions extends DecorationOptions { readonly position: model.OverviewRulerLane; private _resolvedColor: string | null; constructor(options: model.IModelDecorationOverviewRulerOptions) { - this.color = options.color || strings.empty; - this.darkColor = options.darkColor || strings.empty; - this.position = (typeof options.position === 'number' ? options.position : model.OverviewRulerLane.Center); + super(options); this._resolvedColor = null; + this.position = (typeof options.position === 'number' ? options.position : model.OverviewRulerLane.Center); } public getColor(theme: ITheme): string { @@ -2863,6 +2681,40 @@ export class ModelDecorationOverviewRulerOptions implements model.IModelDecorati } } +export class ModelDecorationMinimapOptions extends DecorationOptions { + readonly position: model.MinimapPosition; + private _resolvedColor: Color | undefined; + + + constructor(options: model.IModelDecorationMinimapOptions) { + super(options); + this.position = options.position; + } + + public getColor(theme: ITheme): Color | undefined { + if (!this._resolvedColor) { + if (theme.type !== 'light' && this.darkColor) { + this._resolvedColor = this._resolveColor(this.darkColor, theme); + } else { + this._resolvedColor = this._resolveColor(this.color, theme); + } + } + + return this._resolvedColor; + } + + public invalidateCachedColor(): void { + this._resolvedColor = undefined; + } + + private _resolveColor(color: string | ThemeColor, theme: ITheme): Color | undefined { + if (typeof color === 'string') { + return Color.fromHex(color); + } + return theme.getColor(color.id); + } +} + export class ModelDecorationOptions implements model.IModelDecorationOptions { public static EMPTY: ModelDecorationOptions; @@ -2884,6 +2736,7 @@ export class ModelDecorationOptions implements model.IModelDecorationOptions { readonly showIfCollapsed: boolean; readonly collapseOnReplaceEdit: boolean; readonly overviewRuler: ModelDecorationOverviewRulerOptions | null; + readonly minimap: ModelDecorationMinimapOptions | null; readonly glyphMarginClassName: string | null; readonly linesDecorationsClassName: string | null; readonly marginClassName: string | null; @@ -2902,6 +2755,7 @@ export class ModelDecorationOptions implements model.IModelDecorationOptions { this.showIfCollapsed = options.showIfCollapsed || false; this.collapseOnReplaceEdit = options.collapseOnReplaceEdit || false; this.overviewRuler = options.overviewRuler ? new ModelDecorationOverviewRulerOptions(options.overviewRuler) : null; + this.minimap = options.minimap ? new ModelDecorationMinimapOptions(options.minimap) : null; this.glyphMarginClassName = options.glyphMarginClassName ? cleanClassName(options.glyphMarginClassName) : null; this.linesDecorationsClassName = options.linesDecorationsClassName ? cleanClassName(options.linesDecorationsClassName) : null; this.marginClassName = options.marginClassName ? cleanClassName(options.marginClassName) : null; diff --git a/src/vs/editor/common/model/textModelSearch.ts b/src/vs/editor/common/model/textModelSearch.ts index 1b63ef93f..ec2bb71ec 100644 --- a/src/vs/editor/common/model/textModelSearch.ts +++ b/src/vs/editor/common/model/textModelSearch.ts @@ -545,6 +545,12 @@ export class Searcher { const matchStartIndex = m.index; const matchLength = m[0].length; if (matchStartIndex === this._prevMatchStartIndex && matchLength === this._prevMatchLength) { + if (matchLength === 0) { + // the search result is an empty string and won't advance `regex.lastIndex`, so `regex.exec` will stuck here + // we attempt to recover from that by advancing by one + this._searchRegex.lastIndex += 1; + continue; + } // Exit early if the regex matches the same range twice return null; } diff --git a/src/vs/editor/common/model/textModelTokens.ts b/src/vs/editor/common/model/textModelTokens.ts index 8387872c1..076b142db 100644 --- a/src/vs/editor/common/model/textModelTokens.ts +++ b/src/vs/editor/common/model/textModelTokens.ts @@ -7,501 +7,458 @@ import * as arrays from 'vs/base/common/arrays'; import { onUnexpectedError } from 'vs/base/common/errors'; import { LineTokens } from 'vs/editor/common/core/lineTokens'; import { Position } from 'vs/editor/common/core/position'; -import { Range } from 'vs/editor/common/core/range'; +import { IRange } from 'vs/editor/common/core/range'; import { TokenizationResult2 } from 'vs/editor/common/core/token'; -import { ITextBuffer } from 'vs/editor/common/model'; -import { IModelTokensChangedEvent } from 'vs/editor/common/model/textModelEvents'; -import { ColorId, FontStyle, IState, ITokenizationSupport, LanguageId, LanguageIdentifier, MetadataConsts, StandardTokenType, TokenMetadata } from 'vs/editor/common/modes'; +import { RawContentChangedType } from 'vs/editor/common/model/textModelEvents'; +import { IState, ITokenizationSupport, LanguageIdentifier, TokenizationRegistry } from 'vs/editor/common/modes'; import { nullTokenize2 } from 'vs/editor/common/modes/nullMode'; +import { TextModel } from 'vs/editor/common/model/textModel'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { StopWatch } from 'vs/base/common/stopwatch'; +import { MultilineTokensBuilder, countEOL } from 'vs/editor/common/model/tokensStore'; -function getDefaultMetadata(topLevelLanguageId: LanguageId): number { - return ( - (topLevelLanguageId << MetadataConsts.LANGUAGEID_OFFSET) - | (StandardTokenType.Other << MetadataConsts.TOKEN_TYPE_OFFSET) - | (FontStyle.None << MetadataConsts.FONT_STYLE_OFFSET) - | (ColorId.DefaultForeground << MetadataConsts.FOREGROUND_OFFSET) - | (ColorId.DefaultBackground << MetadataConsts.BACKGROUND_OFFSET) - ) >>> 0; +const enum Constants { + CHEAP_TOKENIZATION_LENGTH_LIMIT = 2048 } -const EMPTY_LINE_TOKENS = (new Uint32Array(0)).buffer; - -class ModelLineTokens { - _state: IState | null; - _lineTokens: ArrayBuffer | null; - _invalid: boolean; +export class TokenizationStateStore { + private _beginState: (IState | null)[]; + private _valid: boolean[]; + private _len: number; + private _invalidLineStartIndex: number; - constructor(state: IState | null) { - this._state = state; - this._lineTokens = null; - this._invalid = true; + constructor() { + this._reset(null); } - public deleteBeginning(toChIndex: number): void { - if (this._lineTokens === null || this._lineTokens === EMPTY_LINE_TOKENS) { - return; + private _reset(initialState: IState | null): void { + this._beginState = []; + this._valid = []; + this._len = 0; + this._invalidLineStartIndex = 0; + + if (initialState) { + this._setBeginState(0, initialState); } - this.delete(0, toChIndex); } - public deleteEnding(fromChIndex: number): void { - if (this._lineTokens === null || this._lineTokens === EMPTY_LINE_TOKENS) { - return; - } + public flush(initialState: IState | null): void { + this._reset(initialState); + } - const tokens = new Uint32Array(this._lineTokens); - const lineTextLength = tokens[tokens.length - 2]; - this.delete(fromChIndex, lineTextLength); + public get invalidLineStartIndex() { + return this._invalidLineStartIndex; } - public delete(fromChIndex: number, toChIndex: number): void { - if (this._lineTokens === null || this._lineTokens === EMPTY_LINE_TOKENS || fromChIndex === toChIndex) { - return; + private _invalidateLine(lineIndex: number): void { + if (lineIndex < this._len) { + this._valid[lineIndex] = false; } - const tokens = new Uint32Array(this._lineTokens); - const tokensCount = (tokens.length >>> 1); - - // special case: deleting everything - if (fromChIndex === 0 && tokens[tokens.length - 2] === toChIndex) { - this._lineTokens = EMPTY_LINE_TOKENS; - return; + if (lineIndex < this._invalidLineStartIndex) { + this._invalidLineStartIndex = lineIndex; } + } - const fromTokenIndex = LineTokens.findIndexInTokensArray(tokens, fromChIndex); - const fromTokenStartOffset = (fromTokenIndex > 0 ? tokens[(fromTokenIndex - 1) << 1] : 0); - const fromTokenEndOffset = tokens[fromTokenIndex << 1]; - - if (toChIndex < fromTokenEndOffset) { - // the delete range is inside a single token - const delta = (toChIndex - fromChIndex); - for (let i = fromTokenIndex; i < tokensCount; i++) { - tokens[i << 1] -= delta; - } - return; + private _isValid(lineIndex: number): boolean { + if (lineIndex < this._len) { + return this._valid[lineIndex]; } + return false; + } - let dest: number; - let lastEnd: number; - if (fromTokenStartOffset !== fromChIndex) { - tokens[fromTokenIndex << 1] = fromChIndex; - dest = ((fromTokenIndex + 1) << 1); - lastEnd = fromChIndex; - } else { - dest = (fromTokenIndex << 1); - lastEnd = fromTokenStartOffset; - } - - const delta = (toChIndex - fromChIndex); - for (let tokenIndex = fromTokenIndex + 1; tokenIndex < tokensCount; tokenIndex++) { - const tokenEndOffset = tokens[tokenIndex << 1] - delta; - if (tokenEndOffset > lastEnd) { - tokens[dest++] = tokenEndOffset; - tokens[dest++] = tokens[(tokenIndex << 1) + 1]; - lastEnd = tokenEndOffset; - } + public getBeginState(lineIndex: number): IState | null { + if (lineIndex < this._len) { + return this._beginState[lineIndex]; } + return null; + } - if (dest === tokens.length) { - // nothing to trim - return; + private _ensureLine(lineIndex: number): void { + while (lineIndex >= this._len) { + this._beginState[this._len] = null; + this._valid[this._len] = false; + this._len++; } - - let tmp = new Uint32Array(dest); - tmp.set(tokens.subarray(0, dest), 0); - this._lineTokens = tmp.buffer; } - public append(_otherTokens: ArrayBuffer | null): void { - if (_otherTokens === EMPTY_LINE_TOKENS) { + private _deleteLines(start: number, deleteCount: number): void { + if (deleteCount === 0) { return; } - if (this._lineTokens === EMPTY_LINE_TOKENS) { - this._lineTokens = _otherTokens; - return; + if (start + deleteCount > this._len) { + deleteCount = this._len - start; } - if (this._lineTokens === null) { + this._beginState.splice(start, deleteCount); + this._valid.splice(start, deleteCount); + this._len -= deleteCount; + } + + private _insertLines(insertIndex: number, insertCount: number): void { + if (insertCount === 0) { return; } - if (_otherTokens === null) { - // cannot determine combined line length... - this._lineTokens = null; - return; + let beginState: (IState | null)[] = []; + let valid: boolean[] = []; + for (let i = 0; i < insertCount; i++) { + beginState[i] = null; + valid[i] = false; } - const myTokens = new Uint32Array(this._lineTokens); - const otherTokens = new Uint32Array(_otherTokens); - const otherTokensCount = (otherTokens.length >>> 1); + this._beginState = arrays.arrayInsert(this._beginState, insertIndex, beginState); + this._valid = arrays.arrayInsert(this._valid, insertIndex, valid); + this._len += insertCount; + } - let result = new Uint32Array(myTokens.length + otherTokens.length); - result.set(myTokens, 0); - let dest = myTokens.length; - const delta = myTokens[myTokens.length - 2]; - for (let i = 0; i < otherTokensCount; i++) { - result[dest++] = otherTokens[(i << 1)] + delta; - result[dest++] = otherTokens[(i << 1) + 1]; - } - this._lineTokens = result.buffer; + private _setValid(lineIndex: number, valid: boolean): void { + this._ensureLine(lineIndex); + this._valid[lineIndex] = valid; } - public insert(chIndex: number, textLength: number): void { - if (!this._lineTokens) { - // nothing to do + private _setBeginState(lineIndex: number, beginState: IState | null): void { + this._ensureLine(lineIndex); + this._beginState[lineIndex] = beginState; + } + + public setEndState(linesLength: number, lineIndex: number, endState: IState): void { + this._setValid(lineIndex, true); + this._invalidLineStartIndex = lineIndex + 1; + + // Check if this was the last line + if (lineIndex === linesLength - 1) { return; } - const tokens = new Uint32Array(this._lineTokens); - const tokensCount = (tokens.length >>> 1); + // Check if the end state has changed + const previousEndState = this.getBeginState(lineIndex + 1); + if (previousEndState === null || !endState.equals(previousEndState)) { + this._setBeginState(lineIndex + 1, endState); + this._invalidateLine(lineIndex + 1); + return; + } - let fromTokenIndex = LineTokens.findIndexInTokensArray(tokens, chIndex); - if (fromTokenIndex > 0) { - const fromTokenStartOffset = tokens[(fromTokenIndex - 1) << 1]; - if (fromTokenStartOffset === chIndex) { - fromTokenIndex--; + // Perhaps we can skip tokenizing some lines... + let i = lineIndex + 1; + while (i < linesLength) { + if (!this._isValid(i)) { + break; } + i++; } - for (let tokenIndex = fromTokenIndex; tokenIndex < tokensCount; tokenIndex++) { - tokens[tokenIndex << 1] += textLength; - } + this._invalidLineStartIndex = i; } -} -export class ModelLinesTokens { + public setFakeTokens(lineIndex: number): void { + this._setValid(lineIndex, false); + } - public readonly languageIdentifier: LanguageIdentifier; - public readonly tokenizationSupport: ITokenizationSupport | null; - private _tokens: ModelLineTokens[]; - private _invalidLineStartIndex: number; - private _lastState: IState | null; - - constructor(languageIdentifier: LanguageIdentifier, tokenizationSupport: ITokenizationSupport | null) { - this.languageIdentifier = languageIdentifier; - this.tokenizationSupport = tokenizationSupport; - this._tokens = []; - if (this.tokenizationSupport) { - let initialState: IState | null = null; - try { - initialState = this.tokenizationSupport.getInitialState(); - } catch (e) { - onUnexpectedError(e); - this.tokenizationSupport = null; - } + //#region Editing - if (initialState) { - this._tokens[0] = new ModelLineTokens(initialState); - } - } + public applyEdits(range: IRange, eolCount: number): void { + const deletingLinesCnt = range.endLineNumber - range.startLineNumber; + const insertingLinesCnt = eolCount; + const editingLinesCnt = Math.min(deletingLinesCnt, insertingLinesCnt); - this._invalidLineStartIndex = 0; - this._lastState = null; - } + for (let j = editingLinesCnt; j >= 0; j--) { + this._invalidateLine(range.startLineNumber + j - 1); + } - public get inValidLineStartIndex() { - return this._invalidLineStartIndex; + this._acceptDeleteRange(range); + this._acceptInsertText(new Position(range.startLineNumber, range.startColumn), eolCount); } - public getTokens(topLevelLanguageId: LanguageId, lineIndex: number, lineText: string): LineTokens { - let rawLineTokens: ArrayBuffer | null = null; - if (lineIndex < this._tokens.length && this._tokens[lineIndex]) { - rawLineTokens = this._tokens[lineIndex]._lineTokens; - } + private _acceptDeleteRange(range: IRange): void { - if (rawLineTokens !== null && rawLineTokens !== EMPTY_LINE_TOKENS) { - return new LineTokens(new Uint32Array(rawLineTokens), lineText); + const firstLineIndex = range.startLineNumber - 1; + if (firstLineIndex >= this._len) { + return; } - let lineTokens = new Uint32Array(2); - lineTokens[0] = lineText.length; - lineTokens[1] = getDefaultMetadata(topLevelLanguageId); - return new LineTokens(lineTokens, lineText); + this._deleteLines(range.startLineNumber, range.endLineNumber - range.startLineNumber); } - public isCheapToTokenize(lineNumber: number): boolean { - const firstInvalidLineNumber = this._invalidLineStartIndex + 1; - return (firstInvalidLineNumber >= lineNumber); - } + private _acceptInsertText(position: Position, eolCount: number): void { - public hasLinesToTokenize(buffer: ITextBuffer): boolean { - return (this._invalidLineStartIndex < buffer.getLineCount()); - } - - public invalidateLine(lineIndex: number): void { - this._setIsInvalid(lineIndex, true); - if (lineIndex < this._invalidLineStartIndex) { - this._setIsInvalid(this._invalidLineStartIndex, true); - this._invalidLineStartIndex = lineIndex; + const lineIndex = position.lineNumber - 1; + if (lineIndex >= this._len) { + return; } - } - _setIsInvalid(lineIndex: number, invalid: boolean): void { - if (lineIndex < this._tokens.length && this._tokens[lineIndex]) { - this._tokens[lineIndex]._invalid = invalid; - } + this._insertLines(position.lineNumber, eolCount); } - _isInvalid(lineIndex: number): boolean { - if (lineIndex < this._tokens.length && this._tokens[lineIndex]) { - return this._tokens[lineIndex]._invalid; - } - return true; - } + //#endregion +} - _getState(lineIndex: number): IState | null { - if (lineIndex < this._tokens.length && this._tokens[lineIndex]) { - return this._tokens[lineIndex]._state; - } - return null; - } +export class TextModelTokenization extends Disposable { - _setTokens(topLevelLanguageId: LanguageId, lineIndex: number, lineTextLength: number, tokens: Uint32Array): void { - let target: ModelLineTokens; - if (lineIndex < this._tokens.length && this._tokens[lineIndex]) { - target = this._tokens[lineIndex]; - } else { - target = new ModelLineTokens(null); - this._tokens[lineIndex] = target; - } + private readonly _textModel: TextModel; + private readonly _tokenizationStateStore: TokenizationStateStore; + private _revalidateTokensTimeout: any; + private _tokenizationSupport: ITokenizationSupport | null; - if (lineTextLength === 0) { - let hasDifferentLanguageId = false; - if (tokens && tokens.length > 1) { - hasDifferentLanguageId = (TokenMetadata.getLanguageId(tokens[1]) !== topLevelLanguageId); - } + constructor(textModel: TextModel) { + super(); + this._textModel = textModel; + this._tokenizationStateStore = new TokenizationStateStore(); + this._revalidateTokensTimeout = -1; + this._tokenizationSupport = null; - if (!hasDifferentLanguageId) { - target._lineTokens = EMPTY_LINE_TOKENS; + this._register(TokenizationRegistry.onDidChange((e) => { + const languageIdentifier = this._textModel.getLanguageIdentifier(); + if (e.changedLanguages.indexOf(languageIdentifier.language) === -1) { return; } - } - if (!tokens || tokens.length === 0) { - tokens = new Uint32Array(2); - tokens[0] = 0; - tokens[1] = getDefaultMetadata(topLevelLanguageId); - } + this._resetTokenizationState(); + this._textModel.clearTokens(); + })); - LineTokens.convertToEndOffset(tokens, lineTextLength); + this._register(this._textModel.onDidChangeRawContentFast((e) => { + if (e.containsEvent(RawContentChangedType.Flush)) { + this._resetTokenizationState(); + return; + } + })); - target._lineTokens = tokens.buffer; - } + this._register(this._textModel.onDidChangeContentFast((e) => { + for (let i = 0, len = e.changes.length; i < len; i++) { + const change = e.changes[i]; + const [eolCount] = countEOL(change.text); + this._tokenizationStateStore.applyEdits(change.range, eolCount); + } - _setState(lineIndex: number, state: IState): void { - if (lineIndex < this._tokens.length && this._tokens[lineIndex]) { - this._tokens[lineIndex]._state = state; - } else { - const tmp = new ModelLineTokens(state); - this._tokens[lineIndex] = tmp; - } - } + this._beginBackgroundTokenization(); + })); - //#region Editing + this._register(this._textModel.onDidChangeAttached(() => { + this._beginBackgroundTokenization(); + })); - public applyEdits(range: Range, eolCount: number, firstLineLength: number): void { + this._register(this._textModel.onDidChangeLanguage(() => { + this._resetTokenizationState(); + this._textModel.clearTokens(); + })); - const deletingLinesCnt = range.endLineNumber - range.startLineNumber; - const insertingLinesCnt = eolCount; - const editingLinesCnt = Math.min(deletingLinesCnt, insertingLinesCnt); + this._resetTokenizationState(); + } - for (let j = editingLinesCnt; j >= 0; j--) { - this.invalidateLine(range.startLineNumber + j - 1); - } + public dispose(): void { + this._clearTimers(); + super.dispose(); + } - this._acceptDeleteRange(range); - this._acceptInsertText(new Position(range.startLineNumber, range.startColumn), eolCount, firstLineLength); + private _clearTimers(): void { + if (this._revalidateTokensTimeout !== -1) { + clearTimeout(this._revalidateTokensTimeout); + this._revalidateTokensTimeout = -1; + } } - private _acceptDeleteRange(range: Range): void { + private _resetTokenizationState(): void { + this._clearTimers(); + const [tokenizationSupport, initialState] = initializeTokenization(this._textModel); + this._tokenizationSupport = tokenizationSupport; + this._tokenizationStateStore.flush(initialState); + this._beginBackgroundTokenization(); + } - const firstLineIndex = range.startLineNumber - 1; - if (firstLineIndex >= this._tokens.length) { - return; + private _beginBackgroundTokenization(): void { + if (this._textModel.isAttachedToEditor() && this._hasLinesToTokenize() && this._revalidateTokensTimeout === -1) { + this._revalidateTokensTimeout = setTimeout(() => { + this._revalidateTokensTimeout = -1; + this._revalidateTokensNow(); + }, 0); } + } - if (range.startLineNumber === range.endLineNumber) { - if (range.startColumn === range.endColumn) { - // Nothing to delete - return; + private _revalidateTokensNow(toLineNumber: number = this._textModel.getLineCount()): void { + const MAX_ALLOWED_TIME = 20; + const builder = new MultilineTokensBuilder(); + const sw = StopWatch.create(false); + + while (this._hasLinesToTokenize()) { + if (sw.elapsed() > MAX_ALLOWED_TIME) { + // Stop if MAX_ALLOWED_TIME is reached + break; } - this._tokens[firstLineIndex].delete(range.startColumn - 1, range.endColumn - 1); - return; + const tokenizedLineNumber = this._tokenizeOneInvalidLine(builder); + + if (tokenizedLineNumber >= toLineNumber) { + break; + } } - const firstLine = this._tokens[firstLineIndex]; - firstLine.deleteEnding(range.startColumn - 1); + this._beginBackgroundTokenization(); + this._textModel.setTokens(builder.tokens); + } - const lastLineIndex = range.endLineNumber - 1; - let lastLineTokens: ArrayBuffer | null = null; - if (lastLineIndex < this._tokens.length) { - const lastLine = this._tokens[lastLineIndex]; - lastLine.deleteBeginning(range.endColumn - 1); - lastLineTokens = lastLine._lineTokens; - } + public tokenizeViewport(startLineNumber: number, endLineNumber: number): void { + const builder = new MultilineTokensBuilder(); + this._tokenizeViewport(builder, startLineNumber, endLineNumber); + this._textModel.setTokens(builder.tokens); + } - // Take remaining text on last line and append it to remaining text on first line - firstLine.append(lastLineTokens); + public reset(): void { + this._resetTokenizationState(); + this._textModel.clearTokens(); + } - // Delete middle lines - this._tokens.splice(range.startLineNumber, range.endLineNumber - range.startLineNumber); + public forceTokenization(lineNumber: number): void { + const builder = new MultilineTokensBuilder(); + this._updateTokensUntilLine(builder, lineNumber); + this._textModel.setTokens(builder.tokens); } - private _acceptInsertText(position: Position, eolCount: number, firstLineLength: number): void { + public isCheapToTokenize(lineNumber: number): boolean { + if (!this._tokenizationSupport) { + return true; + } - if (eolCount === 0 && firstLineLength === 0) { - // Nothing to insert - return; + const firstInvalidLineNumber = this._tokenizationStateStore.invalidLineStartIndex + 1; + if (lineNumber > firstInvalidLineNumber) { + return false; } - const lineIndex = position.lineNumber - 1; - if (lineIndex >= this._tokens.length) { - return; + if (lineNumber < firstInvalidLineNumber) { + return true; } - if (eolCount === 0) { - // Inserting text on one line - this._tokens[lineIndex].insert(position.column - 1, firstLineLength); - return; + if (this._textModel.getLineLength(lineNumber) < Constants.CHEAP_TOKENIZATION_LENGTH_LIMIT) { + return true; } - const line = this._tokens[lineIndex]; - line.deleteEnding(position.column - 1); - line.insert(position.column - 1, firstLineLength); + return false; + } - let insert: ModelLineTokens[] = new Array(eolCount); - for (let i = eolCount - 1; i >= 0; i--) { - insert[i] = new ModelLineTokens(null); + private _hasLinesToTokenize(): boolean { + if (!this._tokenizationSupport) { + return false; } - this._tokens = arrays.arrayInsert(this._tokens, position.lineNumber, insert); + return (this._tokenizationStateStore.invalidLineStartIndex < this._textModel.getLineCount()); } - //#endregion - - //#region Tokenization - - public _tokenizeOneLine(buffer: ITextBuffer, eventBuilder: ModelTokensChangedEventBuilder): number { - if (!this.hasLinesToTokenize(buffer)) { - return buffer.getLineCount() + 1; + private _tokenizeOneInvalidLine(builder: MultilineTokensBuilder): number { + if (!this._hasLinesToTokenize()) { + return this._textModel.getLineCount() + 1; } - const lineNumber = this._invalidLineStartIndex + 1; - this._updateTokensUntilLine(buffer, eventBuilder, lineNumber); + const lineNumber = this._tokenizationStateStore.invalidLineStartIndex + 1; + this._updateTokensUntilLine(builder, lineNumber); return lineNumber; } - public _tokenizeText(buffer: ITextBuffer, text: string, state: IState): TokenizationResult2 { - let r: TokenizationResult2 | null = null; - - if (this.tokenizationSupport) { - try { - r = this.tokenizationSupport.tokenize2(text, state, 0); - } catch (e) { - onUnexpectedError(e); - } + private _updateTokensUntilLine(builder: MultilineTokensBuilder, lineNumber: number): void { + if (!this._tokenizationSupport) { + return; } + const languageIdentifier = this._textModel.getLanguageIdentifier(); + const linesLength = this._textModel.getLineCount(); + const endLineIndex = lineNumber - 1; - if (!r) { - r = nullTokenize2(this.languageIdentifier.id, text, state, 0); + // Validate all states up to and including endLineIndex + for (let lineIndex = this._tokenizationStateStore.invalidLineStartIndex; lineIndex <= endLineIndex; lineIndex++) { + const text = this._textModel.getLineContent(lineIndex + 1); + const lineStartState = this._tokenizationStateStore.getBeginState(lineIndex); + + const r = safeTokenize(languageIdentifier, this._tokenizationSupport, text, lineStartState!); + builder.add(lineIndex + 1, r.tokens); + this._tokenizationStateStore.setEndState(linesLength, lineIndex, r.endState); + lineIndex = this._tokenizationStateStore.invalidLineStartIndex - 1; // -1 because the outer loop increments it } - return r; } - public _updateTokensUntilLine(buffer: ITextBuffer, eventBuilder: ModelTokensChangedEventBuilder, lineNumber: number): void { - if (!this.tokenizationSupport) { - this._invalidLineStartIndex = buffer.getLineCount(); + private _tokenizeViewport(builder: MultilineTokensBuilder, startLineNumber: number, endLineNumber: number): void { + if (!this._tokenizationSupport) { + // nothing to do return; } - const linesLength = buffer.getLineCount(); - const endLineIndex = lineNumber - 1; + if (endLineNumber <= this._tokenizationStateStore.invalidLineStartIndex) { + // nothing to do + return; + } - // Validate all states up to and including endLineIndex - for (let lineIndex = this._invalidLineStartIndex; lineIndex <= endLineIndex; lineIndex++) { - const endStateIndex = lineIndex + 1; - const text = buffer.getLineContent(lineIndex + 1); - const lineStartState = this._getState(lineIndex); - - let r: TokenizationResult2 | null = null; - - try { - // Tokenize only the first X characters - let freshState = lineStartState!.clone(); - r = this.tokenizationSupport.tokenize2(text, freshState, 0); - } catch (e) { - onUnexpectedError(e); - } + if (startLineNumber <= this._tokenizationStateStore.invalidLineStartIndex) { + // tokenization has reached the viewport start... + this._updateTokensUntilLine(builder, endLineNumber); + return; + } + + let nonWhitespaceColumn = this._textModel.getLineFirstNonWhitespaceColumn(startLineNumber); + let fakeLines: string[] = []; + let initialState: IState | null = null; + for (let i = startLineNumber - 1; nonWhitespaceColumn > 0 && i >= 1; i--) { + let newNonWhitespaceIndex = this._textModel.getLineFirstNonWhitespaceColumn(i); - if (!r) { - r = nullTokenize2(this.languageIdentifier.id, text, lineStartState, 0); + if (newNonWhitespaceIndex === 0) { + continue; } - this._setTokens(this.languageIdentifier.id, lineIndex, text.length, r.tokens); - eventBuilder.registerChangedTokens(lineIndex + 1); - this._setIsInvalid(lineIndex, false); - - if (endStateIndex < linesLength) { - const previousEndState = this._getState(endStateIndex); - if (previousEndState !== null && r.endState.equals(previousEndState)) { - // The end state of this line remains the same - let nextInvalidLineIndex = lineIndex + 1; - while (nextInvalidLineIndex < linesLength) { - if (this._isInvalid(nextInvalidLineIndex)) { - break; - } - if (nextInvalidLineIndex + 1 < linesLength) { - if (this._getState(nextInvalidLineIndex + 1) === null) { - break; - } - } else { - if (this._lastState === null) { - break; - } - } - nextInvalidLineIndex++; - } - this._invalidLineStartIndex = Math.max(this._invalidLineStartIndex, nextInvalidLineIndex); - lineIndex = nextInvalidLineIndex - 1; // -1 because the outer loop increments it - } else { - this._setState(endStateIndex, r.endState); + + if (newNonWhitespaceIndex < nonWhitespaceColumn) { + initialState = this._tokenizationStateStore.getBeginState(i - 1); + if (initialState) { + break; } - } else { - this._lastState = r.endState; + fakeLines.push(this._textModel.getLineContent(i)); + nonWhitespaceColumn = newNonWhitespaceIndex; } } - this._invalidLineStartIndex = Math.max(this._invalidLineStartIndex, endLineIndex + 1); - } - // #endregion -} + if (!initialState) { + initialState = this._tokenizationSupport.getInitialState(); + } -export class ModelTokensChangedEventBuilder { + const languageIdentifier = this._textModel.getLanguageIdentifier(); + let state = initialState; + for (let i = fakeLines.length - 1; i >= 0; i--) { + let r = safeTokenize(languageIdentifier, this._tokenizationSupport, fakeLines[i], state); + state = r.endState; + } - private readonly _ranges: { fromLineNumber: number; toLineNumber: number; }[]; + for (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) { + let text = this._textModel.getLineContent(lineNumber); + let r = safeTokenize(languageIdentifier, this._tokenizationSupport, text, state); + builder.add(lineNumber, r.tokens); + this._tokenizationStateStore.setFakeTokens(lineNumber - 1); + state = r.endState; + } + } +} - constructor() { - this._ranges = []; +function initializeTokenization(textModel: TextModel): [ITokenizationSupport | null, IState | null] { + const languageIdentifier = textModel.getLanguageIdentifier(); + let tokenizationSupport = ( + textModel.isTooLargeForTokenization() + ? null + : TokenizationRegistry.get(languageIdentifier.language) + ); + let initialState: IState | null = null; + if (tokenizationSupport) { + try { + initialState = tokenizationSupport.getInitialState(); + } catch (e) { + onUnexpectedError(e); + tokenizationSupport = null; + } } + return [tokenizationSupport, initialState]; +} - public registerChangedTokens(lineNumber: number): void { - const ranges = this._ranges; - const rangesLength = ranges.length; - const previousRange = rangesLength > 0 ? ranges[rangesLength - 1] : null; +function safeTokenize(languageIdentifier: LanguageIdentifier, tokenizationSupport: ITokenizationSupport | null, text: string, state: IState): TokenizationResult2 { + let r: TokenizationResult2 | null = null; - if (previousRange && previousRange.toLineNumber === lineNumber - 1) { - // extend previous range - previousRange.toLineNumber++; - } else { - // insert new range - ranges[rangesLength] = { - fromLineNumber: lineNumber, - toLineNumber: lineNumber - }; + if (tokenizationSupport) { + try { + r = tokenizationSupport.tokenize2(text, state.clone(), 0); + } catch (e) { + onUnexpectedError(e); } } - public build(): IModelTokensChangedEvent | null { - if (this._ranges.length === 0) { - return null; - } - return { - tokenizationSupportChanged: false, - ranges: this._ranges - }; + if (!r) { + r = nullTokenize2(languageIdentifier.id, text, state, 0); } + + LineTokens.convertToEndOffset(r.tokens, text.length); + return r; } diff --git a/src/vs/editor/common/model/tokensStore.ts b/src/vs/editor/common/model/tokensStore.ts new file mode 100644 index 000000000..d965bcf89 --- /dev/null +++ b/src/vs/editor/common/model/tokensStore.ts @@ -0,0 +1,579 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as arrays from 'vs/base/common/arrays'; +import { LineTokens } from 'vs/editor/common/core/lineTokens'; +import { Position } from 'vs/editor/common/core/position'; +import { IRange } from 'vs/editor/common/core/range'; +import { ColorId, FontStyle, LanguageId, MetadataConsts, StandardTokenType, TokenMetadata } from 'vs/editor/common/modes'; +import { writeUInt32BE, readUInt32BE } from 'vs/base/common/buffer'; +import { CharCode } from 'vs/base/common/charCode'; + +export function countEOL(text: string): [number, number] { + let eolCount = 0; + let firstLineLength = 0; + for (let i = 0, len = text.length; i < len; i++) { + const chr = text.charCodeAt(i); + + if (chr === CharCode.CarriageReturn) { + if (eolCount === 0) { + firstLineLength = i; + } + eolCount++; + if (i + 1 < len && text.charCodeAt(i + 1) === CharCode.LineFeed) { + // \r\n... case + i++; // skip \n + } else { + // \r... case + } + } else if (chr === CharCode.LineFeed) { + if (eolCount === 0) { + firstLineLength = i; + } + eolCount++; + } + } + if (eolCount === 0) { + firstLineLength = text.length; + } + return [eolCount, firstLineLength]; +} + +function getDefaultMetadata(topLevelLanguageId: LanguageId): number { + return ( + (topLevelLanguageId << MetadataConsts.LANGUAGEID_OFFSET) + | (StandardTokenType.Other << MetadataConsts.TOKEN_TYPE_OFFSET) + | (FontStyle.None << MetadataConsts.FONT_STYLE_OFFSET) + | (ColorId.DefaultForeground << MetadataConsts.FOREGROUND_OFFSET) + | (ColorId.DefaultBackground << MetadataConsts.BACKGROUND_OFFSET) + ) >>> 0; +} + +const EMPTY_LINE_TOKENS = (new Uint32Array(0)).buffer; + +export class MultilineTokensBuilder { + + public readonly tokens: MultilineTokens[]; + + constructor() { + this.tokens = []; + } + + public add(lineNumber: number, lineTokens: Uint32Array): void { + if (this.tokens.length > 0) { + const last = this.tokens[this.tokens.length - 1]; + const lastLineNumber = last.startLineNumber + last.tokens.length - 1; + if (lastLineNumber + 1 === lineNumber) { + // append + last.tokens.push(lineTokens); + return; + } + } + this.tokens.push(new MultilineTokens(lineNumber, [lineTokens])); + } + + public static deserialize(buff: Uint8Array): MultilineTokens[] { + let offset = 0; + const count = readUInt32BE(buff, offset); offset += 4; + let result: MultilineTokens[] = []; + for (let i = 0; i < count; i++) { + offset = MultilineTokens.deserialize(buff, offset, result); + } + return result; + } + + public serialize(): Uint8Array { + const size = this._serializeSize(); + const result = new Uint8Array(size); + this._serialize(result); + return result; + } + + private _serializeSize(): number { + let result = 0; + result += 4; // 4 bytes for the count + for (let i = 0; i < this.tokens.length; i++) { + result += this.tokens[i].serializeSize(); + } + return result; + } + + private _serialize(destination: Uint8Array): void { + let offset = 0; + writeUInt32BE(destination, this.tokens.length, offset); offset += 4; + for (let i = 0; i < this.tokens.length; i++) { + offset = this.tokens[i].serialize(destination, offset); + } + } +} + +export class MultilineTokens { + + public startLineNumber: number; + public tokens: (Uint32Array | ArrayBuffer | null)[]; + + constructor(startLineNumber: number, tokens: Uint32Array[]) { + this.startLineNumber = startLineNumber; + this.tokens = tokens; + } + + public static deserialize(buff: Uint8Array, offset: number, result: MultilineTokens[]): number { + const view32 = new Uint32Array(buff.buffer); + const startLineNumber = readUInt32BE(buff, offset); offset += 4; + const count = readUInt32BE(buff, offset); offset += 4; + let tokens: Uint32Array[] = []; + for (let i = 0; i < count; i++) { + const byteCount = readUInt32BE(buff, offset); offset += 4; + tokens.push(view32.subarray(offset / 4, offset / 4 + byteCount / 4)); + offset += byteCount; + } + result.push(new MultilineTokens(startLineNumber, tokens)); + return offset; + } + + public serializeSize(): number { + let result = 0; + result += 4; // 4 bytes for the start line number + result += 4; // 4 bytes for the line count + for (let i = 0; i < this.tokens.length; i++) { + const lineTokens = this.tokens[i]; + if (!(lineTokens instanceof Uint32Array)) { + throw new Error(`Not supported!`); + } + result += 4; // 4 bytes for the byte count + result += lineTokens.byteLength; + } + return result; + } + + public serialize(destination: Uint8Array, offset: number): number { + writeUInt32BE(destination, this.startLineNumber, offset); offset += 4; + writeUInt32BE(destination, this.tokens.length, offset); offset += 4; + for (let i = 0; i < this.tokens.length; i++) { + const lineTokens = this.tokens[i]; + if (!(lineTokens instanceof Uint32Array)) { + throw new Error(`Not supported!`); + } + writeUInt32BE(destination, lineTokens.byteLength, offset); offset += 4; + destination.set(new Uint8Array(lineTokens.buffer), offset); offset += lineTokens.byteLength; + } + return offset; + } + + public applyEdit(range: IRange, text: string): void { + const [eolCount, firstLineLength] = countEOL(text); + this._acceptDeleteRange(range); + this._acceptInsertText(new Position(range.startLineNumber, range.startColumn), eolCount, firstLineLength); + } + + private _acceptDeleteRange(range: IRange): void { + if (range.startLineNumber === range.endLineNumber && range.startColumn === range.endColumn) { + // Nothing to delete + return; + } + + const firstLineIndex = range.startLineNumber - this.startLineNumber; + const lastLineIndex = range.endLineNumber - this.startLineNumber; + + if (lastLineIndex < 0) { + // this deletion occurs entirely before this block, so we only need to adjust line numbers + const deletedLinesCount = lastLineIndex - firstLineIndex; + this.startLineNumber -= deletedLinesCount; + return; + } + + if (firstLineIndex >= this.tokens.length) { + // this deletion occurs entirely after this block, so there is nothing to do + return; + } + + if (firstLineIndex < 0 && lastLineIndex >= this.tokens.length) { + // this deletion completely encompasses this block + this.startLineNumber = 0; + this.tokens = []; + } + + if (firstLineIndex === lastLineIndex) { + // a delete on a single line + this.tokens[firstLineIndex] = TokensStore._delete(this.tokens[firstLineIndex], range.startColumn - 1, range.endColumn - 1); + return; + } + + if (firstLineIndex >= 0) { + // The first line survives + this.tokens[firstLineIndex] = TokensStore._deleteEnding(this.tokens[firstLineIndex], range.startColumn - 1); + + if (lastLineIndex < this.tokens.length) { + // The last line survives + const lastLineTokens = TokensStore._deleteBeginning(this.tokens[lastLineIndex], range.endColumn - 1); + + // Take remaining text on last line and append it to remaining text on first line + this.tokens[firstLineIndex] = TokensStore._append(this.tokens[firstLineIndex], lastLineTokens); + + // Delete middle lines + this.tokens.splice(firstLineIndex + 1, lastLineIndex - firstLineIndex); + } else { + // The last line does not survive + + // Take remaining text on last line and append it to remaining text on first line + this.tokens[firstLineIndex] = TokensStore._append(this.tokens[firstLineIndex], null); + + // Delete lines + this.tokens = this.tokens.slice(0, firstLineIndex + 1); + } + } else { + // The first line does not survive + + const deletedBefore = -firstLineIndex; + this.startLineNumber -= deletedBefore; + + // Remove beginning from last line + this.tokens[lastLineIndex] = TokensStore._deleteBeginning(this.tokens[lastLineIndex], range.endColumn - 1); + + // Delete lines + this.tokens = this.tokens.slice(lastLineIndex); + } + } + + private _acceptInsertText(position: Position, eolCount: number, firstLineLength: number): void { + + if (eolCount === 0 && firstLineLength === 0) { + // Nothing to insert + return; + } + + const lineIndex = position.lineNumber - this.startLineNumber; + + if (lineIndex < 0) { + // this insertion occurs before this block, so we only need to adjust line numbers + this.startLineNumber += eolCount; + return; + } + + if (lineIndex >= this.tokens.length) { + // this insertion occurs after this block, so there is nothing to do + return; + } + + if (eolCount === 0) { + // Inserting text on one line + this.tokens[lineIndex] = TokensStore._insert(this.tokens[lineIndex], position.column - 1, firstLineLength); + return; + } + + this.tokens[lineIndex] = TokensStore._deleteEnding(this.tokens[lineIndex], position.column - 1); + this.tokens[lineIndex] = TokensStore._insert(this.tokens[lineIndex], position.column - 1, firstLineLength); + + this._insertLines(position.lineNumber, eolCount); + } + + private _insertLines(insertIndex: number, insertCount: number): void { + if (insertCount === 0) { + return; + } + let lineTokens: (Uint32Array | ArrayBuffer | null)[] = []; + for (let i = 0; i < insertCount; i++) { + lineTokens[i] = null; + } + this.tokens = arrays.arrayInsert(this.tokens, insertIndex, lineTokens); + } +} + +function toUint32Array(arr: Uint32Array | ArrayBuffer): Uint32Array { + if (arr instanceof Uint32Array) { + return arr; + } else { + return new Uint32Array(arr); + } +} + +export class TokensStore { + private _lineTokens: (Uint32Array | ArrayBuffer | null)[]; + private _len: number; + + constructor() { + this._lineTokens = []; + this._len = 0; + } + + public flush(): void { + this._lineTokens = []; + this._len = 0; + } + + public getTokens(topLevelLanguageId: LanguageId, lineIndex: number, lineText: string): LineTokens { + let rawLineTokens: Uint32Array | ArrayBuffer | null = null; + if (lineIndex < this._len) { + rawLineTokens = this._lineTokens[lineIndex]; + } + + if (rawLineTokens !== null && rawLineTokens !== EMPTY_LINE_TOKENS) { + return new LineTokens(toUint32Array(rawLineTokens), lineText); + } + + let lineTokens = new Uint32Array(2); + lineTokens[0] = lineText.length; + lineTokens[1] = getDefaultMetadata(topLevelLanguageId); + return new LineTokens(lineTokens, lineText); + } + + private static _massageTokens(topLevelLanguageId: LanguageId, lineTextLength: number, _tokens: Uint32Array | ArrayBuffer | null): Uint32Array | ArrayBuffer { + + const tokens = _tokens ? toUint32Array(_tokens) : null; + + if (lineTextLength === 0) { + let hasDifferentLanguageId = false; + if (tokens && tokens.length > 1) { + hasDifferentLanguageId = (TokenMetadata.getLanguageId(tokens[1]) !== topLevelLanguageId); + } + + if (!hasDifferentLanguageId) { + return EMPTY_LINE_TOKENS; + } + } + + if (!tokens || tokens.length === 0) { + const tokens = new Uint32Array(2); + tokens[0] = lineTextLength; + tokens[1] = getDefaultMetadata(topLevelLanguageId); + return tokens.buffer; + } + + // Ensure the last token covers the end of the text + tokens[tokens.length - 2] = lineTextLength; + + if (tokens.byteOffset === 0 && tokens.byteLength === tokens.buffer.byteLength) { + // Store directly the ArrayBuffer pointer to save an object + return tokens.buffer; + } + return tokens; + } + + private _ensureLine(lineIndex: number): void { + while (lineIndex >= this._len) { + this._lineTokens[this._len] = null; + this._len++; + } + } + + private _deleteLines(start: number, deleteCount: number): void { + if (deleteCount === 0) { + return; + } + if (start + deleteCount > this._len) { + deleteCount = this._len - start; + } + this._lineTokens.splice(start, deleteCount); + this._len -= deleteCount; + } + + private _insertLines(insertIndex: number, insertCount: number): void { + if (insertCount === 0) { + return; + } + let lineTokens: (Uint32Array | ArrayBuffer | null)[] = []; + for (let i = 0; i < insertCount; i++) { + lineTokens[i] = null; + } + this._lineTokens = arrays.arrayInsert(this._lineTokens, insertIndex, lineTokens); + this._len += insertCount; + } + + public setTokens(topLevelLanguageId: LanguageId, lineIndex: number, lineTextLength: number, _tokens: Uint32Array | ArrayBuffer | null): void { + const tokens = TokensStore._massageTokens(topLevelLanguageId, lineTextLength, _tokens); + this._ensureLine(lineIndex); + this._lineTokens[lineIndex] = tokens; + } + + //#region Editing + + public acceptEdit(range: IRange, eolCount: number, firstLineLength: number): void { + this._acceptDeleteRange(range); + this._acceptInsertText(new Position(range.startLineNumber, range.startColumn), eolCount, firstLineLength); + } + + private _acceptDeleteRange(range: IRange): void { + + const firstLineIndex = range.startLineNumber - 1; + if (firstLineIndex >= this._len) { + return; + } + + if (range.startLineNumber === range.endLineNumber) { + if (range.startColumn === range.endColumn) { + // Nothing to delete + return; + } + + this._lineTokens[firstLineIndex] = TokensStore._delete(this._lineTokens[firstLineIndex], range.startColumn - 1, range.endColumn - 1); + return; + } + + this._lineTokens[firstLineIndex] = TokensStore._deleteEnding(this._lineTokens[firstLineIndex], range.startColumn - 1); + + const lastLineIndex = range.endLineNumber - 1; + let lastLineTokens: Uint32Array | ArrayBuffer | null = null; + if (lastLineIndex < this._len) { + lastLineTokens = TokensStore._deleteBeginning(this._lineTokens[lastLineIndex], range.endColumn - 1); + } + + // Take remaining text on last line and append it to remaining text on first line + this._lineTokens[firstLineIndex] = TokensStore._append(this._lineTokens[firstLineIndex], lastLineTokens); + + // Delete middle lines + this._deleteLines(range.startLineNumber, range.endLineNumber - range.startLineNumber); + } + + private _acceptInsertText(position: Position, eolCount: number, firstLineLength: number): void { + + if (eolCount === 0 && firstLineLength === 0) { + // Nothing to insert + return; + } + + const lineIndex = position.lineNumber - 1; + if (lineIndex >= this._len) { + return; + } + + if (eolCount === 0) { + // Inserting text on one line + this._lineTokens[lineIndex] = TokensStore._insert(this._lineTokens[lineIndex], position.column - 1, firstLineLength); + return; + } + + this._lineTokens[lineIndex] = TokensStore._deleteEnding(this._lineTokens[lineIndex], position.column - 1); + this._lineTokens[lineIndex] = TokensStore._insert(this._lineTokens[lineIndex], position.column - 1, firstLineLength); + + this._insertLines(position.lineNumber, eolCount); + } + + public static _deleteBeginning(lineTokens: Uint32Array | ArrayBuffer | null, toChIndex: number): Uint32Array | ArrayBuffer | null { + if (lineTokens === null || lineTokens === EMPTY_LINE_TOKENS) { + return lineTokens; + } + return TokensStore._delete(lineTokens, 0, toChIndex); + } + + public static _deleteEnding(lineTokens: Uint32Array | ArrayBuffer | null, fromChIndex: number): Uint32Array | ArrayBuffer | null { + if (lineTokens === null || lineTokens === EMPTY_LINE_TOKENS) { + return lineTokens; + } + + const tokens = toUint32Array(lineTokens); + const lineTextLength = tokens[tokens.length - 2]; + return TokensStore._delete(lineTokens, fromChIndex, lineTextLength); + } + + public static _delete(lineTokens: Uint32Array | ArrayBuffer | null, fromChIndex: number, toChIndex: number): Uint32Array | ArrayBuffer | null { + if (lineTokens === null || lineTokens === EMPTY_LINE_TOKENS || fromChIndex === toChIndex) { + return lineTokens; + } + + const tokens = toUint32Array(lineTokens); + const tokensCount = (tokens.length >>> 1); + + // special case: deleting everything + if (fromChIndex === 0 && tokens[tokens.length - 2] === toChIndex) { + return EMPTY_LINE_TOKENS; + } + + const fromTokenIndex = LineTokens.findIndexInTokensArray(tokens, fromChIndex); + const fromTokenStartOffset = (fromTokenIndex > 0 ? tokens[(fromTokenIndex - 1) << 1] : 0); + const fromTokenEndOffset = tokens[fromTokenIndex << 1]; + + if (toChIndex < fromTokenEndOffset) { + // the delete range is inside a single token + const delta = (toChIndex - fromChIndex); + for (let i = fromTokenIndex; i < tokensCount; i++) { + tokens[i << 1] -= delta; + } + return lineTokens; + } + + let dest: number; + let lastEnd: number; + if (fromTokenStartOffset !== fromChIndex) { + tokens[fromTokenIndex << 1] = fromChIndex; + dest = ((fromTokenIndex + 1) << 1); + lastEnd = fromChIndex; + } else { + dest = (fromTokenIndex << 1); + lastEnd = fromTokenStartOffset; + } + + const delta = (toChIndex - fromChIndex); + for (let tokenIndex = fromTokenIndex + 1; tokenIndex < tokensCount; tokenIndex++) { + const tokenEndOffset = tokens[tokenIndex << 1] - delta; + if (tokenEndOffset > lastEnd) { + tokens[dest++] = tokenEndOffset; + tokens[dest++] = tokens[(tokenIndex << 1) + 1]; + lastEnd = tokenEndOffset; + } + } + + if (dest === tokens.length) { + // nothing to trim + return lineTokens; + } + + let tmp = new Uint32Array(dest); + tmp.set(tokens.subarray(0, dest), 0); + return tmp.buffer; + } + + public static _append(lineTokens: Uint32Array | ArrayBuffer | null, _otherTokens: Uint32Array | ArrayBuffer | null): Uint32Array | ArrayBuffer | null { + if (_otherTokens === EMPTY_LINE_TOKENS) { + return lineTokens; + } + if (lineTokens === EMPTY_LINE_TOKENS) { + return _otherTokens; + } + if (lineTokens === null) { + return lineTokens; + } + if (_otherTokens === null) { + // cannot determine combined line length... + return null; + } + const myTokens = toUint32Array(lineTokens); + const otherTokens = toUint32Array(_otherTokens); + const otherTokensCount = (otherTokens.length >>> 1); + + let result = new Uint32Array(myTokens.length + otherTokens.length); + result.set(myTokens, 0); + let dest = myTokens.length; + const delta = myTokens[myTokens.length - 2]; + for (let i = 0; i < otherTokensCount; i++) { + result[dest++] = otherTokens[(i << 1)] + delta; + result[dest++] = otherTokens[(i << 1) + 1]; + } + return result.buffer; + } + + public static _insert(lineTokens: Uint32Array | ArrayBuffer | null, chIndex: number, textLength: number): Uint32Array | ArrayBuffer | null { + if (lineTokens === null || lineTokens === EMPTY_LINE_TOKENS) { + // nothing to do + return lineTokens; + } + + const tokens = toUint32Array(lineTokens); + const tokensCount = (tokens.length >>> 1); + + let fromTokenIndex = LineTokens.findIndexInTokensArray(tokens, chIndex); + if (fromTokenIndex > 0) { + const fromTokenStartOffset = tokens[(fromTokenIndex - 1) << 1]; + if (fromTokenStartOffset === chIndex) { + fromTokenIndex--; + } + } + for (let tokenIndex = fromTokenIndex; tokenIndex < tokensCount; tokenIndex++) { + tokens[tokenIndex << 1] += textLength; + } + return lineTokens; + } + + //#endregion +} diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index 338645cd9..fa05b9b96 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -17,8 +17,8 @@ import { TokenizationResult, TokenizationResult2 } from 'vs/editor/common/core/t import * as model from 'vs/editor/common/model'; import { LanguageFeatureRegistry } from 'vs/editor/common/modes/languageFeatureRegistry'; import { TokenizationRegistryImpl } from 'vs/editor/common/modes/tokenizationRegistry'; -import { IMarkerData } from 'vs/platform/markers/common/markers'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; +import { IMarkerData } from 'vs/platform/markers/common/markers'; /** * Open ended enum at runtime @@ -510,6 +510,11 @@ export interface CompletionContext { */ export interface CompletionItemProvider { + /** + * @internal + */ + _debugDisplayName?: string; + triggerCharacters?: string[]; /** * Provide completion items for the given position and document. @@ -550,6 +555,10 @@ export interface CodeActionContext { trigger: CodeActionTrigger; } +export interface CodeActionList extends IDisposable { + readonly actions: ReadonlyArray; +} + /** * The code action interface defines the contract between extensions and * the [light bulb](https://code.visualstudio.com/docs/editor/editingevolved#_code-action) feature. @@ -559,7 +568,7 @@ export interface CodeActionProvider { /** * Provide commands for the given document and range. */ - provideCodeActions(model: model.ITextModel, range: Range | Selection, context: CodeActionContext, token: CancellationToken): ProviderResult; + provideCodeActions(model: model.ITextModel, range: Range | Selection, context: CodeActionContext, token: CancellationToken): ProviderResult; /** * Optional list of CodeActionKinds that this provider returns. @@ -624,6 +633,10 @@ export interface SignatureHelp { activeParameter: number; } +export interface SignatureHelpResult extends IDisposable { + value: SignatureHelp; +} + export enum SignatureHelpTriggerKind { Invoke = 1, TriggerCharacter = 2, @@ -649,7 +662,7 @@ export interface SignatureHelpProvider { /** * Provide help for the signature at the given position and document. */ - provideSignatureHelp(model: model.ITextModel, position: Position, token: CancellationToken, context: SignatureHelpContext): ProviderResult; + provideSignatureHelp(model: model.ITextModel, position: Position, token: CancellationToken, context: SignatureHelpContext): ProviderResult; } /** @@ -1000,6 +1013,7 @@ export interface IInplaceReplaceSupportResult { export interface ILink { range: IRange; url?: URI | string; + tooltip?: string; } export interface ILinksList { @@ -1093,7 +1107,6 @@ export interface DocumentColorProvider { } export interface SelectionRange { - kind: string; range: IRange; } @@ -1215,6 +1228,7 @@ export interface Command { * @internal */ export interface CommentThreadTemplate { + controllerHandle: number; label: string; acceptInputCommand?: Command; additionalCommands?: Command[]; @@ -1227,19 +1241,7 @@ export interface CommentThreadTemplate { export interface CommentInfo { extensionId?: string; threads: CommentThread[]; - commentingRanges?: (IRange[] | CommentingRanges); - reply?: Command; - draftMode?: DraftMode; - template?: CommentThreadTemplate; -} - -/** - * @internal - */ -export enum DraftMode { - NotSupported, - InDraft, - NotInDraft + commentingRanges: CommentingRanges; } /** @@ -1279,23 +1281,20 @@ export interface CommentInput { /** * @internal */ -export interface CommentThread2 { +export interface CommentThread { commentThreadHandle: number; + controllerHandle: number; extensionId?: string; - threadId: string | null; + threadId: string; resource: string | null; range: IRange; label: string; + contextValue: string | undefined; comments: Comment[] | undefined; onDidChangeComments: Event; collapsibleState?: CommentThreadCollapsibleState; input?: CommentInput; onDidChangeInput: Event; - acceptInputCommand?: Command; - additionalCommands?: Command[]; - deleteCommand?: Command; - onDidChangeAcceptInputCommand: Event; - onDidChangeAdditionalCommands: Event; onDidChangeRange: Event; onDidChangeLabel: Event; onDidChangeCollasibleState: Event; @@ -1309,29 +1308,6 @@ export interface CommentThread2 { export interface CommentingRanges { readonly resource: URI; ranges: IRange[]; - newCommentThreadCallback?: (uri: UriComponents, range: IRange) => Promise; -} - -/** - * @internal - */ -export interface CommentThread { - extensionId?: string; - threadId: string | null; - resource: string | null; - range: IRange; - comments: Comment[] | undefined; - collapsibleState?: CommentThreadCollapsibleState; - reply?: Command; - isDisposed?: boolean; -} - -/** - * @internal - */ -export interface NewCommentAction { - ranges: IRange[]; - actions: Command[]; } /** @@ -1345,22 +1321,26 @@ export interface CommentReaction { readonly canEdit?: boolean; } +/** + * @internal + */ +export enum CommentMode { + Editing = 0, + Preview = 1 +} + /** * @internal */ export interface Comment { - readonly commentId: string; + readonly uniqueIdInThread: number; readonly body: IMarkdownString; readonly userName: string; readonly userIconPath?: string; - readonly canEdit?: boolean; - readonly canDelete?: boolean; - readonly selectCommand?: Command; - readonly editCommand?: Command; - readonly deleteCommand?: Command; - readonly isDraft?: boolean; + readonly contextValue?: string; readonly commentReactions?: CommentReaction[]; readonly label?: string; + readonly mode?: CommentMode; } /** @@ -1370,54 +1350,17 @@ export interface CommentThreadChangedEvent { /** * Added comment threads. */ - readonly added: (CommentThread | CommentThread2)[]; + readonly added: CommentThread[]; /** * Removed comment threads. */ - readonly removed: (CommentThread | CommentThread2)[]; + readonly removed: CommentThread[]; /** * Changed comment threads. */ - readonly changed: (CommentThread | CommentThread2)[]; - - /** - * changed draft mode. - */ - readonly draftMode?: DraftMode; -} - -/** - * @internal - */ -export interface DocumentCommentProvider { - provideDocumentComments(resource: URI, token: CancellationToken): Promise; - createNewCommentThread(resource: URI, range: Range, text: string, token: CancellationToken): Promise; - replyToCommentThread(resource: URI, range: Range, thread: CommentThread, text: string, token: CancellationToken): Promise; - editComment(resource: URI, comment: Comment, text: string, token: CancellationToken): Promise; - deleteComment(resource: URI, comment: Comment, token: CancellationToken): Promise; - startDraft?(resource: URI, token: CancellationToken): Promise; - deleteDraft?(resource: URI, token: CancellationToken): Promise; - finishDraft?(resource: URI, token: CancellationToken): Promise; - - startDraftLabel?: string; - deleteDraftLabel?: string; - finishDraftLabel?: string; - - addReaction?(resource: URI, comment: Comment, reaction: CommentReaction, token: CancellationToken): Promise; - deleteReaction?(resource: URI, comment: Comment, reaction: CommentReaction, token: CancellationToken): Promise; - reactionGroup?: CommentReaction[]; - - onDidChangeCommentThreads?(): Event; -} - -/** - * @internal - */ -export interface WorkspaceCommentProvider { - provideWorkspaceComments(token: CancellationToken): Promise; - onDidChangeCommentThreads(): Event; + readonly changed: CommentThread[]; } /** @@ -1446,15 +1389,21 @@ export interface IWebviewPanelOptions { readonly retainContextWhenHidden?: boolean; } -export interface ICodeLensSymbol { +export interface CodeLens { range: IRange; id?: string; command?: Command; } + +export interface CodeLensList { + lenses: CodeLens[]; + dispose(): void; +} + export interface CodeLensProvider { onDidChange?: Event; - provideCodeLenses(model: model.ITextModel, token: CancellationToken): ProviderResult; - resolveCodeLens?(model: model.ITextModel, codeLens: ICodeLensSymbol, token: CancellationToken): ProviderResult; + provideCodeLenses(model: model.ITextModel, token: CancellationToken): ProviderResult; + resolveCodeLens?(model: model.ITextModel, codeLens: CodeLens, token: CancellationToken): ProviderResult; } // --- feature registries ------ diff --git a/src/vs/editor/common/modes/tokenization/typescript.ts b/src/vs/editor/common/modes/tokenization/typescript.ts new file mode 100644 index 000000000..207e8f492 --- /dev/null +++ b/src/vs/editor/common/modes/tokenization/typescript.ts @@ -0,0 +1,304 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { StandardTokenType } from 'vs/editor/common/modes'; +import { CharCode } from 'vs/base/common/charCode'; + +class ParserContext { + public readonly text: string; + public readonly len: number; + public readonly tokens: number[]; + public pos: number; + + private currentTokenStartOffset: number; + private currentTokenType: StandardTokenType; + + constructor(text: string) { + this.text = text; + this.len = this.text.length; + this.tokens = []; + this.pos = 0; + this.currentTokenStartOffset = 0; + this.currentTokenType = StandardTokenType.Other; + } + + private _safeCharCodeAt(index: number): number { + if (index >= this.len) { + return CharCode.Null; + } + return this.text.charCodeAt(index); + } + + peek(distance: number = 0): number { + return this._safeCharCodeAt(this.pos + distance); + } + + next(): number { + const result = this._safeCharCodeAt(this.pos); + this.pos++; + return result; + } + + advance(distance: number): void { + this.pos += distance; + } + + eof(): boolean { + return this.pos >= this.len; + } + + beginToken(tokenType: StandardTokenType, deltaPos: number = 0): void { + this.currentTokenStartOffset = this.pos + deltaPos; + this.currentTokenType = tokenType; + } + + endToken(deltaPos: number = 0): void { + const length = this.pos + deltaPos - this.currentTokenStartOffset; + // check if it is touching previous token + if (this.tokens.length > 0) { + const previousStartOffset = this.tokens[this.tokens.length - 3]; + const previousLength = this.tokens[this.tokens.length - 2]; + const previousTokenType = this.tokens[this.tokens.length - 1]; + const previousEndOffset = previousStartOffset + previousLength; + if (this.currentTokenStartOffset === previousEndOffset && previousTokenType === this.currentTokenType) { + // extend previous token + this.tokens[this.tokens.length - 2] += length; + return; + } + } + this.tokens.push(this.currentTokenStartOffset, length, this.currentTokenType); + } +} + +export function parse(text: string): number[] { + const ctx = new ParserContext(text); + while (!ctx.eof()) { + parseRoot(ctx); + } + return ctx.tokens; +} + +function parseRoot(ctx: ParserContext): void { + let curlyCount = 0; + while (!ctx.eof()) { + const ch = ctx.peek(); + + switch (ch) { + case CharCode.SingleQuote: + parseSimpleString(ctx, CharCode.SingleQuote); + break; + case CharCode.DoubleQuote: + parseSimpleString(ctx, CharCode.DoubleQuote); + break; + case CharCode.BackTick: + parseInterpolatedString(ctx); + break; + case CharCode.Slash: + parseSlash(ctx); + break; + case CharCode.OpenCurlyBrace: + ctx.advance(1); + curlyCount++; + break; + case CharCode.CloseCurlyBrace: + ctx.advance(1); + curlyCount--; + if (curlyCount < 0) { + return; + } + break; + default: + ctx.advance(1); + } + } + +} + +function parseSimpleString(ctx: ParserContext, closingQuote: number): void { + ctx.beginToken(StandardTokenType.String); + + // skip the opening quote + ctx.advance(1); + + while (!ctx.eof()) { + const ch = ctx.next(); + if (ch === CharCode.Backslash) { + // skip \r\n or any other character following a backslash + const advanceCount = (ctx.peek() === CharCode.CarriageReturn && ctx.peek(1) === CharCode.LineFeed ? 2 : 1); + ctx.advance(advanceCount); + } else if (ch === closingQuote) { + // hit end quote, so stop + break; + } + } + + ctx.endToken(); +} + +function parseInterpolatedString(ctx: ParserContext): void { + ctx.beginToken(StandardTokenType.String); + + // skip the opening quote + ctx.advance(1); + + while (!ctx.eof()) { + const ch = ctx.next(); + if (ch === CharCode.Backslash) { + // skip \r\n or any other character following a backslash + const advanceCount = (ctx.peek() === CharCode.CarriageReturn && ctx.peek(1) === CharCode.LineFeed ? 2 : 1); + ctx.advance(advanceCount); + } else if (ch === CharCode.BackTick) { + // hit end quote, so stop + break; + } else if (ch === CharCode.DollarSign) { + if (ctx.peek() === CharCode.OpenCurlyBrace) { + ctx.advance(1); + ctx.endToken(); + parseRoot(ctx); + ctx.beginToken(StandardTokenType.String, -1); + } + } + } + + ctx.endToken(); +} + +function parseSlash(ctx: ParserContext): void { + + const nextCh = ctx.peek(1); + if (nextCh === CharCode.Asterisk) { + parseMultiLineComment(ctx); + return; + } + + if (nextCh === CharCode.Slash) { + parseSingleLineComment(ctx); + return; + } + + if (tryParseRegex(ctx)) { + return; + } + + ctx.advance(1); +} + +function tryParseRegex(ctx: ParserContext): boolean { + // See https://www.ecma-international.org/ecma-262/10.0/index.html#prod-RegularExpressionLiteral + + // TODO: avoid regex... + let contentBefore = ctx.text.substr(ctx.pos - 100, 100); + if (/[a-zA-Z0-9](\s*)$/.test(contentBefore)) { + // Cannot start after an identifier + return false; + } + + let pos = 0; + let len = ctx.len - ctx.pos; + let inClass = false; + + // skip / + pos++; + + while (pos < len) { + const ch = ctx.peek(pos++); + + if (ch === CharCode.CarriageReturn || ch === CharCode.LineFeed) { + return false; + } + + if (ch === CharCode.Backslash) { + const nextCh = ctx.peek(); + if (nextCh === CharCode.CarriageReturn || nextCh === CharCode.LineFeed) { + return false; + } + // skip next character + pos++; + continue; + } + + if (inClass) { + + if (ch === CharCode.CloseSquareBracket) { + inClass = false; + continue; + } + + } else { + + if (ch === CharCode.Slash) { + // cannot be directly followed by a / + if (ctx.peek(pos) === CharCode.Slash) { + return false; + } + + // consume flags + do { + let nextCh = ctx.peek(pos); + if (nextCh >= CharCode.a && nextCh <= CharCode.z) { + pos++; + continue; + } else { + break; + } + } while (true); + + // TODO: avoid regex... + if (/^(\s*)(\.|;|\/|,|\)|\]|\}|$)/.test(ctx.text.substr(ctx.pos + pos))) { + // Must be followed by an operator of kinds + ctx.beginToken(StandardTokenType.RegEx); + ctx.advance(pos); + ctx.endToken(); + return true; + } + + return false; + } + + if (ch === CharCode.OpenSquareBracket) { + inClass = true; + continue; + } + + } + } + + return false; +} + +function parseMultiLineComment(ctx: ParserContext): void { + ctx.beginToken(StandardTokenType.Comment); + + // skip the /* + ctx.advance(2); + + while (!ctx.eof()) { + const ch = ctx.next(); + if (ch === CharCode.Asterisk) { + if (ctx.peek() === CharCode.Slash) { + ctx.advance(1); + break; + } + } + } + + ctx.endToken(); +} + +function parseSingleLineComment(ctx: ParserContext): void { + ctx.beginToken(StandardTokenType.Comment); + + // skip the // + ctx.advance(2); + + while (!ctx.eof()) { + const ch = ctx.next(); + if (ch === CharCode.CarriageReturn || ch === CharCode.LineFeed) { + break; + } + } + + ctx.endToken(); +} diff --git a/src/vs/editor/common/services/editorSimpleWorker.ts b/src/vs/editor/common/services/editorSimpleWorker.ts index a4c9dd6e8..06c11b330 100644 --- a/src/vs/editor/common/services/editorSimpleWorker.ts +++ b/src/vs/editor/common/services/editorSimpleWorker.ts @@ -22,7 +22,8 @@ import { ILinkComputerTarget, computeLinks } from 'vs/editor/common/modes/linkCo import { BasicInplaceReplace } from 'vs/editor/common/modes/supports/inplaceReplaceSupport'; import { IDiffComputationResult } from 'vs/editor/common/services/editorWorkerService'; import { createMonacoBaseAPI } from 'vs/editor/common/standalone/standaloneBase'; -import { getAllPropertyNames } from 'vs/base/common/types'; +import * as types from 'vs/base/common/types'; +import { EditorWorkerHost } from 'vs/editor/common/services/editorWorkerServiceImpl'; export interface IMirrorModel { readonly uri: URI; @@ -30,7 +31,11 @@ export interface IMirrorModel { getValue(): string; } -export interface IWorkerContext { +export interface IWorkerContext { + /** + * A proxy to the main thread host object. + */ + host: H; /** * Get all available mirror models in this worker. */ @@ -322,17 +327,53 @@ declare var require: any; /** * @internal */ -export abstract class BaseEditorSimpleWorker { +export class EditorSimpleWorker implements IRequestHandler, IDisposable { + _requestHandlerBrand: any; + + private readonly _host: EditorWorkerHost; + private _models: { [uri: string]: MirrorModel; }; private readonly _foreignModuleFactory: IForeignModuleFactory | null; private _foreignModule: any; - constructor(foreignModuleFactory: IForeignModuleFactory | null) { + constructor(host: EditorWorkerHost, foreignModuleFactory: IForeignModuleFactory | null) { + this._host = host; + this._models = Object.create(null); this._foreignModuleFactory = foreignModuleFactory; this._foreignModule = null; } - protected abstract _getModel(uri: string): ICommonModel; - protected abstract _getModels(): ICommonModel[]; + public dispose(): void { + this._models = Object.create(null); + } + + protected _getModel(uri: string): ICommonModel { + return this._models[uri]; + } + + private _getModels(): ICommonModel[] { + let all: MirrorModel[] = []; + Object.keys(this._models).forEach((key) => all.push(this._models[key])); + return all; + } + + public acceptNewModel(data: IRawModelData): void { + this._models[data.url] = new MirrorModel(URI.parse(data.url), data.lines, data.EOL, data.versionId); + } + + public acceptModelChanged(strURL: string, e: IModelChangedEvent): void { + if (!this._models[strURL]) { + return; + } + let model = this._models[strURL]; + model.onEvents(e); + } + + public acceptRemovedModel(strURL: string): void { + if (!this._models[strURL]) { + return; + } + delete this._models[strURL]; + } // ---- BEGIN diff -------------------------------------------------------------------------- @@ -440,7 +481,7 @@ export abstract class BaseEditorSimpleWorker { } // make sure diff won't take too long - if (Math.max(text.length, original.length) > BaseEditorSimpleWorker._diffLimit) { + if (Math.max(text.length, original.length) > EditorSimpleWorker._diffLimit) { result.push({ range, text }); continue; } @@ -503,7 +544,7 @@ export abstract class BaseEditorSimpleWorker { for ( let iter = model.createWordIterator(wordDefRegExp), e = iter.next(); - !e.done && suggestions.length <= BaseEditorSimpleWorker._suggestionsLimit; + !e.done && suggestions.length <= EditorSimpleWorker._suggestionsLimit; e = iter.next() ) { const word = e.value; @@ -591,8 +632,15 @@ export abstract class BaseEditorSimpleWorker { // ---- BEGIN foreign module support -------------------------------------------------------------------------- - public loadForeignModule(moduleId: string, createData: any): Promise { - let ctx: IWorkerContext = { + public loadForeignModule(moduleId: string, createData: any, foreignHostMethods: string[]): Promise { + const proxyMethodRequest = (method: string, args: any[]): Promise => { + return this._host.fhr(method, args); + }; + + const foreignHost = types.createProxyObject(foreignHostMethods, proxyMethodRequest); + + let ctx: IWorkerContext = { + host: foreignHost, getMirrorModels: (): IMirrorModel[] => { return this._getModels(); } @@ -601,27 +649,14 @@ export abstract class BaseEditorSimpleWorker { if (this._foreignModuleFactory) { this._foreignModule = this._foreignModuleFactory(ctx, createData); // static foreing module - let methods: string[] = []; - for (const prop of getAllPropertyNames(this._foreignModule)) { - if (typeof this._foreignModule[prop] === 'function') { - methods.push(prop); - } - } - return Promise.resolve(methods); + return Promise.resolve(types.getAllMethodNames(this._foreignModule)); } // ESM-comment-begin return new Promise((resolve, reject) => { require([moduleId], (foreignModule: { create: IForeignModuleFactory }) => { this._foreignModule = foreignModule.create(ctx, createData); - let methods: string[] = []; - for (const prop of getAllPropertyNames(this._foreignModule)) { - if (typeof this._foreignModule[prop] === 'function') { - methods.push(prop); - } - } - - resolve(methods); + resolve(types.getAllMethodNames(this._foreignModule)); }, reject); }); @@ -648,59 +683,12 @@ export abstract class BaseEditorSimpleWorker { // ---- END foreign module support -------------------------------------------------------------------------- } -/** - * @internal - */ -export class EditorSimpleWorkerImpl extends BaseEditorSimpleWorker implements IRequestHandler, IDisposable { - _requestHandlerBrand: any; - - private _models: { [uri: string]: MirrorModel; }; - - constructor(foreignModuleFactory: IForeignModuleFactory | null) { - super(foreignModuleFactory); - this._models = Object.create(null); - } - - public dispose(): void { - this._models = Object.create(null); - } - - protected _getModel(uri: string): ICommonModel { - return this._models[uri]; - } - - protected _getModels(): ICommonModel[] { - let all: MirrorModel[] = []; - Object.keys(this._models).forEach((key) => all.push(this._models[key])); - return all; - } - - public acceptNewModel(data: IRawModelData): void { - this._models[data.url] = new MirrorModel(URI.parse(data.url), data.lines, data.EOL, data.versionId); - } - - public acceptModelChanged(strURL: string, e: IModelChangedEvent): void { - if (!this._models[strURL]) { - return; - } - let model = this._models[strURL]; - model.onEvents(e); - } - - public acceptRemovedModel(strURL: string): void { - if (!this._models[strURL]) { - return; - } - delete this._models[strURL]; - } -} - /** * Called on the worker side * @internal */ -export function create(): IRequestHandler { - return new EditorSimpleWorkerImpl(null); +export function create(host: EditorWorkerHost): IRequestHandler { + return new EditorSimpleWorker(host, null); } // This is only available in a Web Worker diff --git a/src/vs/editor/common/services/editorWorkerServiceImpl.ts b/src/vs/editor/common/services/editorWorkerServiceImpl.ts index 97457863d..1d46cc3a2 100644 --- a/src/vs/editor/common/services/editorWorkerServiceImpl.ts +++ b/src/vs/editor/common/services/editorWorkerServiceImpl.ts @@ -4,9 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import { IntervalTimer } from 'vs/base/common/async'; -import { Disposable, IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; -import { SimpleWorkerClient, logOnceWebWorkerWarning } from 'vs/base/common/worker/simpleWorker'; +import { SimpleWorkerClient, logOnceWebWorkerWarning, IWorkerClient } from 'vs/base/common/worker/simpleWorker'; import { DefaultWorkerFactory } from 'vs/base/worker/defaultWorkerFactory'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { IPosition, Position } from 'vs/editor/common/core/position'; @@ -15,7 +15,7 @@ import * as editorCommon from 'vs/editor/common/editorCommon'; import { ITextModel } from 'vs/editor/common/model'; import * as modes from 'vs/editor/common/modes'; import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; -import { EditorSimpleWorkerImpl } from 'vs/editor/common/services/editorSimpleWorker'; +import { EditorSimpleWorker } from 'vs/editor/common/services/editorSimpleWorker'; import { IDiffComputationResult, IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService'; import { IModelService } from 'vs/editor/common/services/modelService'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; @@ -133,6 +133,8 @@ class WordBasedCompletionItemProvider implements modes.CompletionItemProvider { private readonly _configurationService: ITextResourceConfigurationService; private readonly _modelService: IModelService; + readonly _debugDisplayName = 'wordbasedCompletions'; + constructor( workerManager: WorkerManager, configurationService: ITextResourceConfigurationService, @@ -222,12 +224,12 @@ class WorkerManager extends Disposable { class EditorModelManager extends Disposable { - private readonly _proxy: EditorSimpleWorkerImpl; + private readonly _proxy: EditorSimpleWorker; private readonly _modelService: IModelService; - private _syncedModels: { [modelUrl: string]: IDisposable[]; } = Object.create(null); + private _syncedModels: { [modelUrl: string]: IDisposable; } = Object.create(null); private _syncedModelsLastUsedTime: { [modelUrl: string]: number; } = Object.create(null); - constructor(proxy: EditorSimpleWorkerImpl, modelService: IModelService, keepIdleModels: boolean) { + constructor(proxy: EditorSimpleWorker, modelService: IModelService, keepIdleModels: boolean) { super(); this._proxy = proxy; this._modelService = modelService; @@ -248,7 +250,7 @@ class EditorModelManager extends Disposable { super.dispose(); } - public esureSyncedResources(resources: URI[]): void { + public ensureSyncedResources(resources: URI[]): void { for (const resource of resources) { let resourceStr = resource.toString(); @@ -295,14 +297,14 @@ class EditorModelManager extends Disposable { versionId: model.getVersionId() }); - let toDispose: IDisposable[] = []; - toDispose.push(model.onDidChangeContent((e) => { + const toDispose = new DisposableStore(); + toDispose.add(model.onDidChangeContent((e) => { this._proxy.acceptModelChanged(modelUrl.toString(), e); })); - toDispose.push(model.onWillDispose(() => { + toDispose.add(model.onWillDispose(() => { this._stopModelSync(modelUrl); })); - toDispose.push(toDisposable(() => { + toDispose.add(toDisposable(() => { this._proxy.acceptRemovedModel(modelUrl); })); @@ -317,11 +319,6 @@ class EditorModelManager extends Disposable { } } -interface IWorkerClient { - getProxyObject(): Promise; - dispose(): void; -} - class SynchronousWorkerClient implements IWorkerClient { private readonly _instance: T; private readonly _proxyObj: Promise; @@ -340,10 +337,24 @@ class SynchronousWorkerClient implements IWorkerClient } } +export class EditorWorkerHost { + + private readonly _workerClient: EditorWorkerClient; + + constructor(workerClient: EditorWorkerClient) { + this._workerClient = workerClient; + } + + // foreign host request + public fhr(method: string, args: any[]): Promise { + return this._workerClient.fhr(method, args); + } +} + export class EditorWorkerClient extends Disposable { private readonly _modelService: IModelService; - private _worker: IWorkerClient | null; + private _worker: IWorkerClient | null; private readonly _workerFactory: DefaultWorkerFactory; private _modelManager: EditorModelManager | null; @@ -355,39 +366,45 @@ export class EditorWorkerClient extends Disposable { this._modelManager = null; } - private _getOrCreateWorker(): IWorkerClient { + // foreign host request + public fhr(method: string, args: any[]): Promise { + throw new Error(`Not implemented!`); + } + + private _getOrCreateWorker(): IWorkerClient { if (!this._worker) { try { - this._worker = this._register(new SimpleWorkerClient( + this._worker = this._register(new SimpleWorkerClient( this._workerFactory, - 'vs/editor/common/services/editorSimpleWorker' + 'vs/editor/common/services/editorSimpleWorker', + new EditorWorkerHost(this) )); } catch (err) { logOnceWebWorkerWarning(err); - this._worker = new SynchronousWorkerClient(new EditorSimpleWorkerImpl(null)); + this._worker = new SynchronousWorkerClient(new EditorSimpleWorker(new EditorWorkerHost(this), null)); } } return this._worker; } - protected _getProxy(): Promise { + protected _getProxy(): Promise { return this._getOrCreateWorker().getProxyObject().then(undefined, (err) => { logOnceWebWorkerWarning(err); - this._worker = new SynchronousWorkerClient(new EditorSimpleWorkerImpl(null)); + this._worker = new SynchronousWorkerClient(new EditorSimpleWorker(new EditorWorkerHost(this), null)); return this._getOrCreateWorker().getProxyObject(); }); } - private _getOrCreateModelManager(proxy: EditorSimpleWorkerImpl): EditorModelManager { + private _getOrCreateModelManager(proxy: EditorSimpleWorker): EditorModelManager { if (!this._modelManager) { this._modelManager = this._register(new EditorModelManager(proxy, this._modelService, false)); } return this._modelManager; } - protected _withSyncedResources(resources: URI[]): Promise { + protected _withSyncedResources(resources: URI[]): Promise { return this._getProxy().then((proxy) => { - this._getOrCreateModelManager(proxy).esureSyncedResources(resources); + this._getOrCreateModelManager(proxy).ensureSyncedResources(resources); return proxy; }); } diff --git a/src/vs/editor/common/services/getIconClasses.ts b/src/vs/editor/common/services/getIconClasses.ts index ca49de252..fbdc31d6d 100644 --- a/src/vs/editor/common/services/getIconClasses.ts +++ b/src/vs/editor/common/services/getIconClasses.ts @@ -19,14 +19,11 @@ export function getIconClasses(modelService: IModelService, modeService: IModeSe // Get the path and name of the resource. For data-URIs, we need to parse specially let name: string | undefined; - let path: string | undefined; if (resource.scheme === Schemas.data) { const metadata = DataUri.parseMetaData(resource); name = metadata.get(DataUri.META_DATA_LABEL); - path = name; } else { name = cssEscape(basenameOrAuthority(resource).toLowerCase()); - path = resource.path.toLowerCase(); } // Folders @@ -47,46 +44,48 @@ export function getIconClasses(modelService: IModelService, modeService: IModeSe classes.push(`ext-file-icon`); // extra segment to increase file-ext score } - // Configured Language - let configuredLangId: string | null = getConfiguredLangId(modelService, modeService, resource); - configuredLangId = configuredLangId || (path ? modeService.getModeIdByFilepathOrFirstLine(path) : null); - if (configuredLangId) { - classes.push(`${cssEscape(configuredLangId)}-lang-file-icon`); + // Detected Mode + const detectedModeId = detectModeId(modelService, modeService, resource); + if (detectedModeId) { + classes.push(`${cssEscape(detectedModeId)}-lang-file-icon`); } } } return classes; } -export function getConfiguredLangId(modelService: IModelService, modeService: IModeService, resource: uri): string | null { - let configuredLangId: string | null = null; - if (resource) { - let modeId: string | null = null; +export function detectModeId(modelService: IModelService, modeService: IModeService, resource: uri): string | null { + if (!resource) { + return null; // we need a resource at least + } - // Data URI: check for encoded metadata - if (resource.scheme === Schemas.data) { - const metadata = DataUri.parseMetaData(resource); - const mime = metadata.get(DataUri.META_DATA_MIME); + let modeId: string | null = null; - if (mime) { - modeId = modeService.getModeId(mime); - } - } + // Data URI: check for encoded metadata + if (resource.scheme === Schemas.data) { + const metadata = DataUri.parseMetaData(resource); + const mime = metadata.get(DataUri.META_DATA_MIME); - // Any other URI: check for model if existing - else { - const model = modelService.getModel(resource); - if (model) { - modeId = model.getLanguageIdentifier().language; - } + if (mime) { + modeId = modeService.getModeId(mime); } + } - if (modeId && modeId !== PLAINTEXT_MODE_ID) { - configuredLangId = modeId; // only take if the mode is specific (aka no just plain text) + // Any other URI: check for model if existing + else { + const model = modelService.getModel(resource); + if (model) { + modeId = model.getModeId(); } } - return configuredLangId; + // only take if the mode is specific (aka no just plain text) + if (modeId && modeId !== PLAINTEXT_MODE_ID) { + return modeId; + } + + // otherwise fallback to path based detection + return modeService.getModeIdByFilepathOrFirstLine(resource); } export function cssEscape(val: string): string { diff --git a/src/vs/editor/common/services/languagesRegistry.ts b/src/vs/editor/common/services/languagesRegistry.ts index 9e5e79223..8a12a471f 100644 --- a/src/vs/editor/common/services/languagesRegistry.ts +++ b/src/vs/editor/common/services/languagesRegistry.ts @@ -323,11 +323,11 @@ export class LanguagesRegistry extends Disposable { return []; } - public getModeIdsFromFilepathOrFirstLine(filepath: string | null, firstLine?: string): string[] { - if (!filepath && !firstLine) { + public getModeIdsFromFilepathOrFirstLine(resource: URI | null, firstLine?: string): string[] { + if (!resource && !firstLine) { return []; } - let mimeTypes = mime.guessMimeTypes(filepath, firstLine); + let mimeTypes = mime.guessMimeTypes(resource, firstLine); return this.extractModeIds(mimeTypes.join(',')); } diff --git a/src/vs/editor/common/services/markerDecorationsServiceImpl.ts b/src/vs/editor/common/services/markerDecorationsServiceImpl.ts index 0b6e25eac..3da62fed1 100644 --- a/src/vs/editor/common/services/markerDecorationsServiceImpl.ts +++ b/src/vs/editor/common/services/markerDecorationsServiceImpl.ts @@ -63,10 +63,10 @@ export class MarkerDecorationsService extends Disposable implements IMarkerDecor _serviceBrand: any; - private readonly _onDidChangeMarker = new Emitter(); + private readonly _onDidChangeMarker = this._register(new Emitter()); readonly onDidChangeMarker: Event = this._onDidChangeMarker.event; - private readonly _markerDecorations: Map = new Map(); + private readonly _markerDecorations = new Map(); constructor( @IModelService modelService: IModelService, @@ -79,6 +79,12 @@ export class MarkerDecorationsService extends Disposable implements IMarkerDecor this._register(this._markerService.onMarkerChanged(this._handleMarkerChange, this)); } + dispose() { + super.dispose(); + this._markerDecorations.forEach(value => value.dispose()); + this._markerDecorations.clear(); + } + getMarker(model: ITextModel, decoration: IModelDecoration): IMarker | null { const markerDecorations = this._markerDecorations.get(MODEL_ID(model.uri)); return markerDecorations ? withUndefinedAsNull(markerDecorations.getMarker(decoration)) : null; @@ -215,6 +221,9 @@ export class MarkerDecorationsService extends Disposable implements IMarkerDecor if (marker.tags.indexOf(MarkerTag.Unnecessary) !== -1) { inlineClassName = ClassName.EditorUnnecessaryInlineDecoration; } + if (marker.tags.indexOf(MarkerTag.Deprecated) !== -1) { + inlineClassName = ClassName.EditorDeprecatedInlineDecoration; + } } return { diff --git a/src/vs/editor/common/services/modeService.ts b/src/vs/editor/common/services/modeService.ts index de852f670..fd01515a9 100644 --- a/src/vs/editor/common/services/modeService.ts +++ b/src/vs/editor/common/services/modeService.ts @@ -41,7 +41,7 @@ export interface IModeService { getMimeForMode(modeId: string): string | null; getLanguageName(modeId: string): string | null; getModeIdForLanguageName(alias: string): string | null; - getModeIdByFilepathOrFirstLine(filepath: string, firstLine?: string): string | null; + getModeIdByFilepathOrFirstLine(resource: URI, firstLine?: string): string | null; getModeId(commaSeparatedMimetypesOrCommaSeparatedIds: string): string | null; getLanguageIdentifier(modeId: string | LanguageId): LanguageIdentifier | null; getConfigurationFiles(modeId: string): URI[]; @@ -49,7 +49,7 @@ export interface IModeService { // --- instantiation create(commaSeparatedMimetypesOrCommaSeparatedIds: string | undefined): ILanguageSelection; createByLanguageName(languageName: string): ILanguageSelection; - createByFilepathOrFirstLine(filepath: string | null, firstLine?: string): ILanguageSelection; + createByFilepathOrFirstLine(rsource: URI | null, firstLine?: string): ILanguageSelection; triggerMode(commaSeparatedMimetypesOrCommaSeparatedIds: string): void; } diff --git a/src/vs/editor/common/services/modeServiceImpl.ts b/src/vs/editor/common/services/modeServiceImpl.ts index 9b4667220..30ac27d49 100644 --- a/src/vs/editor/common/services/modeServiceImpl.ts +++ b/src/vs/editor/common/services/modeServiceImpl.ts @@ -94,8 +94,8 @@ export class ModeServiceImpl implements IModeService { return this._registry.getModeIdForLanguageNameLowercase(alias); } - public getModeIdByFilepathOrFirstLine(filepath: string | null, firstLine?: string): string | null { - const modeIds = this._registry.getModeIdsFromFilepathOrFirstLine(filepath, firstLine); + public getModeIdByFilepathOrFirstLine(resource: URI | null, firstLine?: string): string | null { + const modeIds = this._registry.getModeIdsFromFilepathOrFirstLine(resource, firstLine); if (modeIds.length > 0) { return modeIds[0]; @@ -138,9 +138,9 @@ export class ModeServiceImpl implements IModeService { }); } - public createByFilepathOrFirstLine(filepath: string | null, firstLine?: string): ILanguageSelection { + public createByFilepathOrFirstLine(resource: URI | null, firstLine?: string): ILanguageSelection { return new LanguageSelection(this.onLanguagesMaybeChanged, () => { - const modeId = this.getModeIdByFilepathOrFirstLine(filepath, firstLine); + const modeId = this.getModeIdByFilepathOrFirstLine(resource, firstLine); return this._createModeAndGetLanguageIdentifier(modeId); }); } diff --git a/src/vs/editor/common/services/modelServiceImpl.ts b/src/vs/editor/common/services/modelServiceImpl.ts index 166bec43d..00a95b42c 100644 --- a/src/vs/editor/common/services/modelServiceImpl.ts +++ b/src/vs/editor/common/services/modelServiceImpl.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Emitter, Event } from 'vs/base/common/event'; -import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import * as platform from 'vs/base/common/platform'; import { URI } from 'vs/base/common/uri'; import { EDITOR_MODEL_DEFAULTS } from 'vs/editor/common/config/editorOptions'; @@ -30,7 +30,7 @@ class ModelData implements IDisposable { private _languageSelection: ILanguageSelection | null; private _languageSelectionListener: IDisposable | null; - private _modelEventListeners: IDisposable[]; + private readonly _modelEventListeners = new DisposableStore(); constructor( model: ITextModel, @@ -42,9 +42,8 @@ class ModelData implements IDisposable { this._languageSelection = null; this._languageSelectionListener = null; - this._modelEventListeners = []; - this._modelEventListeners.push(model.onWillDispose(() => onWillDispose(model))); - this._modelEventListeners.push(model.onDidChangeLanguage((e) => onDidChangeLanguage(model, e))); + this._modelEventListeners.add(model.onWillDispose(() => onWillDispose(model))); + this._modelEventListeners.add(model.onDidChangeLanguage((e) => onDidChangeLanguage(model, e))); } private _disposeLanguageSelection(): void { @@ -59,7 +58,7 @@ class ModelData implements IDisposable { } public dispose(): void { - this._modelEventListeners = dispose(this._modelEventListeners); + this._modelEventListeners.dispose(); this._disposeLanguageSelection(); } diff --git a/src/vs/editor/common/services/resolverService.ts b/src/vs/editor/common/services/resolverService.ts index 442813334..958469e16 100644 --- a/src/vs/editor/common/services/resolverService.ts +++ b/src/vs/editor/common/services/resolverService.ts @@ -5,7 +5,7 @@ import { IDisposable, IReference } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; -import { ITextModel } from 'vs/editor/common/model'; +import { ITextModel, ITextSnapshot } from 'vs/editor/common/model'; import { IEditorModel } from 'vs/platform/editor/common/editor'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; @@ -46,6 +46,12 @@ export interface ITextEditorModel extends IEditorModel { */ readonly textEditorModel: ITextModel | null; + /** + * Creates a snapshot of the model's contents. + */ + createSnapshot(this: IResolvedTextEditorModel): ITextSnapshot; + createSnapshot(this: ITextEditorModel): ITextSnapshot | null; + isReadonly(): boolean; } diff --git a/src/vs/editor/common/services/resourceConfiguration.ts b/src/vs/editor/common/services/resourceConfiguration.ts index 79e3624f4..311556df8 100644 --- a/src/vs/editor/common/services/resourceConfiguration.ts +++ b/src/vs/editor/common/services/resourceConfiguration.ts @@ -25,7 +25,7 @@ export interface ITextResourceConfigurationService { * Value can be of native type or an object keyed off the section name. * * @param resource - Resource for which the configuration has to be fetched. - * @param postion - Position in the resource for which configuration has to be fetched. + * @param position - Position in the resource for which configuration has to be fetched. * @param section - Section of the configuraion. * */ diff --git a/src/vs/editor/common/services/resourceConfigurationImpl.ts b/src/vs/editor/common/services/resourceConfigurationImpl.ts index b9353553d..7ca815e37 100644 --- a/src/vs/editor/common/services/resourceConfigurationImpl.ts +++ b/src/vs/editor/common/services/resourceConfigurationImpl.ts @@ -50,7 +50,7 @@ export class TextResourceConfigurationService extends Disposable implements ITex if (model) { return position ? this.modeService.getLanguageIdentifier(model.getLanguageIdAtPosition(position.lineNumber, position.column))!.language : model.getLanguageIdentifier().language; } - return this.modeService.getModeIdByFilepathOrFirstLine(resource.path); + return this.modeService.getModeIdByFilepathOrFirstLine(resource); } } \ No newline at end of file diff --git a/src/vs/editor/common/services/webWorker.ts b/src/vs/editor/common/services/webWorker.ts index a75cd9773..0ae55dffa 100644 --- a/src/vs/editor/common/services/webWorker.ts +++ b/src/vs/editor/common/services/webWorker.ts @@ -6,6 +6,7 @@ import { URI } from 'vs/base/common/uri'; import { EditorWorkerClient } from 'vs/editor/common/services/editorWorkerServiceImpl'; import { IModelService } from 'vs/editor/common/services/modelService'; +import * as types from 'vs/base/common/types'; /** * Create a new web worker that has model syncing capabilities built in. @@ -48,11 +49,16 @@ export interface IWebWorkerOptions { * A label to be used to identify the web worker for debugging purposes. */ label?: string; + /** + * An object that can be used by the web worker to make calls back to the main thread. + */ + host?: any; } class MonacoWebWorkerImpl extends EditorWorkerClient implements MonacoWebWorker { private readonly _foreignModuleId: string; + private readonly _foreignModuleHost: { [method: string]: Function } | null; private _foreignModuleCreateData: any | null; private _foreignProxy: Promise | null; @@ -60,13 +66,28 @@ class MonacoWebWorkerImpl extends EditorWorkerClient implements MonacoWebWork super(modelService, opts.label); this._foreignModuleId = opts.moduleId; this._foreignModuleCreateData = opts.createData || null; + this._foreignModuleHost = opts.host || null; this._foreignProxy = null; } + // foreign host request + public fhr(method: string, args: any[]): Promise { + if (!this._foreignModuleHost || typeof this._foreignModuleHost[method] !== 'function') { + return Promise.reject(new Error('Missing method ' + method + ' or missing main thread foreign host.')); + } + + try { + return Promise.resolve(this._foreignModuleHost[method].apply(this._foreignModuleHost, args)); + } catch (e) { + return Promise.reject(e); + } + } + private _getForeignProxy(): Promise { if (!this._foreignProxy) { this._foreignProxy = this._getProxy().then((proxy) => { - return proxy.loadForeignModule(this._foreignModuleId, this._foreignModuleCreateData).then((foreignMethods) => { + const foreignHostMethods = this._foreignModuleHost ? types.getAllMethodNames(this._foreignModuleHost) : []; + return proxy.loadForeignModule(this._foreignModuleId, this._foreignModuleCreateData, foreignHostMethods).then((foreignMethods) => { this._foreignModuleCreateData = null; const proxyMethodRequest = (method: string, args: any[]): Promise => { diff --git a/src/vs/editor/common/standalone/standaloneEnums.ts b/src/vs/editor/common/standalone/standaloneEnums.ts index 113afbafc..46d295d23 100644 --- a/src/vs/editor/common/standalone/standaloneEnums.ts +++ b/src/vs/editor/common/standalone/standaloneEnums.ts @@ -7,7 +7,8 @@ export enum MarkerTag { - Unnecessary = 1 + Unnecessary = 1, + Deprecated = 2 } export enum MarkerSeverity { @@ -228,6 +229,13 @@ export enum OverviewRulerLane { Full = 7 } +/** + * Position in the minimap to render the decoration. + */ +export enum MinimapPosition { + Inline = 1 +} + /** * End of line character preference. */ diff --git a/src/vs/editor/common/view/editorColorRegistry.ts b/src/vs/editor/common/view/editorColorRegistry.ts index 27ccaf58e..23d5e072b 100644 --- a/src/vs/editor/common/view/editorColorRegistry.ts +++ b/src/vs/editor/common/view/editorColorRegistry.ts @@ -5,7 +5,7 @@ import * as nls from 'vs/nls'; import { Color, RGBA } from 'vs/base/common/color'; -import { activeContrastBorder, editorBackground, editorForeground, registerColor } from 'vs/platform/theme/common/colorRegistry'; +import { activeContrastBorder, editorBackground, editorForeground, registerColor, editorWarningForeground, editorInfoForeground, editorWarningBorder, editorInfoBorder, contrastBorder } from 'vs/platform/theme/common/colorRegistry'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; /** @@ -31,32 +31,20 @@ export const editorRuler = registerColor('editorRuler.foreground', { dark: '#5A5 export const editorCodeLensForeground = registerColor('editorCodeLens.foreground', { dark: '#999999', light: '#999999', hc: '#999999' }, nls.localize('editorCodeLensForeground', 'Foreground color of editor code lenses')); export const editorBracketMatchBackground = registerColor('editorBracketMatch.background', { dark: '#0064001a', light: '#0064001a', hc: '#0064001a' }, nls.localize('editorBracketMatchBackground', 'Background color behind matching brackets')); -export const editorBracketMatchBorder = registerColor('editorBracketMatch.border', { dark: '#888', light: '#B9B9B9', hc: '#fff' }, nls.localize('editorBracketMatchBorder', 'Color for matching brackets boxes')); +export const editorBracketMatchBorder = registerColor('editorBracketMatch.border', { dark: '#888', light: '#B9B9B9', hc: contrastBorder }, nls.localize('editorBracketMatchBorder', 'Color for matching brackets boxes')); export const editorOverviewRulerBorder = registerColor('editorOverviewRuler.border', { dark: '#7f7f7f4d', light: '#7f7f7f4d', hc: '#7f7f7f4d' }, nls.localize('editorOverviewRulerBorder', 'Color of the overview ruler border.')); export const editorGutter = registerColor('editorGutter.background', { dark: editorBackground, light: editorBackground, hc: editorBackground }, nls.localize('editorGutter', 'Background color of the editor gutter. The gutter contains the glyph margins and the line numbers.')); -export const editorErrorForeground = registerColor('editorError.foreground', { dark: '#ea4646', light: '#d60a0a', hc: null }, nls.localize('errorForeground', 'Foreground color of error squigglies in the editor.')); -export const editorErrorBorder = registerColor('editorError.border', { dark: null, light: null, hc: Color.fromHex('#E47777').transparent(0.8) }, nls.localize('errorBorder', 'Border color of error squigglies in the editor.')); - -export const editorWarningForeground = registerColor('editorWarning.foreground', { dark: '#4d9e4d', light: '#117711', 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.')); - -export const editorHintForeground = registerColor('editorHint.foreground', { dark: Color.fromHex('#eeeeee').transparent(0.7), light: '#6c6c6c', hc: null }, nls.localize('hintForeground', 'Foreground color of hint squigglies in the editor.')); -export const editorHintBorder = registerColor('editorHint.border', { dark: null, light: null, hc: Color.fromHex('#eeeeee').transparent(0.8) }, nls.localize('hintBorder', 'Border color of hint squigglies in the editor.')); - export const editorUnnecessaryCodeBorder = registerColor('editorUnnecessaryCode.border', { dark: null, light: null, hc: Color.fromHex('#fff').transparent(0.8) }, nls.localize('unnecessaryCodeBorder', 'Border color of unnecessary (unused) source code in the editor.')); export const editorUnnecessaryCodeOpacity = registerColor('editorUnnecessaryCode.opacity', { dark: Color.fromHex('#000a'), light: Color.fromHex('#0007'), hc: null }, nls.localize('unnecessaryCodeOpacity', 'Opacity of unnecessary (unused) source code in the editor. For example, "#000000c0" will render the code with 75% opacity. For high contrast themes, use the \'editorUnnecessaryCode.border\' theme color to underline unnecessary code instead of fading it out.')); 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. The color must not be opaque so as not to hide underlying decorations.'), true); 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.')); -export const overviewRulerWarning = registerColor('editorOverviewRuler.warningForeground', { dark: new Color(new RGBA(18, 136, 18, 0.7)), light: new Color(new RGBA(18, 136, 18, 0.7)), hc: new Color(new RGBA(50, 255, 50, 1)) }, nls.localize('overviewRuleWarning', 'Overview ruler marker color for warnings.')); -export const overviewRulerInfo = registerColor('editorOverviewRuler.infoForeground', { dark: new Color(new RGBA(18, 18, 136, 0.7)), light: new Color(new RGBA(18, 18, 136, 0.7)), hc: new Color(new RGBA(50, 50, 255, 1)) }, nls.localize('overviewRuleInfo', 'Overview ruler marker color for infos.')); +export const overviewRulerWarning = registerColor('editorOverviewRuler.warningForeground', { dark: editorWarningForeground, light: editorWarningForeground, hc: editorWarningBorder }, nls.localize('overviewRuleWarning', 'Overview ruler marker color for warnings.')); +export const overviewRulerInfo = registerColor('editorOverviewRuler.infoForeground', { dark: editorInfoForeground, light: editorInfoForeground, hc: editorInfoBorder }, nls.localize('overviewRuleInfo', 'Overview ruler marker color for infos.')); // contains all color rules that used to defined in editor/browser/widget/editor.css registerThemingParticipant((theme, collector) => { diff --git a/src/vs/editor/common/viewLayout/viewLineRenderer.ts b/src/vs/editor/common/viewLayout/viewLineRenderer.ts index f1b5c0422..bbb9b39cb 100644 --- a/src/vs/editor/common/viewLayout/viewLineRenderer.ts +++ b/src/vs/editor/common/viewLayout/viewLineRenderer.ts @@ -13,7 +13,8 @@ import { InlineDecorationType } from 'vs/editor/common/viewModel/viewModel'; export const enum RenderWhitespace { None = 0, Boundary = 1, - All = 2 + Selection = 2, + All = 3 } class LinePart { @@ -31,6 +32,28 @@ class LinePart { } } +export class LineRange { + /** + * Zero-based offset on which the range starts, inclusive. + */ + public readonly startOffset: number; + + /** + * Zero-based offset on which the range ends, inclusive. + */ + public readonly endOffset: number; + + constructor(startIndex: number, endIndex: number) { + this.startOffset = startIndex; + this.endOffset = endIndex; + } + + public equals(otherLineRange: LineRange) { + return this.startOffset === otherLineRange.startOffset + && this.endOffset === otherLineRange.endOffset; + } +} + export class RenderLineInput { public readonly useMonospaceOptimizations: boolean; @@ -49,6 +72,12 @@ export class RenderLineInput { public readonly renderControlCharacters: boolean; public readonly fontLigatures: boolean; + /** + * Defined only when renderWhitespace is 'selection'. Selections are non-overlapping, + * and ordered by position within the line. + */ + public readonly selectionsOnLine: LineRange[] | null; + constructor( useMonospaceOptimizations: boolean, canUseHalfwidthRightwardsArrow: boolean, @@ -62,9 +91,10 @@ export class RenderLineInput { tabSize: number, spaceWidth: number, stopRenderingLineAfter: number, - renderWhitespace: 'none' | 'boundary' | 'all', + renderWhitespace: 'none' | 'boundary' | 'selection' | 'all', renderControlCharacters: boolean, - fontLigatures: boolean + fontLigatures: boolean, + selectionsOnLine: LineRange[] | null ) { this.useMonospaceOptimizations = useMonospaceOptimizations; this.canUseHalfwidthRightwardsArrow = canUseHalfwidthRightwardsArrow; @@ -83,10 +113,35 @@ export class RenderLineInput { ? RenderWhitespace.All : renderWhitespace === 'boundary' ? RenderWhitespace.Boundary - : RenderWhitespace.None + : renderWhitespace === 'selection' + ? RenderWhitespace.Selection + : RenderWhitespace.None ); this.renderControlCharacters = renderControlCharacters; this.fontLigatures = fontLigatures; + this.selectionsOnLine = selectionsOnLine && selectionsOnLine.sort((a, b) => a.startOffset < b.startOffset ? -1 : 1); + } + + private sameSelection(otherSelections: LineRange[] | null): boolean { + if (this.selectionsOnLine === null) { + return otherSelections === null; + } + + if (otherSelections === null) { + return false; + } + + if (otherSelections.length !== this.selectionsOnLine.length) { + return false; + } + + for (let i = 0; i < this.selectionsOnLine.length; i++) { + if (!this.selectionsOnLine[i].equals(otherSelections[i])) { + return false; + } + } + + return true; } public equals(other: RenderLineInput): boolean { @@ -106,6 +161,7 @@ export class RenderLineInput { && this.fontLigatures === other.fontLigatures && LineDecoration.equalsArr(this.lineDecorations, other.lineDecorations) && this.lineTokens.equals(other.lineTokens) + && this.sameSelection(other.selectionsOnLine) ); } } @@ -338,8 +394,8 @@ function resolveRenderLineInput(input: RenderLineInput): ResolvedRenderLineInput } let tokens = transformAndRemoveOverflowing(input.lineTokens, input.fauxIndentLength, len); - if (input.renderWhitespace === RenderWhitespace.All || input.renderWhitespace === RenderWhitespace.Boundary) { - tokens = _applyRenderWhitespace(lineContent, len, input.continuesWithWrappedLine, tokens, input.fauxIndentLength, input.tabSize, useMonospaceOptimizations, input.renderWhitespace === RenderWhitespace.Boundary); + if (input.renderWhitespace === RenderWhitespace.All || input.renderWhitespace === RenderWhitespace.Boundary || (input.renderWhitespace === RenderWhitespace.Selection && !!input.selectionsOnLine)) { + tokens = _applyRenderWhitespace(lineContent, len, input.continuesWithWrappedLine, tokens, input.fauxIndentLength, input.tabSize, useMonospaceOptimizations, input.selectionsOnLine, input.renderWhitespace === RenderWhitespace.Boundary); } let containsForeignElements = ForeignElementType.None; if (input.lineDecorations.length > 0) { @@ -481,7 +537,7 @@ function splitLargeTokens(lineContent: string, tokens: LinePart[], onlyAtSpaces: * Moreover, a token is created for every visual indent because on some fonts the glyphs used for rendering whitespace (→ or ·) do not have the same width as  . * The rendering phase will generate `style="width:..."` for these tokens. */ -function _applyRenderWhitespace(lineContent: string, len: number, continuesWithWrappedLine: boolean, tokens: LinePart[], fauxIndentLength: number, tabSize: number, useMonospaceOptimizations: boolean, onlyBoundary: boolean): LinePart[] { +function _applyRenderWhitespace(lineContent: string, len: number, continuesWithWrappedLine: boolean, tokens: LinePart[], fauxIndentLength: number, tabSize: number, useMonospaceOptimizations: boolean, selections: LineRange[] | null, onlyBoundary: boolean): LinePart[] { let result: LinePart[] = [], resultLen = 0; let tokenIndex = 0; @@ -511,11 +567,17 @@ function _applyRenderWhitespace(lineContent: string, len: number, continuesWithW } } tmpIndent = tmpIndent % tabSize; - let wasInWhitespace = false; + let currentSelectionIndex = 0; + let currentSelection = selections && selections[currentSelectionIndex]; for (let charIndex = fauxIndentLength; charIndex < len; charIndex++) { const chCode = lineContent.charCodeAt(charIndex); + if (currentSelection && charIndex >= currentSelection.endOffset) { + currentSelectionIndex++; + currentSelection = selections && selections[currentSelectionIndex]; + } + let isInWhitespace: boolean; if (charIndex < firstNonWhitespaceIndex || charIndex > lastNonWhitespaceIndex) { // in leading or trailing whitespace @@ -540,6 +602,11 @@ function _applyRenderWhitespace(lineContent: string, len: number, continuesWithW isInWhitespace = false; } + // If rendering whitespace on selection, check that the charIndex falls within a selection + if (isInWhitespace && selections) { + isInWhitespace = !!currentSelection && currentSelection.startOffset <= charIndex && currentSelection.endOffset > charIndex; + } + if (wasInWhitespace) { // was in whitespace token if (!isInWhitespace || (!useMonospaceOptimizations && tmpIndent >= tabSize)) { diff --git a/src/vs/editor/common/viewModel/splitLinesCollection.ts b/src/vs/editor/common/viewModel/splitLinesCollection.ts index 75b8b3739..f593fdbc5 100644 --- a/src/vs/editor/common/viewModel/splitLinesCollection.ts +++ b/src/vs/editor/common/viewModel/splitLinesCollection.ts @@ -13,6 +13,7 @@ import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { PrefixSumComputerWithCache } from 'vs/editor/common/viewModel/prefixSumComputer'; import { ICoordinatesConverter, IOverviewRulerDecorations, ViewLineData } from 'vs/editor/common/viewModel/viewModel'; import { ITheme } from 'vs/platform/theme/common/themeService'; +import { IDisposable } from 'vs/base/common/lifecycle'; export class OutputPosition { _outputPositionBrand: void; @@ -62,11 +63,9 @@ export interface ISplitLine { getViewLineNumberOfModelPosition(deltaLineNumber: number, inputColumn: number): number; } -export interface IViewModelLinesCollection { +export interface IViewModelLinesCollection extends IDisposable { createCoordinatesConverter(): ICoordinatesConverter; - dispose(): void; - setWrappingSettings(wrappingIndent: WrappingIndent, wrappingColumn: number, columnsForFullWidthChar: number): boolean; setTabSize(newTabSize: number): boolean; getHiddenAreas(): Range[]; diff --git a/src/vs/editor/common/viewModel/viewModel.ts b/src/vs/editor/common/viewModel/viewModel.ts index 1c889284c..fe832ef37 100644 --- a/src/vs/editor/common/viewModel/viewModel.ts +++ b/src/vs/editor/common/viewModel/viewModel.ts @@ -141,6 +141,7 @@ export interface IViewModel { getLineLastNonWhitespaceColumn(lineNumber: number): number; getAllOverviewRulerDecorations(theme: ITheme): IOverviewRulerDecorations; invalidateOverviewRulerColorCache(): void; + invalidateMinimapColorCache(): void; getValueInRange(range: Range, eol: EndOfLinePreference): string; getModelLineMaxColumn(modelLineNumber: number): number; diff --git a/src/vs/editor/common/viewModel/viewModelImpl.ts b/src/vs/editor/common/viewModel/viewModelImpl.ts index e721c4af6..65284147a 100644 --- a/src/vs/editor/common/viewModel/viewModelImpl.ts +++ b/src/vs/editor/common/viewModel/viewModelImpl.ts @@ -6,12 +6,12 @@ import { Color } from 'vs/base/common/color'; import { IDisposable } from 'vs/base/common/lifecycle'; import * as strings from 'vs/base/common/strings'; -import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; +import { IConfigurationChangedEvent, EDITOR_FONT_DEFAULTS } from 'vs/editor/common/config/editorOptions'; import { IPosition, Position } from 'vs/editor/common/core/position'; import { IRange, Range } from 'vs/editor/common/core/range'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { EndOfLinePreference, IActiveIndentGuideInfo, ITextModel, TrackedRangeStickiness, TextModelResolvedOptions } from 'vs/editor/common/model'; -import { ModelDecorationOverviewRulerOptions } from 'vs/editor/common/model/textModel'; +import { ModelDecorationOverviewRulerOptions, ModelDecorationMinimapOptions } from 'vs/editor/common/model/textModel'; import * as textModelEvents from 'vs/editor/common/model/textModelEvents'; import { ColorId, LanguageId, TokenizationRegistry } from 'vs/editor/common/modes'; import { tokenizeLineToHTML } from 'vs/editor/common/modes/textToHtmlTokenizer'; @@ -565,6 +565,16 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel } } + public invalidateMinimapColorCache(): void { + const decorations = this.model.getAllDecorations(); + for (const decoration of decorations) { + const opts = decoration.options.minimap; + if (opts) { + opts.invalidateCachedColor(); + } + } + } + public getValueInRange(range: Range, eol: EndOfLinePreference): string { const modelRange = this.coordinatesConverter.convertViewRangeToModelRange(range); return this.model.getValueInRange(modelRange, eol); @@ -658,12 +668,13 @@ export class ViewModel extends viewEvents.ViewEventEmitter implements IViewModel const fontInfo = this.configuration.editor.fontInfo; const colorMap = this._getColorMap(); + const fontFamily = fontInfo.fontFamily === EDITOR_FONT_DEFAULTS.fontFamily ? fontInfo.fontFamily : `'${fontInfo.fontFamily}', ${EDITOR_FONT_DEFAULTS.fontFamily}`; return ( `
{ return Promise.resolve(provider.provideCodeActions(model, rangeOrSelection, codeActionContext, cts.token)).then(providedCodeActions => { - if (cts.token.isCancellationRequested || !Array.isArray(providedCodeActions)) { + if (cts.token.isCancellationRequested || !providedCodeActions) { return []; } - return providedCodeActions.filter(action => action && filtersAction(filter, action)); + disposables.add(providedCodeActions); + return providedCodeActions.actions.filter(action => action && filtersAction(filter, action)); }, (err): CodeAction[] => { if (isPromiseCanceledError(err)) { throw err; @@ -84,7 +94,7 @@ export function getCodeActions( return Promise.all(promises) .then(flatten) - .then(actions => new CodeActionSet(actions)) + .then(actions => new ManagedCodeActionSet(actions, disposables)) .finally(() => { listener.dispose(); cts.dispose(); @@ -106,7 +116,7 @@ function getCodeActionProviders( }); } -registerLanguageCommand('_executeCodeActionProvider', function (accessor, args): Promise> { +registerLanguageCommand('_executeCodeActionProvider', async function (accessor, args): Promise> { const { resource, range, kind } = args; if (!(resource instanceof URI) || !Range.isIRange(range)) { throw illegalArgument(); @@ -117,9 +127,12 @@ registerLanguageCommand('_executeCodeActionProvider', function (accessor, args): throw illegalArgument(); } - return getCodeActions( + const codeActionSet = await getCodeActions( model, model.validateRange(range), { type: 'manual', filter: { includeSourceActions: true, kind: kind && kind.value ? new CodeActionKind(kind.value) : undefined } }, - CancellationToken.None).then(actions => actions.actions); + CancellationToken.None); + + setTimeout(() => codeActionSet.dispose(), 0); + return codeActionSet.actions; }); diff --git a/src/vs/editor/contrib/codeAction/codeActionCommands.ts b/src/vs/editor/contrib/codeAction/codeActionCommands.ts index 28e7a707b..1b76fa157 100644 --- a/src/vs/editor/contrib/codeAction/codeActionCommands.ts +++ b/src/vs/editor/contrib/codeAction/codeActionCommands.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { CancelablePromise } from 'vs/base/common/async'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { Disposable } from 'vs/base/common/lifecycle'; import { escapeRegExpCharacters } from 'vs/base/common/strings'; @@ -13,21 +12,21 @@ import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService'; import { IEditorContribution } from 'vs/editor/common/editorCommon'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { CodeAction } from 'vs/editor/common/modes'; +import { CodeActionUi } from 'vs/editor/contrib/codeAction/codeActionUi'; import { MessageController } from 'vs/editor/contrib/message/messageController'; import * as nls from 'vs/nls'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { IMarkerService } from 'vs/platform/markers/common/markers'; -import { IProgressService } from 'vs/platform/progress/common/progress'; -import { CodeActionModel, SUPPORTED_CODE_ACTIONS, CodeActionsState } from './codeActionModel'; -import { CodeActionAutoApply, CodeActionFilter, CodeActionKind } from './codeActionTrigger'; -import { CodeActionContextMenu } from './codeActionWidget'; -import { LightBulbWidget } from './lightBulbWidget'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { onUnexpectedError } from 'vs/base/common/errors'; +import { IMarkerService } from 'vs/platform/markers/common/markers'; +import { IEditorProgressService } from 'vs/platform/progress/common/progress'; +import { CodeActionModel, CodeActionsState, SUPPORTED_CODE_ACTIONS } from './codeActionModel'; +import { CodeActionAutoApply, CodeActionFilter, CodeActionKind, CodeActionTrigger } from './codeActionTrigger'; import { CodeActionSet } from 'vs/editor/contrib/codeAction/codeAction'; +import { IAnchor } from 'vs/base/browser/ui/contextview/contextview'; +import { IPosition } from 'vs/editor/common/core/position'; function contextKeyForSupportedActions(kind: CodeActionKind) { return ContextKeyExpr.regex( @@ -35,6 +34,7 @@ function contextKeyForSupportedActions(kind: CodeActionKind) { new RegExp('(\\s|^)' + escapeRegExpCharacters(kind.value) + '\\b')); } + export class QuickFixController extends Disposable implements IEditorContribution { private static readonly ID = 'editor.contrib.quickFixController'; @@ -45,104 +45,68 @@ export class QuickFixController extends Disposable implements IEditorContributio private readonly _editor: ICodeEditor; private readonly _model: CodeActionModel; - private readonly _codeActionContextMenu: CodeActionContextMenu; - private readonly _lightBulbWidget: LightBulbWidget; - - private _activeRequest: CancelablePromise | undefined; + private readonly _ui: CodeActionUi; constructor( editor: ICodeEditor, @IMarkerService markerService: IMarkerService, @IContextKeyService contextKeyService: IContextKeyService, - @IProgressService progressService: IProgressService, + @IEditorProgressService progressService: IEditorProgressService, @IContextMenuService contextMenuService: IContextMenuService, + @IKeybindingService keybindingService: IKeybindingService, @ICommandService private readonly _commandService: ICommandService, - @IKeybindingService private readonly _keybindingService: IKeybindingService, @IBulkEditService private readonly _bulkEditService: IBulkEditService, ) { super(); this._editor = editor; - this._model = new CodeActionModel(this._editor, markerService, contextKeyService, progressService); - this._codeActionContextMenu = new CodeActionContextMenu(editor, contextMenuService, action => this._onApplyCodeAction(action)); - this._lightBulbWidget = this._register(new LightBulbWidget(editor)); - - this._updateLightBulbTitle(); - - this._register(this._codeActionContextMenu.onDidExecuteCodeAction(_ => this._model.trigger({ type: 'auto', filter: {} }))); - this._register(this._lightBulbWidget.onClick(this._handleLightBulbSelect, this)); - this._register(this._model.onDidChangeState(e => this._onDidChangeCodeActionsState(e))); - this._register(this._keybindingService.onDidUpdateKeybindings(this._updateLightBulbTitle, this)); + this._model = this._register(new CodeActionModel(this._editor, markerService, contextKeyService, progressService)); + this._register(this._model.onDidChangeState((newState) => this.update(newState))); + + this._ui = this._register(new CodeActionUi(editor, QuickFixAction.Id, { + applyCodeAction: async (action, retrigger) => { + try { + await this._applyCodeAction(action); + } finally { + if (retrigger) { + this._trigger({ type: 'auto', filter: {} }); + } + } + } + }, contextMenuService, keybindingService)); } - public dispose(): void { - super.dispose(); - this._model.dispose(); + private update(newState: CodeActionsState.State): void { + this._ui.update(newState); } - private _onDidChangeCodeActionsState(newState: CodeActionsState.State): void { - if (this._activeRequest) { - this._activeRequest.cancel(); - this._activeRequest = undefined; - } - - if (newState.type === CodeActionsState.Type.Triggered) { - this._activeRequest = newState.actions; - - if (newState.trigger.filter && newState.trigger.filter.kind) { - // Triggered for specific scope - newState.actions.then(fixes => { - if (fixes.actions.length > 0) { - // Apply if we only have one action or requested autoApply - if (newState.trigger.autoApply === CodeActionAutoApply.First || (newState.trigger.autoApply === CodeActionAutoApply.IfSingle && fixes.actions.length === 1)) { - this._onApplyCodeAction(fixes.actions[0]); - return; - } - } - this._codeActionContextMenu.show(newState.actions, newState.position); - - }).catch(onUnexpectedError); - } else if (newState.trigger.type === 'manual') { - this._codeActionContextMenu.show(newState.actions, newState.position); - } else { - // auto magically triggered - // * update an existing list of code actions - // * manage light bulb - if (this._codeActionContextMenu.isVisible) { - this._codeActionContextMenu.show(newState.actions, newState.position); - } else { - this._lightBulbWidget.tryShow(newState); - } - } - } else { - this._lightBulbWidget.hide(); - } + public showCodeActions(actions: CodeActionSet, at: IAnchor | IPosition) { + return this._ui.showCodeActionList(actions, at); } public getId(): string { return QuickFixController.ID; } - private _handleLightBulbSelect(e: { x: number, y: number, state: CodeActionsState.Triggered }): void { - this._codeActionContextMenu.show(e.state.actions, e); - } + public manualTriggerAtCurrentPosition( + notAvailableMessage: string, + filter?: CodeActionFilter, + autoApply?: CodeActionAutoApply + ): void { + if (!this._editor.hasModel()) { + return; + } - public triggerFromEditorSelection(filter?: CodeActionFilter, autoApply?: CodeActionAutoApply): Promise { - return this._model.trigger({ type: 'manual', filter, autoApply }); + MessageController.get(this._editor).closeMessage(); + const triggerPosition = this._editor.getPosition(); + this._trigger({ type: 'manual', filter, autoApply, context: { notAvailableMessage, position: triggerPosition } }); } - private _updateLightBulbTitle(): void { - const kb = this._keybindingService.lookupKeybinding(QuickFixAction.Id); - let title: string; - if (kb) { - title = nls.localize('quickFixWithKb', "Show Fixes ({0})", kb.getLabel()); - } else { - title = nls.localize('quickFix', "Show Fixes"); - } - this._lightBulbWidget.title = title; + private _trigger(trigger: CodeActionTrigger) { + return this._model.trigger(trigger); } - private _onApplyCodeAction(action: CodeAction): Promise { + private _applyCodeAction(action: CodeAction): Promise { return applyCodeAction(action, this._bulkEditService, this._commandService, this._editor); } } @@ -161,27 +125,18 @@ export async function applyCodeAction( } } -function showCodeActionsForEditorSelection( +function triggerCodeActionsForEditorSelection( editor: ICodeEditor, notAvailableMessage: string, - filter?: CodeActionFilter, - autoApply?: CodeActionAutoApply -) { - if (!editor.hasModel()) { - return; - } - - const controller = QuickFixController.get(editor); - if (!controller) { - return; - } - - const pos = editor.getPosition(); - controller.triggerFromEditorSelection(filter, autoApply).then(codeActions => { - if (!codeActions || !codeActions.actions.length) { - MessageController.get(editor).showMessage(notAvailableMessage, pos); + filter: CodeActionFilter | undefined, + autoApply: CodeActionAutoApply | undefined +): void { + if (editor.hasModel()) { + const controller = QuickFixController.get(editor); + if (controller) { + controller.manualTriggerAtCurrentPosition(notAvailableMessage, filter, autoApply); } - }); + } } export class QuickFixAction extends EditorAction { @@ -192,7 +147,7 @@ export class QuickFixAction extends EditorAction { super({ id: QuickFixAction.Id, label: nls.localize('quickfix.trigger.label', "Quick Fix..."), - alias: 'Quick Fix', + alias: 'Quick Fix...', precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasCodeActionsProvider), kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, @@ -203,7 +158,7 @@ export class QuickFixAction extends EditorAction { } public run(_accessor: ServicesAccessor, editor: ICodeEditor): void { - return showCodeActionsForEditorSelection(editor, nls.localize('editor.action.quickFix.noneMessage', "No code actions available")); + return triggerCodeActionsForEditorSelection(editor, nls.localize('editor.action.quickFix.noneMessage', "No code actions available"), undefined, undefined); } } @@ -283,7 +238,7 @@ export class CodeActionCommand extends EditorCommand { kind: CodeActionKind.Empty, apply: CodeActionAutoApply.IfSingle, }); - return showCodeActionsForEditorSelection(editor, nls.localize('editor.action.quickFix.noneMessage', "No code actions available"), + return triggerCodeActionsForEditorSelection(editor, nls.localize('editor.action.quickFix.noneMessage', "No code actions available"), { kind: args.kind, includeSourceActions: true, @@ -302,7 +257,7 @@ export class RefactorAction extends EditorAction { super({ id: RefactorAction.Id, label: nls.localize('refactor.label', "Refactor..."), - alias: 'Refactor', + alias: 'Refactor...', precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasCodeActionsProvider), kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, @@ -346,7 +301,7 @@ export class RefactorAction extends EditorAction { kind: CodeActionKind.Refactor, apply: CodeActionAutoApply.Never }); - return showCodeActionsForEditorSelection(editor, + return triggerCodeActionsForEditorSelection(editor, nls.localize('editor.action.refactor.noneMessage', "No refactorings available"), { kind: CodeActionKind.Refactor.contains(args.kind) ? args.kind : CodeActionKind.Empty, @@ -365,7 +320,7 @@ export class SourceAction extends EditorAction { super({ id: SourceAction.Id, label: nls.localize('source.label', "Source Action..."), - alias: 'Source Action', + alias: 'Source Action...', precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasCodeActionsProvider), menuOpts: { group: '1_modification', @@ -401,7 +356,7 @@ export class SourceAction extends EditorAction { kind: CodeActionKind.Source, apply: CodeActionAutoApply.Never }); - return showCodeActionsForEditorSelection(editor, + return triggerCodeActionsForEditorSelection(editor, nls.localize('editor.action.source.noneMessage', "No source actions available"), { kind: CodeActionKind.Source.contains(args.kind) ? args.kind : CodeActionKind.Empty, @@ -433,7 +388,7 @@ export class OrganizeImportsAction extends EditorAction { } public run(_accessor: ServicesAccessor, editor: ICodeEditor): void { - return showCodeActionsForEditorSelection(editor, + return triggerCodeActionsForEditorSelection(editor, nls.localize('editor.action.organize.noneMessage', "No organize imports action available"), { kind: CodeActionKind.SourceOrganizeImports, includeSourceActions: true }, CodeActionAutoApply.IfSingle); @@ -456,7 +411,7 @@ export class FixAllAction extends EditorAction { } public run(_accessor: ServicesAccessor, editor: ICodeEditor): void { - return showCodeActionsForEditorSelection(editor, + return triggerCodeActionsForEditorSelection(editor, nls.localize('fixAll.noneMessage', "No fix all action available"), { kind: CodeActionKind.SourceFixAll, includeSourceActions: true }, CodeActionAutoApply.IfSingle); @@ -471,7 +426,7 @@ export class AutoFixAction extends EditorAction { super({ id: AutoFixAction.Id, label: nls.localize('autoFix.label', "Auto Fix..."), - alias: 'Auto Fix', + alias: 'Auto Fix...', precondition: ContextKeyExpr.and( EditorContextKeys.writable, contextKeyForSupportedActions(CodeActionKind.QuickFix)), @@ -487,7 +442,7 @@ export class AutoFixAction extends EditorAction { } public run(_accessor: ServicesAccessor, editor: ICodeEditor): void { - return showCodeActionsForEditorSelection(editor, + return triggerCodeActionsForEditorSelection(editor, nls.localize('editor.action.autoFix.noneMessage', "No auto fixes available"), { kind: CodeActionKind.QuickFix, diff --git a/src/vs/editor/contrib/codeAction/codeActionModel.ts b/src/vs/editor/contrib/codeAction/codeActionModel.ts index 100f89cbf..d1b33028a 100644 --- a/src/vs/editor/contrib/codeAction/codeActionModel.ts +++ b/src/vs/editor/contrib/codeAction/codeActionModel.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { CancelablePromise, createCancelablePromise, TimeoutTimer } from 'vs/base/common/async'; -import { Emitter, Event } from 'vs/base/common/event'; -import { dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { Emitter } from 'vs/base/common/event'; +import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { Position } from 'vs/editor/common/core/position'; @@ -14,36 +14,34 @@ import { Selection } from 'vs/editor/common/core/selection'; import { CodeActionProviderRegistry } from 'vs/editor/common/modes'; import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IMarkerService } from 'vs/platform/markers/common/markers'; -import { IProgressService } from 'vs/platform/progress/common/progress'; +import { IEditorProgressService } from 'vs/platform/progress/common/progress'; import { getCodeActions, CodeActionSet } from './codeAction'; import { CodeActionTrigger } from './codeActionTrigger'; export const SUPPORTED_CODE_ACTIONS = new RawContextKey('supportedCodeAction', ''); -export class CodeActionOracle { +export type TriggeredCodeAction = undefined | { + readonly selection: Selection; + readonly trigger: CodeActionTrigger; + readonly position: Position; +}; - private _disposables: IDisposable[] = []; - private readonly _autoTriggerTimer = new TimeoutTimer(); +class CodeActionOracle extends Disposable { + + private readonly _autoTriggerTimer = this._register(new TimeoutTimer()); constructor( private readonly _editor: ICodeEditor, private readonly _markerService: IMarkerService, - private readonly _signalChange: (newState: CodeActionsState.State) => void, + private readonly _signalChange: (triggered: TriggeredCodeAction) => void, private readonly _delay: number = 250, - private readonly _progressService?: IProgressService, ) { - this._disposables.push( - this._markerService.onMarkerChanged(e => this._onMarkerChanges(e)), - this._editor.onDidChangeCursorPosition(() => this._onCursorChange()), - ); - } - - dispose(): void { - this._disposables = dispose(this._disposables); - this._autoTriggerTimer.cancel(); + super(); + this._register(this._markerService.onMarkerChanged(e => this._onMarkerChanges(e))); + this._register(this._editor.onDidChangeCursorPosition(() => this._onCursorChange())); } - trigger(trigger: CodeActionTrigger) { + public trigger(trigger: CodeActionTrigger): TriggeredCodeAction { const selection = this._getRangeOfSelectionUnlessWhitespaceEnclosed(trigger); return this._createEventAndSignalChange(trigger, selection); } @@ -109,38 +107,27 @@ export class CodeActionOracle { } } } - return selection ? selection : undefined; + return selection; } - private _createEventAndSignalChange(trigger: CodeActionTrigger, selection: Selection | undefined): Promise { - if (!selection) { + private _createEventAndSignalChange(trigger: CodeActionTrigger, selection: Selection | undefined): TriggeredCodeAction { + const model = this._editor.getModel(); + if (!selection || !model) { // cancel - this._signalChange(CodeActionsState.Empty); - return Promise.resolve(undefined); - } else { - const model = this._editor.getModel(); - if (!model) { - // cancel - this._signalChange(CodeActionsState.Empty); - return Promise.resolve(undefined); - } - - const markerRange = this._getRangeOfMarker(selection); - const position = markerRange ? markerRange.getStartPosition() : selection.getStartPosition(); - const actions = createCancelablePromise(token => getCodeActions(model, selection, trigger, token)); + this._signalChange(undefined); + return undefined; + } - if (this._progressService && trigger.type === 'manual') { - this._progressService.showWhile(actions, 250); - } + const markerRange = this._getRangeOfMarker(selection); + const position = markerRange ? markerRange.getStartPosition() : selection.getStartPosition(); - this._signalChange(new CodeActionsState.Triggered( - trigger, - selection, - position, - actions - )); - return actions; - } + const e: TriggeredCodeAction = { + trigger, + selection, + position + }; + this._signalChange(e); + return e; } } @@ -167,47 +154,39 @@ export namespace CodeActionsState { export type State = typeof Empty | Triggered; } -export class CodeActionModel { +export class CodeActionModel extends Disposable { - private _codeActionOracle?: CodeActionOracle; + private readonly _codeActionOracle = this._register(new MutableDisposable()); private _state: CodeActionsState.State = CodeActionsState.Empty; - private _onDidChangeState = new Emitter(); - private _disposables: IDisposable[] = []; private readonly _supportedCodeActions: IContextKey; + private readonly _onDidChangeState = this._register(new Emitter()); + public readonly onDidChangeState = this._onDidChangeState.event; + constructor( private readonly _editor: ICodeEditor, private readonly _markerService: IMarkerService, contextKeyService: IContextKeyService, - private readonly _progressService: IProgressService + private readonly _progressService?: IEditorProgressService ) { + super(); this._supportedCodeActions = SUPPORTED_CODE_ACTIONS.bindTo(contextKeyService); - this._disposables.push(this._editor.onDidChangeModel(() => this._update())); - this._disposables.push(this._editor.onDidChangeModelLanguage(() => this._update())); - this._disposables.push(CodeActionProviderRegistry.onDidChange(() => this._update())); + this._register(this._editor.onDidChangeModel(() => this._update())); + this._register(this._editor.onDidChangeModelLanguage(() => this._update())); + this._register(CodeActionProviderRegistry.onDidChange(() => this._update())); this._update(); } dispose(): void { - this._disposables = dispose(this._disposables); - dispose(this._codeActionOracle); - } - - get onDidChangeState(): Event { - return this._onDidChangeState.event; + super.dispose(); + this.setState(CodeActionsState.Empty, true); } private _update(): void { - if (this._codeActionOracle) { - this._codeActionOracle.dispose(); - this._codeActionOracle = undefined; - } + this._codeActionOracle.value = undefined; - if (this._state.type === CodeActionsState.Type.Triggered) { - this._state.actions.cancel(); - } this.setState(CodeActionsState.Empty); const model = this._editor.getModel(); @@ -224,25 +203,46 @@ export class CodeActionModel { this._supportedCodeActions.set(supportedActions.join(' ')); - this._codeActionOracle = new CodeActionOracle(this._editor, this._markerService, newState => this.setState(newState), undefined, this._progressService); - this._codeActionOracle.trigger({ type: 'auto' }); + this._codeActionOracle.value = new CodeActionOracle(this._editor, this._markerService, trigger => { + if (!trigger) { + this.setState(CodeActionsState.Empty); + return; + } + + const actions = createCancelablePromise(token => getCodeActions(model, trigger.selection, trigger.trigger, token)); + if (this._progressService && trigger.trigger.type === 'manual') { + this._progressService.showWhile(actions, 250); + } + + this.setState(new CodeActionsState.Triggered(trigger.trigger, trigger.selection, trigger.position, actions)); + + }, undefined); + this._codeActionOracle.value.trigger({ type: 'auto' }); } else { this._supportedCodeActions.reset(); } } - public trigger(trigger: CodeActionTrigger): Promise { - if (this._codeActionOracle) { - return this._codeActionOracle.trigger(trigger); + public trigger(trigger: CodeActionTrigger) { + if (this._codeActionOracle.value) { + this._codeActionOracle.value.trigger(trigger); } - return Promise.resolve(undefined); } - private setState(newState: CodeActionsState.State) { + private setState(newState: CodeActionsState.State, skipNotify?: boolean) { if (newState === this._state) { return; } + + // Cancel old request + if (this._state.type === CodeActionsState.Type.Triggered) { + this._state.actions.cancel(); + } + this._state = newState; - this._onDidChangeState.fire(newState); + + if (!skipNotify) { + this._onDidChangeState.fire(newState); + } } } diff --git a/src/vs/editor/contrib/codeAction/codeActionTrigger.ts b/src/vs/editor/contrib/codeAction/codeActionTrigger.ts index 15e90604e..8d55c8971 100644 --- a/src/vs/editor/contrib/codeAction/codeActionTrigger.ts +++ b/src/vs/editor/contrib/codeAction/codeActionTrigger.ts @@ -5,6 +5,7 @@ import { startsWith } from 'vs/base/common/strings'; import { CodeAction } from 'vs/editor/common/modes'; +import { Position } from 'vs/editor/common/core/position'; export class CodeActionKind { private static readonly sep = '.'; @@ -20,8 +21,12 @@ export class CodeActionKind { public readonly value: string ) { } + public equals(other: CodeActionKind): boolean { + return this.value === other.value; + } + public contains(other: CodeActionKind): boolean { - return this.value === other.value || startsWith(other.value, this.value + CodeActionKind.sep); + return this.equals(other) || startsWith(other.value, this.value + CodeActionKind.sep); } public intersects(other: CodeActionKind): boolean { @@ -86,4 +91,8 @@ export interface CodeActionTrigger { readonly type: 'auto' | 'manual'; readonly filter?: CodeActionFilter; readonly autoApply?: CodeActionAutoApply; + readonly context?: { + readonly notAvailableMessage: string; + readonly position: Position; + }; } \ No newline at end of file diff --git a/src/vs/editor/contrib/codeAction/codeActionUi.ts b/src/vs/editor/contrib/codeAction/codeActionUi.ts new file mode 100644 index 000000000..a496f3e70 --- /dev/null +++ b/src/vs/editor/contrib/codeAction/codeActionUi.ts @@ -0,0 +1,105 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { onUnexpectedError } from 'vs/base/common/errors'; +import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; +import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { CodeAction } from 'vs/editor/common/modes'; +import { CodeActionSet } from 'vs/editor/contrib/codeAction/codeAction'; +import { MessageController } from 'vs/editor/contrib/message/messageController'; +import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { CodeActionsState } from './codeActionModel'; +import { CodeActionAutoApply } from './codeActionTrigger'; +import { CodeActionWidget } from './codeActionWidget'; +import { LightBulbWidget } from './lightBulbWidget'; +import { IPosition } from 'vs/editor/common/core/position'; +import { IAnchor } from 'vs/base/browser/ui/contextview/contextview'; + +export class CodeActionUi extends Disposable { + + private readonly _codeActionWidget: CodeActionWidget; + private readonly _lightBulbWidget: LightBulbWidget; + private readonly _activeCodeActions = this._register(new MutableDisposable()); + + constructor( + private readonly _editor: ICodeEditor, + quickFixActionId: string, + private readonly delegate: { + applyCodeAction: (action: CodeAction, regtriggerAfterApply: boolean) => void + }, + @IContextMenuService contextMenuService: IContextMenuService, + @IKeybindingService keybindingService: IKeybindingService, + ) { + super(); + + this._codeActionWidget = this._register(new CodeActionWidget(this._editor, contextMenuService, { + onSelectCodeAction: async (action) => { + this.delegate.applyCodeAction(action, /* retrigger */ true); + } + })); + this._lightBulbWidget = this._register(new LightBulbWidget(this._editor, quickFixActionId, keybindingService)); + + this._register(this._lightBulbWidget.onClick(this._handleLightBulbSelect, this)); + } + + public async update(newState: CodeActionsState.State): Promise { + if (newState.type !== CodeActionsState.Type.Triggered) { + this._lightBulbWidget.hide(); + return; + } + + let actions: CodeActionSet; + try { + actions = await newState.actions; + } catch (e) { + onUnexpectedError(e); + return; + } + + this._lightBulbWidget.update(actions, newState.position); + + if (!actions.actions.length && newState.trigger.context) { + MessageController.get(this._editor).showMessage(newState.trigger.context.notAvailableMessage, newState.trigger.context.position); + this._activeCodeActions.value = actions; + return; + } + + if (newState.trigger.type === 'manual') { + if (newState.trigger.filter && newState.trigger.filter.kind) { + // Triggered for specific scope + if (actions.actions.length > 0) { + // Apply if we only have one action or requested autoApply + if (newState.trigger.autoApply === CodeActionAutoApply.First || (newState.trigger.autoApply === CodeActionAutoApply.IfSingle && actions.actions.length === 1)) { + try { + await this.delegate.applyCodeAction(actions.actions[0], false); + } finally { + actions.dispose(); + } + return; + } + } + } + this._activeCodeActions.value = actions; + this._codeActionWidget.show(actions, newState.position); + } else { + // auto magically triggered + if (this._codeActionWidget.isVisible) { + // TODO: Figure out if we should update the showing menu? + actions.dispose(); + } else { + this._activeCodeActions.value = actions; + } + } + } + + public async showCodeActionList(actions: CodeActionSet, at?: IAnchor | IPosition): Promise { + this._codeActionWidget.show(actions, at); + } + + private _handleLightBulbSelect(e: { x: number, y: number, actions: CodeActionSet }): void { + this._codeActionWidget.show(e.actions, e); + } +} diff --git a/src/vs/editor/contrib/codeAction/codeActionWidget.ts b/src/vs/editor/contrib/codeAction/codeActionWidget.ts index b3ddad603..ebbeeccb1 100644 --- a/src/vs/editor/contrib/codeAction/codeActionWidget.ts +++ b/src/vs/editor/contrib/codeAction/codeActionWidget.ts @@ -6,35 +6,47 @@ import { getDomNodePagePosition } from 'vs/base/browser/dom'; import { Action } from 'vs/base/common/actions'; import { canceled } from 'vs/base/common/errors'; -import { Emitter, Event } from 'vs/base/common/event'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; -import { Position } from 'vs/editor/common/core/position'; +import { Position, IPosition } from 'vs/editor/common/core/position'; import { ScrollType } from 'vs/editor/common/editorCommon'; import { CodeAction } from 'vs/editor/common/modes'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { CodeActionSet } from 'vs/editor/contrib/codeAction/codeAction'; +import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; +import { IAnchor } from 'vs/base/browser/ui/contextview/contextview'; -export class CodeActionContextMenu { +interface CodeActionWidgetDelegate { + onSelectCodeAction: (action: CodeAction) => Promise; +} - private _visible: boolean; +export class CodeActionWidget extends Disposable { - private readonly _onDidExecuteCodeAction = new Emitter(); - public readonly onDidExecuteCodeAction: Event = this._onDidExecuteCodeAction.event; + private _visible: boolean; + private readonly _showingActions = this._register(new MutableDisposable()); constructor( private readonly _editor: ICodeEditor, private readonly _contextMenuService: IContextMenuService, - private readonly _onApplyCodeAction: (action: CodeAction) => Promise - ) { } + private readonly _delegate: CodeActionWidgetDelegate, + ) { + super(); + } - async show(actionsToShow: Promise, at?: { x: number; y: number } | Position): Promise { - const codeActions = await actionsToShow; + public async show(codeActions: CodeActionSet, at?: IAnchor | IPosition): Promise { + if (!codeActions.actions.length) { + this._visible = false; + return; + } if (!this._editor.getDomNode()) { // cancel when editor went off-dom + this._visible = false; return Promise.reject(canceled()); } + this._visible = true; const actions = codeActions.actions.map(action => this.codeActionToAction(action)); + + this._showingActions.value = codeActions; this._contextMenuService.showContextMenu({ getAnchor: () => { if (Position.isIPosition(at)) { @@ -54,16 +66,14 @@ export class CodeActionContextMenu { private codeActionToAction(action: CodeAction): Action { const id = action.command ? action.command.id : action.title; const title = action.title; - return new Action(id, title, undefined, true, () => - this._onApplyCodeAction(action) - .finally(() => this._onDidExecuteCodeAction.fire(undefined))); + return new Action(id, title, undefined, true, () => this._delegate.onSelectCodeAction(action)); } get isVisible(): boolean { return this._visible; } - private _toCoords(position: Position): { x: number, y: number } { + private _toCoords(position: IPosition): { x: number, y: number } { if (!this._editor.hasModel()) { return { x: 0, y: 0 }; } diff --git a/src/vs/editor/contrib/codeAction/lightBulbWidget.css b/src/vs/editor/contrib/codeAction/lightBulbWidget.css index e496371d9..df27dfd21 100644 --- a/src/vs/editor/contrib/codeAction/lightBulbWidget.css +++ b/src/vs/editor/contrib/codeAction/lightBulbWidget.css @@ -18,11 +18,11 @@ } .monaco-editor.vs .lightbulb-glyph { - background: url('lightbulb.svg') center center no-repeat; + background: url('lightbulb-light.svg') center center no-repeat; } .monaco-editor.vs .lightbulb-glyph.autofixable { - background: url('lightbulb-autofix.svg') center center no-repeat; + background: url('lightbulb-autofix-light.svg') center center no-repeat; } .monaco-editor.vs-dark .lightbulb-glyph, diff --git a/src/vs/editor/contrib/codeAction/lightBulbWidget.ts b/src/vs/editor/contrib/codeAction/lightBulbWidget.ts index 6486a8ec0..8575f354d 100644 --- a/src/vs/editor/contrib/codeAction/lightBulbWidget.ts +++ b/src/vs/editor/contrib/codeAction/lightBulbWidget.ts @@ -5,67 +5,90 @@ import * as dom from 'vs/base/browser/dom'; import { GlobalMouseMoveMonitor, IStandardMouseMoveEventData, standardMouseMoveMerger } from 'vs/base/browser/globalMouseMoveMonitor'; -import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import 'vs/css!./lightBulbWidget'; import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; +import { IPosition } from 'vs/editor/common/core/position'; import { TextModel } from 'vs/editor/common/model/textModel'; import { CodeActionSet } from 'vs/editor/contrib/codeAction/codeAction'; -import { CodeActionsState } from './codeActionModel'; +import * as nls from 'vs/nls'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; + +namespace LightBulbState { + + export const enum Type { + Hidden, + Showing, + } + + export const Hidden = new class { readonly type = Type.Hidden; }; + + export class Showing { + readonly type = Type.Showing; + + constructor( + public readonly actions: CodeActionSet, + public readonly editorPosition: IPosition, + public readonly widgetPosition: IContentWidgetPosition, + ) { } + } + + export type State = typeof Hidden | Showing; +} + export class LightBulbWidget extends Disposable implements IContentWidget { private static readonly _posPref = [ContentWidgetPositionPreference.EXACT]; private readonly _domNode: HTMLDivElement; - private readonly _editor: ICodeEditor; - private readonly _onClick = this._register(new Emitter<{ x: number; y: number; state: CodeActionsState.Triggered }>()); + private readonly _onClick = this._register(new Emitter<{ x: number; y: number; actions: CodeActionSet }>()); public readonly onClick = this._onClick.event; - private _position: IContentWidgetPosition | null; - private _state: CodeActionsState.State = CodeActionsState.Empty; - private _futureFixes = new CancellationTokenSource(); + private _state: LightBulbState.State = LightBulbState.Hidden; - constructor(editor: ICodeEditor) { + constructor( + private readonly _editor: ICodeEditor, + private readonly _quickFixActionId: string, + @IKeybindingService private readonly _keybindingService: IKeybindingService + ) { super(); this._domNode = document.createElement('div'); this._domNode.className = 'lightbulb-glyph'; - this._editor = editor; this._editor.addContentWidget(this); - this._register(this._editor.onDidChangeModel(_ => this._futureFixes.cancel())); - this._register(this._editor.onDidChangeModelLanguage(_ => this._futureFixes.cancel())); this._register(this._editor.onDidChangeModelContent(_ => { // cancel when the line in question has been removed const editorModel = this._editor.getModel(); - if (this._state.type !== CodeActionsState.Type.Triggered || !editorModel || this._state.position.lineNumber >= editorModel.getLineCount()) { - this._futureFixes.cancel(); + if (this._state.type !== LightBulbState.Type.Showing || !editorModel || this._state.editorPosition.lineNumber >= editorModel.getLineCount()) { + this.hide(); } })); - this._register(dom.addStandardDisposableListener(this._domNode, 'click', e => { - if (this._state.type !== CodeActionsState.Type.Triggered) { + this._register(dom.addStandardDisposableListener(this._domNode, 'mousedown', e => { + if (this._state.type !== LightBulbState.Type.Showing) { return; } // Make sure that focus / cursor location is not lost when clicking widget icon this._editor.focus(); + e.preventDefault(); // a bit of extra work to make sure the menu // doesn't cover the line-text const { top, height } = dom.getDomNodePagePosition(this._domNode); const { lineHeight } = this._editor.getConfiguration(); let pad = Math.floor(lineHeight / 3); - if (this._position && this._position.position !== null && this._position.position.lineNumber < this._state.position.lineNumber) { + if (this._state.widgetPosition.position !== null && this._state.widgetPosition.position.lineNumber < this._state.editorPosition.lineNumber) { pad += lineHeight; } this._onClick.fire({ x: e.posx, y: top + height + pad, - state: this._state + actions: this._state.actions }); })); this._register(dom.addDisposableListener(this._domNode, 'mouseenter', (e: MouseEvent) => { @@ -87,6 +110,9 @@ export class LightBulbWidget extends Disposable implements IContentWidget { this.hide(); } })); + + this._updateLightBulbTitle(); + this._register(this._keybindingService.onDidUpdateKeybindings(this._updateLightBulbTitle, this)); } dispose(): void { @@ -103,60 +129,23 @@ export class LightBulbWidget extends Disposable implements IContentWidget { } getPosition(): IContentWidgetPosition | null { - return this._position; + return this._state.type === LightBulbState.Type.Showing ? this._state.widgetPosition : null; } - tryShow(newState: CodeActionsState.State) { - - if (newState.type !== CodeActionsState.Type.Triggered || this._position && (!newState.position || this._position.position && this._position.position.lineNumber !== newState.position.lineNumber)) { - // hide when getting a 'hide'-request or when currently - // showing on another line - this.hide(); - } else if (this._futureFixes) { - // cancel pending show request in any case - this._futureFixes.cancel(); - } - - this._futureFixes = new CancellationTokenSource(); - const { token } = this._futureFixes; - this._state = newState; - - if (this._state.type === CodeActionsState.Empty.type) { - return; + public update(actions: CodeActionSet, atPosition: IPosition) { + if (actions.actions.length <= 0) { + return this.hide(); } - const selection = this._state.rangeOrSelection; - this._state.actions.then(fixes => { - if (!token.isCancellationRequested && fixes.actions.length > 0 && selection) { - this._show(fixes); - } else { - this.hide(); - } - }).catch(() => { - this.hide(); - }); - } - - set title(value: string) { - this._domNode.title = value; - } - - get title(): string { - return this._domNode.title; - } - - private _show(codeActions: CodeActionSet): void { const config = this._editor.getConfiguration(); if (!config.contribInfo.lightbulbEnabled) { - return; + return this.hide(); } - if (this._state.type !== CodeActionsState.Type.Triggered) { - return; - } - const { lineNumber, column } = this._state.position; + + const { lineNumber, column } = atPosition; const model = this._editor.getModel(); if (!model) { - return; + return this.hide(); } const tabSize = model.getOptions().tabSize; @@ -176,23 +165,35 @@ export class LightBulbWidget extends Disposable implements IContentWidget { } else if (column * config.fontInfo.spaceWidth < 22) { // cannot show lightbulb above/below and showing // it inline would overlay the cursor... - this.hide(); - return; + return this.hide(); } } - this._position = { + this._state = new LightBulbState.Showing(actions, atPosition, { position: { lineNumber: effectiveLineNumber, column: 1 }, preference: LightBulbWidget._posPref - }; - dom.toggleClass(this._domNode, 'autofixable', codeActions.hasAutoFix); + }); + dom.toggleClass(this._domNode, 'autofixable', actions.hasAutoFix); this._editor.layoutContentWidget(this); } - hide(): void { - this._position = null; - this._state = CodeActionsState.Empty; - this._futureFixes.cancel(); + private set title(value: string) { + this._domNode.title = value; + } + + public hide(): void { + this._state = LightBulbState.Hidden; this._editor.layoutContentWidget(this); } + + private _updateLightBulbTitle(): void { + const kb = this._keybindingService.lookupKeybinding(this._quickFixActionId); + let title: string; + if (kb) { + title = nls.localize('quickFixWithKb', "Show Fixes ({0})", kb.getLabel()); + } else { + title = nls.localize('quickFix', "Show Fixes"); + } + this.title = title; + } } diff --git a/src/vs/editor/contrib/codeAction/lightbulb-autofix-dark.svg b/src/vs/editor/contrib/codeAction/lightbulb-autofix-dark.svg index 40678e79d..34d4f3aed 100644 --- a/src/vs/editor/contrib/codeAction/lightbulb-autofix-dark.svg +++ b/src/vs/editor/contrib/codeAction/lightbulb-autofix-dark.svg @@ -1,10 +1,4 @@ - - - - - - - - + + diff --git a/src/vs/editor/contrib/codeAction/lightbulb-autofix-light.svg b/src/vs/editor/contrib/codeAction/lightbulb-autofix-light.svg new file mode 100644 index 000000000..c34a0c280 --- /dev/null +++ b/src/vs/editor/contrib/codeAction/lightbulb-autofix-light.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/vs/editor/contrib/codeAction/lightbulb-autofix.svg b/src/vs/editor/contrib/codeAction/lightbulb-autofix.svg deleted file mode 100644 index a4b4858e4..000000000 --- a/src/vs/editor/contrib/codeAction/lightbulb-autofix.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/src/vs/editor/contrib/codeAction/lightbulb-dark.svg b/src/vs/editor/contrib/codeAction/lightbulb-dark.svg index 520f78f3e..d2b6e1287 100644 --- a/src/vs/editor/contrib/codeAction/lightbulb-dark.svg +++ b/src/vs/editor/contrib/codeAction/lightbulb-dark.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + diff --git a/src/vs/editor/contrib/codeAction/lightbulb-light.svg b/src/vs/editor/contrib/codeAction/lightbulb-light.svg new file mode 100644 index 000000000..8572effd0 --- /dev/null +++ b/src/vs/editor/contrib/codeAction/lightbulb-light.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/vs/editor/contrib/codeAction/lightbulb.svg b/src/vs/editor/contrib/codeAction/lightbulb.svg deleted file mode 100644 index b35960466..000000000 --- a/src/vs/editor/contrib/codeAction/lightbulb.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/codeAction/test/codeAction.test.ts b/src/vs/editor/contrib/codeAction/test/codeAction.test.ts index 3774bacfb..07c61c660 100644 --- a/src/vs/editor/contrib/codeAction/test/codeAction.test.ts +++ b/src/vs/editor/contrib/codeAction/test/codeAction.test.ts @@ -3,22 +3,34 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { DisposableStore } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { Range } from 'vs/editor/common/core/range'; import { TextModel } from 'vs/editor/common/model/textModel'; -import { CodeAction, CodeActionContext, CodeActionProvider, CodeActionProviderRegistry, Command, LanguageIdentifier, ResourceTextEdit, WorkspaceEdit } from 'vs/editor/common/modes'; +import * as modes from 'vs/editor/common/modes'; import { getCodeActions } from 'vs/editor/contrib/codeAction/codeAction'; import { CodeActionKind } from 'vs/editor/contrib/codeAction/codeActionTrigger'; import { IMarkerData, MarkerSeverity } from 'vs/platform/markers/common/markers'; import { CancellationToken } from 'vs/base/common/cancellation'; +function staticCodeActionProvider(...actions: modes.CodeAction[]): modes.CodeActionProvider { + return new class implements modes.CodeActionProvider { + provideCodeActions(): modes.CodeActionList { + return { + actions: actions, + dispose: () => { } + }; + } + }; +} + + suite('CodeAction', () => { - let langId = new LanguageIdentifier('fooLang', 17); + let langId = new modes.LanguageIdentifier('fooLang', 17); let uri = URI.parse('untitled:path'); let model: TextModel; - let disposables: IDisposable[] = []; + const disposables = new DisposableStore(); let testData = { diagnostics: { abc: { @@ -46,7 +58,7 @@ suite('CodeAction', () => { }, command: { abc: { - command: new class implements Command { + command: new class implements modes.Command { id: '1'; title: 'abc'; }, @@ -56,8 +68,8 @@ suite('CodeAction', () => { spelling: { bcd: { diagnostics: [], - edit: new class implements WorkspaceEdit { - edits: ResourceTextEdit[]; + edit: new class implements modes.WorkspaceEdit { + edits: modes.ResourceTextEdit[]; }, title: 'abc' } @@ -79,30 +91,27 @@ suite('CodeAction', () => { }; setup(function () { + disposables.clear(); model = TextModel.createFromString('test1\ntest2\ntest3', undefined, langId, uri); - disposables = [model]; + disposables.add(model); }); teardown(function () { - dispose(disposables); + disposables.clear(); }); test('CodeActions are sorted by type, #38623', async function () { - const provider = new class implements CodeActionProvider { - provideCodeActions() { - return [ - testData.command.abc, - testData.diagnostics.bcd, - testData.spelling.bcd, - testData.tsLint.bcd, - testData.tsLint.abc, - testData.diagnostics.abc - ]; - } - }; + const provider = staticCodeActionProvider( + testData.command.abc, + testData.diagnostics.bcd, + testData.spelling.bcd, + testData.tsLint.bcd, + testData.tsLint.abc, + testData.diagnostics.abc + ); - disposables.push(CodeActionProviderRegistry.register('fooLang', provider)); + disposables.add(modes.CodeActionProviderRegistry.register('fooLang', provider)); const expected = [ // CodeActions with a diagnostics array are shown first ordered by diagnostics.message @@ -122,17 +131,13 @@ suite('CodeAction', () => { }); test('getCodeActions should filter by scope', async function () { - const provider = new class implements CodeActionProvider { - provideCodeActions(): CodeAction[] { - return [ - { title: 'a', kind: 'a' }, - { title: 'b', kind: 'b' }, - { title: 'a.b', kind: 'a.b' } - ]; - } - }; + const provider = staticCodeActionProvider( + { title: 'a', kind: 'a' }, + { title: 'b', kind: 'b' }, + { title: 'a.b', kind: 'a.b' } + ); - disposables.push(CodeActionProviderRegistry.register('fooLang', provider)); + disposables.add(modes.CodeActionProviderRegistry.register('fooLang', provider)); { const { actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: 'auto', filter: { kind: new CodeActionKind('a') } }, CancellationToken.None); @@ -154,15 +159,18 @@ suite('CodeAction', () => { }); test('getCodeActions should forward requested scope to providers', async function () { - const provider = new class implements CodeActionProvider { - provideCodeActions(_model: any, _range: Range, context: CodeActionContext, _token: any): CodeAction[] { - return [ - { title: context.only || '', kind: context.only } - ]; + const provider = new class implements modes.CodeActionProvider { + provideCodeActions(_model: any, _range: Range, context: modes.CodeActionContext, _token: any): modes.CodeActionList { + return { + actions: [ + { title: context.only || '', kind: context.only } + ], + dispose: () => { } + }; } }; - disposables.push(CodeActionProviderRegistry.register('fooLang', provider)); + disposables.add(modes.CodeActionProviderRegistry.register('fooLang', provider)); const { actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: 'auto', filter: { kind: new CodeActionKind('a') } }, CancellationToken.None); assert.equal(actions.length, 1); @@ -170,16 +178,12 @@ suite('CodeAction', () => { }); test('getCodeActions should not return source code action by default', async function () { - const provider = new class implements CodeActionProvider { - provideCodeActions(): CodeAction[] { - return [ - { title: 'a', kind: CodeActionKind.Source.value }, - { title: 'b', kind: 'b' } - ]; - } - }; + const provider = staticCodeActionProvider( + { title: 'a', kind: CodeActionKind.Source.value }, + { title: 'b', kind: 'b' } + ); - disposables.push(CodeActionProviderRegistry.register('fooLang', provider)); + disposables.add(modes.CodeActionProviderRegistry.register('fooLang', provider)); { const { actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: 'auto' }, CancellationToken.None); @@ -196,16 +200,16 @@ suite('CodeAction', () => { test('getCodeActions should not invoke code action providers filtered out by providedCodeActionKinds', async function () { let wasInvoked = false; - const provider = new class implements CodeActionProvider { - provideCodeActions() { + const provider = new class implements modes.CodeActionProvider { + provideCodeActions(): modes.CodeActionList { wasInvoked = true; - return []; + return { actions: [], dispose: () => { } }; } providedCodeActionKinds = [CodeActionKind.Refactor.value]; }; - disposables.push(CodeActionProviderRegistry.register('fooLang', provider)); + disposables.add(modes.CodeActionProviderRegistry.register('fooLang', provider)); const { actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: 'auto', diff --git a/src/vs/editor/contrib/codeAction/test/codeActionModel.test.ts b/src/vs/editor/contrib/codeAction/test/codeActionModel.test.ts index c6bfb5145..c2ef44935 100644 --- a/src/vs/editor/contrib/codeAction/test/codeActionModel.test.ts +++ b/src/vs/editor/contrib/codeAction/test/codeActionModel.test.ts @@ -4,32 +4,38 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { DisposableStore } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { Selection } from 'vs/editor/common/core/selection'; import { TextModel } from 'vs/editor/common/model/textModel'; -import { CodeActionProviderRegistry, LanguageIdentifier } from 'vs/editor/common/modes'; -import { CodeActionOracle, CodeActionsState } from 'vs/editor/contrib/codeAction/codeActionModel'; +import * as modes from 'vs/editor/common/modes'; +import { CodeActionModel, CodeActionsState } from 'vs/editor/contrib/codeAction/codeActionModel'; import { createTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor'; +import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService'; import { MarkerService } from 'vs/platform/markers/common/markerService'; const testProvider = { - provideCodeActions() { - return [{ id: 'test-command', title: 'test', arguments: [] }]; + provideCodeActions(): modes.CodeActionList { + return { + actions: [ + { title: 'test', command: { id: 'test-command', title: 'test', arguments: [] } } + ], + dispose() { /* noop*/ } + }; } }; -suite('CodeAction', () => { +suite('CodeActionModel', () => { - const languageIdentifier = new LanguageIdentifier('foo-lang', 3); + const languageIdentifier = new modes.LanguageIdentifier('foo-lang', 3); let uri = URI.parse('untitled:path'); let model: TextModel; let markerService: MarkerService; let editor: ICodeEditor; - let disposables: IDisposable[]; + const disposables = new DisposableStore(); setup(() => { - disposables = []; + disposables.clear(); markerService = new MarkerService(); model = TextModel.createFromString('foobar foo bar\nfarboo far boo', undefined, languageIdentifier, uri); editor = createTestCodeEditor({ model: model }); @@ -37,26 +43,28 @@ suite('CodeAction', () => { }); teardown(() => { - dispose(disposables); + disposables.clear(); editor.dispose(); model.dispose(); markerService.dispose(); }); test('Orcale -> marker added', done => { - const reg = CodeActionProviderRegistry.register(languageIdentifier.language, testProvider); - disposables.push(reg); + const reg = modes.CodeActionProviderRegistry.register(languageIdentifier.language, testProvider); + disposables.add(reg); - const oracle = new CodeActionOracle(editor, markerService, (e: CodeActionsState.Triggered) => { + const contextKeys = new MockContextKeyService(); + const model = disposables.add(new CodeActionModel(editor, markerService, contextKeys, undefined)); + disposables.add(model.onDidChangeState((e: CodeActionsState.Triggered) => { assert.equal(e.trigger.type, 'auto'); assert.ok(e.actions); e.actions.then(fixes => { - oracle.dispose(); + model.dispose(); assert.equal(fixes.actions.length, 1); done(); }, done); - }); + })); // start here markerService.changeOne('fake', uri, [{ @@ -70,8 +78,8 @@ suite('CodeAction', () => { }); test('Orcale -> position changed', () => { - const reg = CodeActionProviderRegistry.register(languageIdentifier.language, testProvider); - disposables.push(reg); + const reg = modes.CodeActionProviderRegistry.register(languageIdentifier.language, testProvider); + disposables.add(reg); markerService.changeOne('fake', uri, [{ startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 6, @@ -84,28 +92,29 @@ suite('CodeAction', () => { editor.setPosition({ lineNumber: 2, column: 1 }); return new Promise((resolve, reject) => { - - const oracle = new CodeActionOracle(editor, markerService, (e: CodeActionsState.Triggered) => { + const contextKeys = new MockContextKeyService(); + const model = disposables.add(new CodeActionModel(editor, markerService, contextKeys, undefined)); + disposables.add(model.onDidChangeState((e: CodeActionsState.Triggered) => { assert.equal(e.trigger.type, 'auto'); assert.ok(e.actions); e.actions.then(fixes => { - oracle.dispose(); + model.dispose(); assert.equal(fixes.actions.length, 1); resolve(undefined); }, reject); - }); + })); // start here editor.setPosition({ lineNumber: 1, column: 1 }); }); }); test('Lightbulb is in the wrong place, #29933', async function () { - const reg = CodeActionProviderRegistry.register(languageIdentifier.language, { - provideCodeActions(_doc, _range) { - return []; + const reg = modes.CodeActionProviderRegistry.register(languageIdentifier.language, { + provideCodeActions(_doc, _range): modes.CodeActionList { + return { actions: [], dispose() { /* noop*/ } }; } }); - disposables.push(reg); + disposables.add(reg); editor.getModel()!.setValue('// @ts-check\n2\ncon\n'); @@ -119,8 +128,9 @@ suite('CodeAction', () => { // case 1 - drag selection over multiple lines -> range of enclosed marker, position or marker await new Promise(resolve => { - - let oracle = new CodeActionOracle(editor, markerService, (e: CodeActionsState.Triggered) => { + const contextKeys = new MockContextKeyService(); + const model = disposables.add(new CodeActionModel(editor, markerService, contextKeys, undefined)); + disposables.add(model.onDidChangeState((e: CodeActionsState.Triggered) => { assert.equal(e.trigger.type, 'auto'); const selection = e.rangeOrSelection; assert.deepEqual(selection.selectionStartLineNumber, 1); @@ -128,31 +138,32 @@ suite('CodeAction', () => { assert.deepEqual(selection.endLineNumber, 4); assert.deepEqual(selection.endColumn, 1); assert.deepEqual(e.position, { lineNumber: 3, column: 1 }); - - oracle.dispose(); + model.dispose(); resolve(undefined); - }, 5); + }, 5)); editor.setSelection({ startLineNumber: 1, startColumn: 1, endLineNumber: 4, endColumn: 1 }); }); }); test('Orcale -> should only auto trigger once for cursor and marker update right after each other', done => { - const reg = CodeActionProviderRegistry.register(languageIdentifier.language, testProvider); - disposables.push(reg); + const reg = modes.CodeActionProviderRegistry.register(languageIdentifier.language, testProvider); + disposables.add(reg); let triggerCount = 0; - const oracle = new CodeActionOracle(editor, markerService, (e: CodeActionsState.Triggered) => { + const contextKeys = new MockContextKeyService(); + const model = disposables.add(new CodeActionModel(editor, markerService, contextKeys, undefined)); + disposables.add(model.onDidChangeState((e: CodeActionsState.Triggered) => { assert.equal(e.trigger.type, 'auto'); ++triggerCount; // give time for second trigger before completing test setTimeout(() => { - oracle.dispose(); + model.dispose(); assert.strictEqual(triggerCount, 1); done(); }, 50); - }, 5 /*delay*/); + }, 5 /*delay*/)); markerService.changeOne('fake', uri, [{ startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 6, diff --git a/src/vs/editor/contrib/codelens/codeLensCache.ts b/src/vs/editor/contrib/codelens/codeLensCache.ts index 0119def52..9bddbb1d3 100644 --- a/src/vs/editor/contrib/codelens/codeLensCache.ts +++ b/src/vs/editor/contrib/codelens/codeLensCache.ts @@ -6,18 +6,20 @@ import { ITextModel } from 'vs/editor/common/model'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { ICodeLensData } from 'vs/editor/contrib/codelens/codelens'; +import { CodeLensModel } from 'vs/editor/contrib/codelens/codelens'; import { LRUCache, values } from 'vs/base/common/map'; -import { ICodeLensSymbol, CodeLensProvider } from 'vs/editor/common/modes'; -import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; +import { CodeLensProvider, CodeLensList, CodeLens } from 'vs/editor/common/modes'; +import { IStorageService, StorageScope, WillSaveStateReason } from 'vs/platform/storage/common/storage'; import { Range } from 'vs/editor/common/core/range'; +import { runWhenIdle } from 'vs/base/common/async'; +import { once } from 'vs/base/common/functional'; export const ICodeLensCache = createDecorator('ICodeLensCache'); export interface ICodeLensCache { _serviceBrand: any; - put(model: ITextModel, data: ICodeLensData[]): void; - get(model: ITextModel): ICodeLensData[] | undefined; + put(model: ITextModel, data: CodeLensModel): void; + get(model: ITextModel): CodeLensModel | undefined; delete(model: ITextModel): void; } @@ -30,16 +32,16 @@ class CacheItem { constructor( readonly lineCount: number, - readonly data: ICodeLensData[] + readonly data: CodeLensModel ) { } } -class CodeLensCache implements ICodeLensCache { +export class CodeLensCache implements ICodeLensCache { _serviceBrand: any; private readonly _fakeProvider = new class implements CodeLensProvider { - provideCodeLenses(): ICodeLensSymbol[] { + provideCodeLenses(): CodeLensList { throw new Error('not supported'); } }; @@ -48,26 +50,29 @@ class CodeLensCache implements ICodeLensCache { constructor(@IStorageService storageService: IStorageService) { - const key = 'codelens/cache'; + // remove old data + const oldkey = 'codelens/cache'; + runWhenIdle(() => storageService.remove(oldkey, StorageScope.WORKSPACE)); // restore lens data on start + const key = 'codelens/cache2'; const raw = storageService.get(key, StorageScope.WORKSPACE, '{}'); this._deserialize(raw); // store lens data on shutdown - const listener = storageService.onWillSaveState(() => { - storageService.store(key, this._serialize(), StorageScope.WORKSPACE); - listener.dispose(); + once(storageService.onWillSaveState)(e => { + if (e.reason === WillSaveStateReason.SHUTDOWN) { + storageService.store(key, this._serialize(), StorageScope.WORKSPACE); + } }); } - put(model: ITextModel, data: ICodeLensData[]): void { - const item = new CacheItem(model.getLineCount(), data.map(item => { - return { - symbol: item.symbol, - provider: this._fakeProvider - }; - })); + put(model: ITextModel, data: CodeLensModel): void { + + const lensModel = new CodeLensModel(); + lensModel.add({ lenses: data.lenses.map(v => v.symbol), dispose() { } }, this._fakeProvider); + + const item = new CacheItem(model.getLineCount(), lensModel); this._cache.set(model.uri.toString(), item); } @@ -86,7 +91,7 @@ class CodeLensCache implements ICodeLensCache { const data: Record = Object.create(null); this._cache.forEach((value, key) => { const lines = new Set(); - for (const d of value.data) { + for (const d of value.data.lenses) { lines.add(d.symbol.range.startLineNumber); } data[key] = { @@ -102,14 +107,14 @@ class CodeLensCache implements ICodeLensCache { const data: Record = JSON.parse(raw); for (const key in data) { const element = data[key]; - const symbols: ICodeLensData[] = []; + const lenses: CodeLens[] = []; for (const line of element.lines) { - symbols.push({ - provider: this._fakeProvider, - symbol: { range: new Range(line, 1, line, 11) } - }); + lenses.push({ range: new Range(line, 1, line, 11) }); } - this._cache.set(key, new CacheItem(element.lineCount, symbols)); + + const model = new CodeLensModel(); + model.add({ lenses, dispose() { } }, this._fakeProvider); + this._cache.set(key, new CacheItem(element.lineCount, model)); } } catch { // ignore... diff --git a/src/vs/editor/contrib/codelens/codelens.ts b/src/vs/editor/contrib/codelens/codelens.ts index 30468bf74..96ccedce7 100644 --- a/src/vs/editor/contrib/codelens/codelens.ts +++ b/src/vs/editor/contrib/codelens/codelens.ts @@ -9,38 +9,59 @@ import { illegalArgument, onUnexpectedExternalError } from 'vs/base/common/error import { URI } from 'vs/base/common/uri'; import { registerLanguageCommand } from 'vs/editor/browser/editorExtensions'; import { ITextModel } from 'vs/editor/common/model'; -import { CodeLensProvider, CodeLensProviderRegistry, ICodeLensSymbol } from 'vs/editor/common/modes'; +import { CodeLensProvider, CodeLensProviderRegistry, CodeLens, CodeLensList } from 'vs/editor/common/modes'; import { IModelService } from 'vs/editor/common/services/modelService'; +import { DisposableStore } from 'vs/base/common/lifecycle'; -export interface ICodeLensData { - symbol: ICodeLensSymbol; +export interface CodeLensItem { + symbol: CodeLens; provider: CodeLensProvider; } -export function getCodeLensData(model: ITextModel, token: CancellationToken): Promise { +export class CodeLensModel { - const symbols: ICodeLensData[] = []; - const provider = CodeLensProviderRegistry.ordered(model); + lenses: CodeLensItem[] = []; - const promises = provider.map(provider => Promise.resolve(provider.provideCodeLenses(model, token)).then(result => { - if (Array.isArray(result)) { - for (let symbol of result) { - symbols.push({ symbol, provider }); - } + private readonly _dispoables = new DisposableStore(); + + dispose(): void { + this._dispoables.dispose(); + } + + add(list: CodeLensList, provider: CodeLensProvider): void { + this._dispoables.add(list); + for (const symbol of list.lenses) { + this.lenses.push({ symbol, provider }); } - }).catch(onUnexpectedExternalError)); + } +} + +export function getCodeLensData(model: ITextModel, token: CancellationToken): Promise { + + const provider = CodeLensProviderRegistry.ordered(model); + const providerRanks = new Map(); + const result = new CodeLensModel(); + + const promises = provider.map((provider, i) => { + + providerRanks.set(provider, i); + + return Promise.resolve(provider.provideCodeLenses(model, token)) + .then(list => list && result.add(list, provider)) + .catch(onUnexpectedExternalError); + }); return Promise.all(promises).then(() => { - return mergeSort(symbols, (a, b) => { + result.lenses = mergeSort(result.lenses, (a, b) => { // sort by lineNumber, provider-rank, and column if (a.symbol.range.startLineNumber < b.symbol.range.startLineNumber) { return -1; } else if (a.symbol.range.startLineNumber > b.symbol.range.startLineNumber) { return 1; - } else if (provider.indexOf(a.provider) < provider.indexOf(b.provider)) { + } else if (providerRanks.get(a.provider)! < providerRanks.get(b.provider)!) { return -1; - } else if (provider.indexOf(a.provider) > provider.indexOf(b.provider)) { + } else if (providerRanks.get(a.provider)! > providerRanks.get(b.provider)!) { return 1; } else if (a.symbol.range.startColumn < b.symbol.range.startColumn) { return -1; @@ -50,6 +71,8 @@ export function getCodeLensData(model: ITextModel, token: CancellationToken): Pr return 0; } }); + + return result; }); } @@ -65,12 +88,12 @@ registerLanguageCommand('_executeCodeLensProvider', function (accessor, args) { throw illegalArgument(); } - const result: ICodeLensSymbol[] = []; + const result: CodeLens[] = []; return getCodeLensData(model, CancellationToken.None).then(value => { let resolve: Promise[] = []; - for (const item of value) { + for (const item of value.lenses) { if (typeof itemResolveCount === 'undefined' || Boolean(item.symbol.command)) { result.push(item.symbol); } else if (itemResolveCount-- > 0 && item.provider.resolveCodeLens) { @@ -78,7 +101,7 @@ registerLanguageCommand('_executeCodeLensProvider', function (accessor, args) { } } - return Promise.all(resolve); + return Promise.all(resolve).finally(() => setTimeout(() => value.dispose(), 0)); }).then(() => { return result; diff --git a/src/vs/editor/contrib/codelens/codelensController.ts b/src/vs/editor/contrib/codelens/codelensController.ts index c7d7ced6e..9f36b6917 100644 --- a/src/vs/editor/contrib/codelens/codelensController.ts +++ b/src/vs/editor/contrib/codelens/codelensController.ts @@ -5,16 +5,15 @@ import { CancelablePromise, RunOnceScheduler, createCancelablePromise, disposableTimeout } from 'vs/base/common/async'; import { onUnexpectedError, onUnexpectedExternalError } from 'vs/base/common/errors'; -import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; +import { toDisposable, DisposableStore, dispose } from 'vs/base/common/lifecycle'; import { StableEditorScrollState } from 'vs/editor/browser/core/editorState'; import * as editorBrowser from 'vs/editor/browser/editorBrowser'; import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; -import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { IModelDecorationsChangeAccessor } from 'vs/editor/common/model'; -import { CodeLensProviderRegistry, ICodeLensSymbol } from 'vs/editor/common/modes'; -import { ICodeLensData, getCodeLensData } from 'vs/editor/contrib/codelens/codelens'; -import { CodeLens, CodeLensHelper } from 'vs/editor/contrib/codelens/codelensWidget'; +import { CodeLensProviderRegistry, CodeLens } from 'vs/editor/common/modes'; +import { CodeLensModel, getCodeLensData, CodeLensItem } from 'vs/editor/contrib/codelens/codelens'; +import { CodeLensWidget, CodeLensHelper } from 'vs/editor/contrib/codelens/codelensWidget'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { ICodeLensCache } from 'vs/editor/contrib/codelens/codeLensCache'; @@ -25,12 +24,14 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { private _isEnabled: boolean; - private _globalToDispose: IDisposable[]; - private _localToDispose: IDisposable[]; - private _lenses: CodeLens[]; - private _currentFindCodeLensSymbolsPromise: CancelablePromise | null; - private _modelChangeCounter: number; - private _currentResolveCodeLensSymbolsPromise: CancelablePromise | null; + private readonly _globalToDispose = new DisposableStore(); + private readonly _localToDispose = new DisposableStore(); + private _lenses: CodeLensWidget[] = []; + private _currentFindCodeLensSymbolsPromise: CancelablePromise | undefined; + private _oldCodeLensModels = new DisposableStore(); + private _currentCodeLensModel: CodeLensModel | undefined; + private _modelChangeCounter: number = 0; + private _currentResolveCodeLensSymbolsPromise: CancelablePromise | undefined; private _detectVisibleLenses: RunOnceScheduler; constructor( @@ -41,41 +42,39 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { ) { this._isEnabled = this._editor.getConfiguration().contribInfo.codeLens; - this._globalToDispose = []; - this._localToDispose = []; - this._lenses = []; - this._currentFindCodeLensSymbolsPromise = null; - this._modelChangeCounter = 0; - - this._globalToDispose.push(this._editor.onDidChangeModel(() => this._onModelChange())); - this._globalToDispose.push(this._editor.onDidChangeModelLanguage(() => this._onModelChange())); - this._globalToDispose.push(this._editor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => { - let prevIsEnabled = this._isEnabled; + this._globalToDispose.add(this._editor.onDidChangeModel(() => this._onModelChange())); + this._globalToDispose.add(this._editor.onDidChangeModelLanguage(() => this._onModelChange())); + this._globalToDispose.add(this._editor.onDidChangeConfiguration(() => { + const prevIsEnabled = this._isEnabled; this._isEnabled = this._editor.getConfiguration().contribInfo.codeLens; if (prevIsEnabled !== this._isEnabled) { this._onModelChange(); } })); - this._globalToDispose.push(CodeLensProviderRegistry.onDidChange(this._onModelChange, this)); + this._globalToDispose.add(CodeLensProviderRegistry.onDidChange(this._onModelChange, this)); this._onModelChange(); } dispose(): void { this._localDispose(); - this._globalToDispose = dispose(this._globalToDispose); + this._globalToDispose.dispose(); + this._oldCodeLensModels.dispose(); + dispose(this._currentCodeLensModel); } private _localDispose(): void { if (this._currentFindCodeLensSymbolsPromise) { this._currentFindCodeLensSymbolsPromise.cancel(); - this._currentFindCodeLensSymbolsPromise = null; + this._currentFindCodeLensSymbolsPromise = undefined; this._modelChangeCounter++; } if (this._currentResolveCodeLensSymbolsPromise) { this._currentResolveCodeLensSymbolsPromise.cancel(); - this._currentResolveCodeLensSymbolsPromise = null; + this._currentResolveCodeLensSymbolsPromise = undefined; } - this._localToDispose = dispose(this._localToDispose); + this._localToDispose.clear(); + this._oldCodeLensModels.clear(); + dispose(this._currentCodeLensModel); } getId(): string { @@ -104,7 +103,7 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { // no provider -> return but check with // cached lenses. they expire after 30 seconds if (cachedLenses) { - this._localToDispose.push(disposableTimeout(() => { + this._localToDispose.add(disposableTimeout(() => { const cachedLensesNow = this._codeLensCache.get(model); if (cachedLenses === cachedLensesNow) { this._codeLensCache.delete(model); @@ -118,7 +117,7 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { for (const provider of CodeLensProviderRegistry.all(model)) { if (typeof provider.onDidChange === 'function') { let registration = provider.onDidChange(() => scheduler.schedule()); - this._localToDispose.push(registration); + this._localToDispose.add(registration); } } @@ -136,18 +135,26 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { this._currentFindCodeLensSymbolsPromise.then(result => { if (counterValue === this._modelChangeCounter) { // only the last one wins + if (this._currentCodeLensModel) { + this._oldCodeLensModels.add(this._currentCodeLensModel); + } + this._currentCodeLensModel = result; + + // cache model to reduce flicker this._codeLensCache.put(model, result); + + // render lenses this._renderCodeLensSymbols(result); this._detectVisibleLenses.schedule(); } }, onUnexpectedError); }, 250); - this._localToDispose.push(scheduler); - this._localToDispose.push(this._detectVisibleLenses); - this._localToDispose.push(this._editor.onDidChangeModelContent((e) => { - this._editor.changeDecorations((changeAccessor) => { - this._editor.changeViewZones((viewAccessor) => { - let toDispose: CodeLens[] = []; + this._localToDispose.add(scheduler); + this._localToDispose.add(this._detectVisibleLenses); + this._localToDispose.add(this._editor.onDidChangeModelContent(() => { + this._editor.changeDecorations(decorationsAccessor => { + this._editor.changeViewZones(viewZonesAccessor => { + let toDispose: CodeLensWidget[] = []; let lastLensLineNumber: number = -1; this._lenses.forEach((lens) => { @@ -157,17 +164,17 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { toDispose.push(lens); } else { - lens.update(viewAccessor); + lens.update(viewZonesAccessor); lastLensLineNumber = lens.getLineNumber(); } }); let helper = new CodeLensHelper(); toDispose.forEach((l) => { - l.dispose(helper, viewAccessor); + l.dispose(helper, viewZonesAccessor); this._lenses.splice(this._lenses.indexOf(l), 1); }); - helper.commit(changeAccessor); + helper.commit(decorationsAccessor); }); }); @@ -176,20 +183,20 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { // Ask for all references again scheduler.schedule(); })); - this._localToDispose.push(this._editor.onDidScrollChange(e => { + this._localToDispose.add(this._editor.onDidScrollChange(e => { if (e.scrollTopChanged && this._lenses.length > 0) { this._detectVisibleLenses.schedule(); } })); - this._localToDispose.push(this._editor.onDidLayoutChange(e => { + this._localToDispose.add(this._editor.onDidLayoutChange(() => { this._detectVisibleLenses.schedule(); })); - this._localToDispose.push(toDisposable(() => { + this._localToDispose.add(toDisposable(() => { if (this._editor.getModel()) { const scrollState = StableEditorScrollState.capture(this._editor); - this._editor.changeDecorations((changeAccessor) => { - this._editor.changeViewZones((accessor) => { - this._disposeAllLenses(changeAccessor, accessor); + this._editor.changeDecorations(decorationsAccessor => { + this._editor.changeViewZones(viewZonesAccessor => { + this._disposeAllLenses(decorationsAccessor, viewZonesAccessor); }); }); scrollState.restore(this._editor); @@ -198,14 +205,14 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { this._disposeAllLenses(undefined, undefined); } })); - this._localToDispose.push(this._editor.onDidChangeConfiguration(e => { + this._localToDispose.add(this._editor.onDidChangeConfiguration(e => { if (e.fontInfo) { for (const lens of this._lenses) { lens.updateHeight(); } } })); - this._localToDispose.push(this._editor.onMouseUp(e => { + this._localToDispose.add(this._editor.onMouseUp(e => { if (e.target.type === editorBrowser.MouseTargetType.CONTENT_WIDGET && e.target.element && e.target.element.tagName === 'A') { for (const lens of this._lenses) { let command = lens.getCommand(e.target.element as HTMLLinkElement); @@ -228,16 +235,16 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { this._lenses = []; } - private _renderCodeLensSymbols(symbols: ICodeLensData[]): void { + private _renderCodeLensSymbols(symbols: CodeLensModel): void { if (!this._editor.hasModel()) { return; } let maxLineNumber = this._editor.getModel().getLineCount(); - let groups: ICodeLensData[][] = []; - let lastGroup: ICodeLensData[] | undefined; + let groups: CodeLensItem[][] = []; + let lastGroup: CodeLensItem[] | undefined; - for (let symbol of symbols) { + for (let symbol of symbols.lenses) { let line = symbol.symbol.range.startLineNumber; if (line < 1 || line > maxLineNumber) { // invalid code lens @@ -254,10 +261,12 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { const scrollState = StableEditorScrollState.capture(this._editor); - this._editor.changeDecorations((changeAccessor) => { - this._editor.changeViewZones((accessor) => { + this._editor.changeDecorations(decorationsAccessor => { + this._editor.changeViewZones(viewZoneAccessor => { - let codeLensIndex = 0, groupsIndex = 0, helper = new CodeLensHelper(); + const helper = new CodeLensHelper(); + let codeLensIndex = 0; + let groupsIndex = 0; while (groupsIndex < groups.length && codeLensIndex < this._lenses.length) { @@ -265,14 +274,14 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { let codeLensLineNumber = this._lenses[codeLensIndex].getLineNumber(); if (codeLensLineNumber < symbolsLineNumber) { - this._lenses[codeLensIndex].dispose(helper, accessor); + this._lenses[codeLensIndex].dispose(helper, viewZoneAccessor); this._lenses.splice(codeLensIndex, 1); } else if (codeLensLineNumber === symbolsLineNumber) { this._lenses[codeLensIndex].updateCodeLensSymbols(groups[groupsIndex], helper); groupsIndex++; codeLensIndex++; } else { - this._lenses.splice(codeLensIndex, 0, new CodeLens(groups[groupsIndex], this._editor, helper, accessor, () => this._detectVisibleLenses.schedule())); + this._lenses.splice(codeLensIndex, 0, new CodeLensWidget(groups[groupsIndex], this._editor, helper, viewZoneAccessor, () => this._detectVisibleLenses.schedule())); codeLensIndex++; groupsIndex++; } @@ -280,17 +289,17 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { // Delete extra code lenses while (codeLensIndex < this._lenses.length) { - this._lenses[codeLensIndex].dispose(helper, accessor); + this._lenses[codeLensIndex].dispose(helper, viewZoneAccessor); this._lenses.splice(codeLensIndex, 1); } // Create extra symbols while (groupsIndex < groups.length) { - this._lenses.push(new CodeLens(groups[groupsIndex], this._editor, helper, accessor, () => this._detectVisibleLenses.schedule())); + this._lenses.push(new CodeLensWidget(groups[groupsIndex], this._editor, helper, viewZoneAccessor, () => this._detectVisibleLenses.schedule())); groupsIndex++; } - helper.commit(changeAccessor); + helper.commit(decorationsAccessor); }); }); @@ -300,7 +309,7 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { private _onViewportChanged(): void { if (this._currentResolveCodeLensSymbolsPromise) { this._currentResolveCodeLensSymbolsPromise.cancel(); - this._currentResolveCodeLensSymbolsPromise = null; + this._currentResolveCodeLensSymbolsPromise = undefined; } const model = this._editor.getModel(); @@ -308,8 +317,8 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { return; } - const toResolve: ICodeLensData[][] = []; - const lenses: CodeLens[] = []; + const toResolve: CodeLensItem[][] = []; + const lenses: CodeLensWidget[] = []; this._lenses.forEach((lens) => { const request = lens.computeIfNecessary(model); if (request) { @@ -326,7 +335,7 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { const promises = toResolve.map((request, i) => { - const resolvedSymbols = new Array(request.length); + const resolvedSymbols = new Array(request.length); const promises = request.map((request, i) => { if (!request.symbol.command && typeof request.provider.resolveCodeLens === 'function') { return Promise.resolve(request.provider.resolveCodeLens(model, request.symbol, token)).then(symbol => { @@ -339,7 +348,9 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { }); return Promise.all(promises).then(() => { - lenses[i].updateCommands(resolvedSymbols); + if (!token.isCancellationRequested) { + lenses[i].updateCommands(resolvedSymbols); + } }); }); @@ -347,10 +358,11 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { }); this._currentResolveCodeLensSymbolsPromise.then(() => { - this._currentResolveCodeLensSymbolsPromise = null; - }).catch(err => { - this._currentResolveCodeLensSymbolsPromise = null; - onUnexpectedError(err); + this._oldCodeLensModels.clear(); // dispose old models once we have updated the UI with the current model + this._currentResolveCodeLensSymbolsPromise = undefined; + }, err => { + onUnexpectedError(err); // can also be cancellation! + this._currentResolveCodeLensSymbolsPromise = undefined; }); } } diff --git a/src/vs/editor/contrib/codelens/codelensWidget.ts b/src/vs/editor/contrib/codelens/codelensWidget.ts index 9a0a0bbe9..24ed75a44 100644 --- a/src/vs/editor/contrib/codelens/codelensWidget.ts +++ b/src/vs/editor/contrib/codelens/codelensWidget.ts @@ -11,9 +11,9 @@ import * as editorBrowser from 'vs/editor/browser/editorBrowser'; import { Range } from 'vs/editor/common/core/range'; import { IModelDecorationsChangeAccessor, IModelDeltaDecoration, ITextModel } from 'vs/editor/common/model'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; -import { Command, ICodeLensSymbol } from 'vs/editor/common/modes'; +import { Command, CodeLens } from 'vs/editor/common/modes'; import { editorCodeLensForeground } from 'vs/editor/common/view/editorColorRegistry'; -import { ICodeLensData } from 'vs/editor/contrib/codelens/codelens'; +import { CodeLensItem } from 'vs/editor/contrib/codelens/codelens'; import { editorActiveLinkForeground } from 'vs/platform/theme/common/colorRegistry'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; @@ -65,7 +65,7 @@ class CodeLensContentWidget implements editorBrowser.IContentWidget { constructor( editor: editorBrowser.ICodeEditor, symbolRange: Range, - data: ICodeLensData[] + data: CodeLensItem[] ) { this._id = 'codeLensWidget' + (++CodeLensContentWidget._idPool); this._editor = editor; @@ -88,7 +88,7 @@ class CodeLensContentWidget implements editorBrowser.IContentWidget { this._domNode.innerHTML = ' '; } - withCommands(inSymbols: Array, animate: boolean): void { + withCommands(inSymbols: Array, animate: boolean): void { this._commands.clear(); const symbols = coalesce(inSymbols); @@ -189,17 +189,17 @@ export class CodeLensHelper { } } -export class CodeLens { +export class CodeLensWidget { private readonly _editor: editorBrowser.ICodeEditor; private readonly _viewZone: CodeLensViewZone; private readonly _viewZoneId: number; private readonly _contentWidget: CodeLensContentWidget; private _decorationIds: string[]; - private _data: ICodeLensData[]; + private _data: CodeLensItem[]; constructor( - data: ICodeLensData[], + data: CodeLensItem[], editor: editorBrowser.ICodeEditor, helper: CodeLensHelper, viewZoneChangeAccessor: editorBrowser.IViewZoneChangeAccessor, @@ -256,7 +256,7 @@ export class CodeLens { }); } - updateCodeLensSymbols(data: ICodeLensData[], helper: CodeLensHelper): void { + updateCodeLensSymbols(data: CodeLensItem[], helper: CodeLensHelper): void { while (this._decorationIds.length) { helper.removeDecoration(this._decorationIds.pop()!); } @@ -270,7 +270,7 @@ export class CodeLens { }); } - computeIfNecessary(model: ITextModel): ICodeLensData[] | null { + computeIfNecessary(model: ITextModel): CodeLensItem[] | null { if (!this._contentWidget.isVisible()) { return null; } @@ -285,7 +285,7 @@ export class CodeLens { return this._data; } - updateCommands(symbols: Array): void { + updateCommands(symbols: Array): void { this._contentWidget.withCommands(symbols, true); for (let i = 0; i < this._data.length; i++) { const resolved = symbols[i]; diff --git a/src/vs/editor/contrib/colorPicker/colorDetector.ts b/src/vs/editor/contrib/colorPicker/colorDetector.ts index 1de0bda03..0ccf498c0 100644 --- a/src/vs/editor/contrib/colorPicker/colorDetector.ts +++ b/src/vs/editor/contrib/colorPicker/colorDetector.ts @@ -7,7 +7,7 @@ import { CancelablePromise, TimeoutTimer, createCancelablePromise } from 'vs/bas import { RGBA } from 'vs/base/common/color'; import { onUnexpectedError } from 'vs/base/common/errors'; import { hash } from 'vs/base/common/hash'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; @@ -22,14 +22,13 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur const MAX_DECORATORS = 500; -export class ColorDetector implements IEditorContribution { +export class ColorDetector extends Disposable implements IEditorContribution { private static readonly ID: string = 'editor.contrib.colorDetector'; static RECOMPUTE_TIME = 1000; // ms - private _globalToDispose: IDisposable[] = []; - private _localToDispose: IDisposable[] = []; + private readonly _localToDispose = this._register(new DisposableStore()); private _computePromise: CancelablePromise | null; private _timeoutTimer: TimeoutTimer | null; @@ -37,7 +36,7 @@ export class ColorDetector implements IEditorContribution { private _colorDatas = new Map(); private _colorDecoratorIds: string[] = []; - private readonly _decorationsTypes: { [key: string]: boolean } = {}; + private readonly _decorationsTypes = new Set(); private _isEnabled: boolean; @@ -45,13 +44,14 @@ export class ColorDetector implements IEditorContribution { @ICodeEditorService private readonly _codeEditorService: ICodeEditorService, @IConfigurationService private readonly _configurationService: IConfigurationService ) { - this._globalToDispose.push(_editor.onDidChangeModel((e) => { + super(); + this._register(_editor.onDidChangeModel((e) => { this._isEnabled = this.isEnabled(); this.onModelChanged(); })); - this._globalToDispose.push(_editor.onDidChangeModelLanguage((e) => this.onModelChanged())); - this._globalToDispose.push(ColorProviderRegistry.onDidChange((e) => this.onModelChanged())); - this._globalToDispose.push(_editor.onDidChangeConfiguration((e) => { + this._register(_editor.onDidChangeModelLanguage((e) => this.onModelChanged())); + this._register(ColorProviderRegistry.onDidChange((e) => this.onModelChanged())); + this._register(_editor.onDidChangeConfiguration((e) => { let prevIsEnabled = this._isEnabled; this._isEnabled = this.isEnabled(); if (prevIsEnabled !== this._isEnabled) { @@ -76,9 +76,9 @@ export class ColorDetector implements IEditorContribution { } const languageId = model.getLanguageIdentifier(); // handle deprecated settings. [languageId].colorDecorators.enable - let deprecatedConfig = this._configurationService.getValue(languageId.language); + const deprecatedConfig = this._configurationService.getValue<{}>(languageId.language); if (deprecatedConfig) { - let colorDecorators = deprecatedConfig['colorDecorators']; // deprecatedConfig.valueOf('.colorDecorators.enable'); + const colorDecorators = (deprecatedConfig as any)['colorDecorators']; // deprecatedConfig.valueOf('.colorDecorators.enable'); if (colorDecorators && colorDecorators['enable'] !== undefined && !colorDecorators['enable']) { return colorDecorators['enable']; } @@ -98,7 +98,7 @@ export class ColorDetector implements IEditorContribution { dispose(): void { this.stop(); this.removeAllDecorations(); - this._globalToDispose = dispose(this._globalToDispose); + super.dispose(); } private onModelChanged(): void { @@ -113,7 +113,7 @@ export class ColorDetector implements IEditorContribution { return; } - this._localToDispose.push(this._editor.onDidChangeModelContent((e) => { + this._localToDispose.add(this._editor.onDidChangeModelContent((e) => { if (!this._timeoutTimer) { this._timeoutTimer = new TimeoutTimer(); this._timeoutTimer.cancelAndSet(() => { @@ -149,7 +149,7 @@ export class ColorDetector implements IEditorContribution { this._computePromise.cancel(); this._computePromise = null; } - this._localToDispose = dispose(this._localToDispose); + this._localToDispose.clear(); } private updateDecorations(colorDatas: IColorData[]): void { @@ -180,7 +180,7 @@ export class ColorDetector implements IEditorContribution { let color = `rgba(${rgba.r}, ${rgba.g}, ${rgba.b}, ${rgba.a})`; let key = 'colorBox-' + subKey; - if (!this._decorationsTypes[key] && !newDecorationsTypes[key]) { + if (!this._decorationsTypes.has(key) && !newDecorationsTypes[key]) { this._codeEditorService.registerDecorationType(key, { before: { contentText: ' ', @@ -210,11 +210,11 @@ export class ColorDetector implements IEditorContribution { }); } - for (let subType in this._decorationsTypes) { + this._decorationsTypes.forEach(subType => { if (!newDecorationsTypes[subType]) { this._codeEditorService.removeDecorationType(subType); } - } + }); this._colorDecoratorIds = this._editor.deltaDecorations(this._colorDecoratorIds, decorations); } @@ -223,9 +223,9 @@ export class ColorDetector implements IEditorContribution { this._decorationsIds = this._editor.deltaDecorations(this._decorationsIds, []); this._colorDecoratorIds = this._editor.deltaDecorations(this._colorDecoratorIds, []); - for (let subType in this._decorationsTypes) { + this._decorationsTypes.forEach(subType => { this._codeEditorService.removeDecorationType(subType); - } + }); } getColorData(position: Position): IColorData | null { diff --git a/src/vs/editor/contrib/colorPicker/colorPicker.css b/src/vs/editor/contrib/colorPicker/colorPicker.css index b1978528c..d1d83d46b 100644 --- a/src/vs/editor/contrib/colorPicker/colorPicker.css +++ b/src/vs/editor/contrib/colorPicker/colorPicker.css @@ -84,21 +84,21 @@ .colorpicker-body .hue-strip { position: relative; margin-left: 8px; - cursor: -webkit-grab; + cursor: grab; background: linear-gradient(to bottom, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); } .colorpicker-body .opacity-strip { position: relative; margin-left: 8px; - cursor: -webkit-grab; + cursor: grab; background: url('images/opacity-background.png'); background-size: 9px 9px; image-rendering: pixelated; } .colorpicker-body .strip.grabbing { - cursor: -webkit-grabbing; + cursor: grabbing; } .colorpicker-body .slider { diff --git a/src/vs/editor/contrib/comment/test/lineCommentCommand.test.ts b/src/vs/editor/contrib/comment/test/lineCommentCommand.test.ts index e9c0c5149..5f8b23c6e 100644 --- a/src/vs/editor/contrib/comment/test/lineCommentCommand.test.ts +++ b/src/vs/editor/contrib/comment/test/lineCommentCommand.test.ts @@ -986,7 +986,8 @@ suite('Editor Contrib - Line Comment in mixed modes', () => { selection, (sel) => new LineCommentCommand(sel, 4, Type.Toggle), expectedLines, - expectedSelection + expectedSelection, + true ); innerMode.dispose(); outerMode.dispose(); diff --git a/src/vs/editor/contrib/contextmenu/contextmenu.ts b/src/vs/editor/contrib/contextmenu/contextmenu.ts index 8fa07282f..2209b38da 100644 --- a/src/vs/editor/contrib/contextmenu/contextmenu.ts +++ b/src/vs/editor/contrib/contextmenu/contextmenu.ts @@ -6,11 +6,11 @@ import * as nls from 'vs/nls'; import * as dom from 'vs/base/browser/dom'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import { ActionItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; +import { ActionViewItem, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { IAnchor } from 'vs/base/browser/ui/contextview/contextview'; import { IAction } from 'vs/base/common/actions'; import { KeyCode, KeyMod, ResolvedKeybinding } from 'vs/base/common/keyCodes'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { DisposableStore } from 'vs/base/common/lifecycle'; import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; import { EditorAction, ServicesAccessor, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import { IEditorContribution, ScrollType } from 'vs/editor/common/editorCommon'; @@ -31,7 +31,7 @@ export class ContextMenuController implements IEditorContribution { return editor.getContribution(ContextMenuController.ID); } - private _toDispose: IDisposable[] = []; + private readonly _toDispose = new DisposableStore(); private _contextMenuIsBeingShownCount: number = 0; private readonly _editor: ICodeEditor; @@ -45,13 +45,13 @@ export class ContextMenuController implements IEditorContribution { ) { this._editor = editor; - this._toDispose.push(this._editor.onContextMenu((e: IEditorMouseEvent) => this._onContextMenu(e))); - this._toDispose.push(this._editor.onMouseWheel((e: IMouseWheelEvent) => { + this._toDispose.add(this._editor.onContextMenu((e: IEditorMouseEvent) => this._onContextMenu(e))); + this._toDispose.add(this._editor.onMouseWheel((e: IMouseWheelEvent) => { if (this._contextMenuIsBeingShownCount > 0) { this._contextViewService.hideContextView(); } })); - this._toDispose.push(this._editor.onKeyDown((e: IKeyboardEvent) => { + this._toDispose.add(this._editor.onKeyDown((e: IKeyboardEvent) => { if (e.keyCode === KeyCode.ContextMenu) { // Chrome is funny like that e.preventDefault(); @@ -125,7 +125,7 @@ export class ContextMenuController implements IEditorContribution { } } - private _getMenuActions(model: ITextModel): IAction[] { + private _getMenuActions(model: ITextModel): ReadonlyArray { const result: IAction[] = []; let contextMenu = this._menuService.createMenu(MenuId.EditorContext, this._contextKeyService); @@ -141,7 +141,7 @@ export class ContextMenuController implements IEditorContribution { return result; } - private _doShowContextMenu(actions: IAction[], anchor: IAnchor | null = null): void { + private _doShowContextMenu(actions: ReadonlyArray, anchor: IAnchor | null = null): void { if (!this._editor.hasModel()) { return; } @@ -176,18 +176,18 @@ export class ContextMenuController implements IEditorContribution { getActions: () => actions, - getActionItem: (action) => { + getActionViewItem: (action) => { const keybinding = this._keybindingFor(action); if (keybinding) { - return new ActionItem(action, action, { label: true, keybinding: keybinding.getLabel(), isMenu: true }); + return new ActionViewItem(action, action, { label: true, keybinding: keybinding.getLabel(), isMenu: true }); } - const customActionItem = action; - if (typeof customActionItem.getActionItem === 'function') { - return customActionItem.getActionItem(); + const customActionViewItem = action; + if (typeof customActionViewItem.getActionViewItem === 'function') { + return customActionViewItem.getActionViewItem(); } - return new ActionItem(action, action, { icon: true, label: true, isMenu: true }); + return new ActionViewItem(action, action, { icon: true, label: true, isMenu: true }); }, getKeyBinding: (action): ResolvedKeybinding | undefined => { @@ -217,7 +217,7 @@ export class ContextMenuController implements IEditorContribution { this._contextViewService.hideContextView(); } - this._toDispose = dispose(this._toDispose); + this._toDispose.dispose(); } } @@ -228,7 +228,7 @@ class ShowContextMenu extends EditorAction { id: 'editor.action.showContextMenu', label: nls.localize('action.showContextMenu.label', "Show Editor Context Menu"), alias: 'Show Editor Context Menu', - precondition: null, + precondition: undefined, kbOpts: { kbExpr: EditorContextKeys.textInputFocus, primary: KeyMod.Shift | KeyCode.F10, diff --git a/src/vs/editor/contrib/cursorUndo/cursorUndo.ts b/src/vs/editor/contrib/cursorUndo/cursorUndo.ts index 4b37afc51..d543253b0 100644 --- a/src/vs/editor/contrib/cursorUndo/cursorUndo.ts +++ b/src/vs/editor/contrib/cursorUndo/cursorUndo.ts @@ -119,7 +119,7 @@ export class CursorUndo extends EditorAction { id: 'cursorUndo', label: nls.localize('cursor.undo', "Soft Undo"), alias: 'Soft Undo', - precondition: null, + precondition: undefined, kbOpts: { kbExpr: EditorContextKeys.textInputFocus, primary: KeyMod.CtrlCmd | KeyCode.KEY_U, diff --git a/src/vs/editor/contrib/dnd/dnd.ts b/src/vs/editor/contrib/dnd/dnd.ts index 44a5dd539..70b3551b5 100644 --- a/src/vs/editor/contrib/dnd/dnd.ts +++ b/src/vs/editor/contrib/dnd/dnd.ts @@ -5,7 +5,7 @@ import 'vs/css!./dnd'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { Disposable } from 'vs/base/common/lifecycle'; import { isMacintosh } from 'vs/base/common/platform'; import { KeyCode } from 'vs/base/common/keyCodes'; import { ICodeEditor, IEditorMouseEvent, IMouseTarget, MouseTargetType } from 'vs/editor/browser/editorBrowser'; @@ -28,12 +28,11 @@ function hasTriggerModifier(e: IKeyboardEvent | IMouseEvent): boolean { } } -export class DragAndDropController implements editorCommon.IEditorContribution { +export class DragAndDropController extends Disposable implements editorCommon.IEditorContribution { private static readonly ID = 'editor.contrib.dragAndDrop'; private readonly _editor: ICodeEditor; - private _toUnhook: IDisposable[]; private _dragSelection: Selection | null; private _dndDecorationIds: string[]; private _mouseDown: boolean; @@ -45,15 +44,15 @@ export class DragAndDropController implements editorCommon.IEditorContribution { } constructor(editor: ICodeEditor) { + super(); this._editor = editor; - this._toUnhook = []; - this._toUnhook.push(this._editor.onMouseDown((e: IEditorMouseEvent) => this._onEditorMouseDown(e))); - this._toUnhook.push(this._editor.onMouseUp((e: IEditorMouseEvent) => this._onEditorMouseUp(e))); - this._toUnhook.push(this._editor.onMouseDrag((e: IEditorMouseEvent) => this._onEditorMouseDrag(e))); - this._toUnhook.push(this._editor.onMouseDrop((e: IEditorMouseEvent) => this._onEditorMouseDrop(e))); - this._toUnhook.push(this._editor.onKeyDown((e: IKeyboardEvent) => this.onEditorKeyDown(e))); - this._toUnhook.push(this._editor.onKeyUp((e: IKeyboardEvent) => this.onEditorKeyUp(e))); - this._toUnhook.push(this._editor.onDidBlurEditorWidget(() => this.onEditorBlur())); + this._register(this._editor.onMouseDown((e: IEditorMouseEvent) => this._onEditorMouseDown(e))); + this._register(this._editor.onMouseUp((e: IEditorMouseEvent) => this._onEditorMouseUp(e))); + this._register(this._editor.onMouseDrag((e: IEditorMouseEvent) => this._onEditorMouseDrag(e))); + this._register(this._editor.onMouseDrop((e: IEditorMouseEvent) => this._onEditorMouseDrop(e))); + this._register(this._editor.onKeyDown((e: IKeyboardEvent) => this.onEditorKeyDown(e))); + this._register(this._editor.onKeyUp((e: IKeyboardEvent) => this.onEditorKeyUp(e))); + this._register(this._editor.onDidBlurEditorWidget(() => this.onEditorBlur())); this._dndDecorationIds = []; this._mouseDown = false; this._modifierPressed = false; @@ -228,7 +227,7 @@ export class DragAndDropController implements editorCommon.IEditorContribution { this._dragSelection = null; this._mouseDown = false; this._modifierPressed = false; - this._toUnhook = dispose(this._toUnhook); + super.dispose(); } } diff --git a/src/vs/editor/contrib/dnd/dragAndDropCommand.ts b/src/vs/editor/contrib/dnd/dragAndDropCommand.ts index 12d405648..f2c9aa869 100644 --- a/src/vs/editor/contrib/dnd/dragAndDropCommand.ts +++ b/src/vs/editor/contrib/dnd/dragAndDropCommand.ts @@ -91,7 +91,7 @@ export class DragAndDropCommand implements editorCommon.ICommand { this.selection.endColumn ); } else { - // The target position is before the selection's end postion. Since the selection doesn't contain the target position, the selection is one-line and target position is before this selection. + // The target position is before the selection's end position. Since the selection doesn't contain the target position, the selection is one-line and target position is before this selection. this.targetSelection = new Selection( this.targetPosition.lineNumber - this.selection.endLineNumber + this.selection.startLineNumber, this.targetPosition.column, diff --git a/src/vs/editor/contrib/documentSymbols/media/BooleanData_16x.svg b/src/vs/editor/contrib/documentSymbols/media/BooleanData_16x.svg deleted file mode 100644 index d9fd295d0..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/BooleanData_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/BooleanData_16x_darkp.svg b/src/vs/editor/contrib/documentSymbols/media/BooleanData_16x_darkp.svg deleted file mode 100644 index 48e8c5a38..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/BooleanData_16x_darkp.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/Class_16x.svg b/src/vs/editor/contrib/documentSymbols/media/Class_16x.svg deleted file mode 100644 index e553c3633..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/Class_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/Class_16x_darkp.svg b/src/vs/editor/contrib/documentSymbols/media/Class_16x_darkp.svg deleted file mode 100644 index c43aad29e..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/Class_16x_darkp.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/ColorPalette_ColorPalette_16x.svg b/src/vs/editor/contrib/documentSymbols/media/ColorPalette_ColorPalette_16x.svg deleted file mode 100644 index 2af5cc6fa..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/ColorPalette_ColorPalette_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/ColorPalette_ColorPalette_16x_darkp.svg b/src/vs/editor/contrib/documentSymbols/media/ColorPalette_ColorPalette_16x_darkp.svg deleted file mode 100644 index a2df3032c..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/ColorPalette_ColorPalette_16x_darkp.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/Constant_16x.svg b/src/vs/editor/contrib/documentSymbols/media/Constant_16x.svg deleted file mode 100644 index ed2a17510..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/Constant_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/Constant_16x_inverse.svg b/src/vs/editor/contrib/documentSymbols/media/Constant_16x_inverse.svg deleted file mode 100644 index 173e427f9..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/Constant_16x_inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/Document_16x.svg b/src/vs/editor/contrib/documentSymbols/media/Document_16x.svg deleted file mode 100644 index 7b36178ab..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/Document_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/Document_16x_darkp.svg b/src/vs/editor/contrib/documentSymbols/media/Document_16x_darkp.svg deleted file mode 100644 index bced3a467..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/Document_16x_darkp.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/EnumItem_16x.svg b/src/vs/editor/contrib/documentSymbols/media/EnumItem_16x.svg deleted file mode 100755 index aa901ec19..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/EnumItem_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/EnumItem_inverse_16x.svg b/src/vs/editor/contrib/documentSymbols/media/EnumItem_inverse_16x.svg deleted file mode 100755 index 791759092..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/EnumItem_inverse_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/Enumerator_16x.svg b/src/vs/editor/contrib/documentSymbols/media/Enumerator_16x.svg deleted file mode 100755 index e4a9551fd..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/Enumerator_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/Enumerator_inverse_16x.svg b/src/vs/editor/contrib/documentSymbols/media/Enumerator_inverse_16x.svg deleted file mode 100755 index d8e9f4f10..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/Enumerator_inverse_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/Event_16x_vscode.svg b/src/vs/editor/contrib/documentSymbols/media/Event_16x_vscode.svg deleted file mode 100644 index 0e202ec10..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/Event_16x_vscode.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/Event_16x_vscode_inverse.svg b/src/vs/editor/contrib/documentSymbols/media/Event_16x_vscode_inverse.svg deleted file mode 100644 index a508edcd3..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/Event_16x_vscode_inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/Field_16x.svg b/src/vs/editor/contrib/documentSymbols/media/Field_16x.svg deleted file mode 100644 index e1b5aa5e3..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/Field_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/Field_16x_darkp.svg b/src/vs/editor/contrib/documentSymbols/media/Field_16x_darkp.svg deleted file mode 100644 index 5fc48ceff..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/Field_16x_darkp.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/Indexer_16x.svg b/src/vs/editor/contrib/documentSymbols/media/Indexer_16x.svg deleted file mode 100644 index ff55f31ff..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/Indexer_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/Indexer_16x_darkp.svg b/src/vs/editor/contrib/documentSymbols/media/Indexer_16x_darkp.svg deleted file mode 100644 index 2f3788e77..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/Indexer_16x_darkp.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/IntelliSenseKeyword_16x.svg b/src/vs/editor/contrib/documentSymbols/media/IntelliSenseKeyword_16x.svg deleted file mode 100644 index 7a80c7fe2..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/IntelliSenseKeyword_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/IntelliSenseKeyword_16x_darkp.svg b/src/vs/editor/contrib/documentSymbols/media/IntelliSenseKeyword_16x_darkp.svg deleted file mode 100644 index ef98b5133..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/IntelliSenseKeyword_16x_darkp.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/Interface_16x.svg b/src/vs/editor/contrib/documentSymbols/media/Interface_16x.svg deleted file mode 100644 index 0c08c8d50..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/Interface_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/Interface_16x_darkp.svg b/src/vs/editor/contrib/documentSymbols/media/Interface_16x_darkp.svg deleted file mode 100644 index f7c2934a5..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/Interface_16x_darkp.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/LocalVariable_16x_vscode.svg b/src/vs/editor/contrib/documentSymbols/media/LocalVariable_16x_vscode.svg deleted file mode 100644 index e78894b6c..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/LocalVariable_16x_vscode.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/LocalVariable_16x_vscode_inverse.svg b/src/vs/editor/contrib/documentSymbols/media/LocalVariable_16x_vscode_inverse.svg deleted file mode 100644 index 44a44b489..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/LocalVariable_16x_vscode_inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/Method_16x.svg b/src/vs/editor/contrib/documentSymbols/media/Method_16x.svg deleted file mode 100644 index e1b587f9c..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/Method_16x.svg +++ /dev/null @@ -1 +0,0 @@ -Method_16x \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/Method_16x_darkp.svg b/src/vs/editor/contrib/documentSymbols/media/Method_16x_darkp.svg deleted file mode 100644 index 0b7dd26ef..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/Method_16x_darkp.svg +++ /dev/null @@ -1 +0,0 @@ -Method_16x \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/Namespace_16x.svg b/src/vs/editor/contrib/documentSymbols/media/Namespace_16x.svg deleted file mode 100644 index 772b9152c..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/Namespace_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/Namespace_16x_darkp.svg b/src/vs/editor/contrib/documentSymbols/media/Namespace_16x_darkp.svg deleted file mode 100644 index dc052a068..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/Namespace_16x_darkp.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/Numeric_16x.svg b/src/vs/editor/contrib/documentSymbols/media/Numeric_16x.svg deleted file mode 100644 index ac848f89b..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/Numeric_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/Numeric_16x_darkp.svg b/src/vs/editor/contrib/documentSymbols/media/Numeric_16x_darkp.svg deleted file mode 100644 index 4144eea0c..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/Numeric_16x_darkp.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/Operator_16x_vscode.svg b/src/vs/editor/contrib/documentSymbols/media/Operator_16x_vscode.svg deleted file mode 100644 index ba2f2d091..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/Operator_16x_vscode.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/Operator_16x_vscode_inverse.svg b/src/vs/editor/contrib/documentSymbols/media/Operator_16x_vscode_inverse.svg deleted file mode 100644 index 21e1e814b..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/Operator_16x_vscode_inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/Property_16x.svg b/src/vs/editor/contrib/documentSymbols/media/Property_16x.svg deleted file mode 100644 index cac629e11..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/Property_16x.svg +++ /dev/null @@ -1 +0,0 @@ -Property_16x \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/Property_16x_darkp.svg b/src/vs/editor/contrib/documentSymbols/media/Property_16x_darkp.svg deleted file mode 100644 index bad83c9a3..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/Property_16x_darkp.svg +++ /dev/null @@ -1 +0,0 @@ -Property_16x \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/Snippet_16x.svg b/src/vs/editor/contrib/documentSymbols/media/Snippet_16x.svg deleted file mode 100644 index 640c24778..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/Snippet_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/Snippet_16x_darkp.svg b/src/vs/editor/contrib/documentSymbols/media/Snippet_16x_darkp.svg deleted file mode 100644 index 0fb4b8bc9..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/Snippet_16x_darkp.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/String_16x.svg b/src/vs/editor/contrib/documentSymbols/media/String_16x.svg deleted file mode 100644 index 880d50dd0..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/String_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/String_16x_darkp.svg b/src/vs/editor/contrib/documentSymbols/media/String_16x_darkp.svg deleted file mode 100644 index de3ea3b37..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/String_16x_darkp.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/Structure_16x_vscode.svg b/src/vs/editor/contrib/documentSymbols/media/Structure_16x_vscode.svg deleted file mode 100644 index e776cbc56..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/Structure_16x_vscode.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/Structure_16x_vscode_inverse.svg b/src/vs/editor/contrib/documentSymbols/media/Structure_16x_vscode_inverse.svg deleted file mode 100644 index 1b76b62be..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/Structure_16x_vscode_inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/Template_16x_vscode.svg b/src/vs/editor/contrib/documentSymbols/media/Template_16x_vscode.svg deleted file mode 100644 index 788cc8d64..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/Template_16x_vscode.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/Template_16x_vscode_inverse.svg b/src/vs/editor/contrib/documentSymbols/media/Template_16x_vscode_inverse.svg deleted file mode 100644 index 6cec71cb0..000000000 --- a/src/vs/editor/contrib/documentSymbols/media/Template_16x_vscode_inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/documentSymbols/media/boolean-dark.svg b/src/vs/editor/contrib/documentSymbols/media/boolean-dark.svg new file mode 100644 index 000000000..e009568b1 --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/boolean-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/boolean-light.svg b/src/vs/editor/contrib/documentSymbols/media/boolean-light.svg new file mode 100644 index 000000000..06613f8be --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/boolean-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/class-dark.svg b/src/vs/editor/contrib/documentSymbols/media/class-dark.svg new file mode 100644 index 000000000..a71e221f6 --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/class-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/class-light.svg b/src/vs/editor/contrib/documentSymbols/media/class-light.svg new file mode 100644 index 000000000..aa106f18f --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/class-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/constant-dark.svg b/src/vs/editor/contrib/documentSymbols/media/constant-dark.svg new file mode 100644 index 000000000..0e90ecafc --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/constant-dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/constant-light.svg b/src/vs/editor/contrib/documentSymbols/media/constant-light.svg new file mode 100644 index 000000000..1a369c1d8 --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/constant-light.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/enumerator-dark.svg b/src/vs/editor/contrib/documentSymbols/media/enumerator-dark.svg new file mode 100644 index 000000000..82d4ff29c --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/enumerator-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/enumerator-item-dark.svg b/src/vs/editor/contrib/documentSymbols/media/enumerator-item-dark.svg new file mode 100644 index 000000000..23c697fdf --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/enumerator-item-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/enumerator-item-light.svg b/src/vs/editor/contrib/documentSymbols/media/enumerator-item-light.svg new file mode 100644 index 000000000..a99045d33 --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/enumerator-item-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/enumerator-light.svg b/src/vs/editor/contrib/documentSymbols/media/enumerator-light.svg new file mode 100644 index 000000000..e2441a0dc --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/enumerator-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/event-dark.svg b/src/vs/editor/contrib/documentSymbols/media/event-dark.svg new file mode 100644 index 000000000..051bef316 --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/event-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/event-light.svg b/src/vs/editor/contrib/documentSymbols/media/event-light.svg new file mode 100644 index 000000000..712344d1f --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/event-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/field-dark.svg b/src/vs/editor/contrib/documentSymbols/media/field-dark.svg new file mode 100644 index 000000000..15623061c --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/field-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/field-light.svg b/src/vs/editor/contrib/documentSymbols/media/field-light.svg new file mode 100644 index 000000000..72dd79504 --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/field-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/file-dark.svg b/src/vs/editor/contrib/documentSymbols/media/file-dark.svg new file mode 100644 index 000000000..5ed5762a1 --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/file-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/file-light.svg b/src/vs/editor/contrib/documentSymbols/media/file-light.svg new file mode 100644 index 000000000..ad54e13b1 --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/file-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/indexer-dark.svg b/src/vs/editor/contrib/documentSymbols/media/indexer-dark.svg new file mode 100644 index 000000000..e92131d3d --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/indexer-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/indexer-light.svg b/src/vs/editor/contrib/documentSymbols/media/indexer-light.svg new file mode 100644 index 000000000..207899642 --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/indexer-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/interface-dark.svg b/src/vs/editor/contrib/documentSymbols/media/interface-dark.svg new file mode 100644 index 000000000..6d482b2ab --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/interface-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/interface-light.svg b/src/vs/editor/contrib/documentSymbols/media/interface-light.svg new file mode 100644 index 000000000..a397dd00b --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/interface-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/keyword-dark.svg b/src/vs/editor/contrib/documentSymbols/media/keyword-dark.svg new file mode 100644 index 000000000..70ba6ea93 --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/keyword-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/keyword-light.svg b/src/vs/editor/contrib/documentSymbols/media/keyword-light.svg new file mode 100644 index 000000000..fc57528a3 --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/keyword-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/method-dark.svg b/src/vs/editor/contrib/documentSymbols/media/method-dark.svg new file mode 100644 index 000000000..970d7b614 --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/method-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/method-light.svg b/src/vs/editor/contrib/documentSymbols/media/method-light.svg new file mode 100644 index 000000000..403a9b90d --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/method-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/namespace-dark.svg b/src/vs/editor/contrib/documentSymbols/media/namespace-dark.svg new file mode 100644 index 000000000..9a725bb41 --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/namespace-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/namespace-light.svg b/src/vs/editor/contrib/documentSymbols/media/namespace-light.svg new file mode 100644 index 000000000..1339da7ce --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/namespace-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/numeric-dark.svg b/src/vs/editor/contrib/documentSymbols/media/numeric-dark.svg new file mode 100644 index 000000000..a1573df01 --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/numeric-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/numeric-light.svg b/src/vs/editor/contrib/documentSymbols/media/numeric-light.svg new file mode 100644 index 000000000..ea0e56e02 --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/numeric-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/operator-dark.svg b/src/vs/editor/contrib/documentSymbols/media/operator-dark.svg new file mode 100644 index 000000000..957f5f44f --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/operator-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/operator-light.svg b/src/vs/editor/contrib/documentSymbols/media/operator-light.svg new file mode 100644 index 000000000..bf6ed5799 --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/operator-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/property-dark.svg b/src/vs/editor/contrib/documentSymbols/media/property-dark.svg new file mode 100644 index 000000000..23e07ffa1 --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/property-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/property-light.svg b/src/vs/editor/contrib/documentSymbols/media/property-light.svg new file mode 100644 index 000000000..be642dd15 --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/property-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/snippet-dark.svg b/src/vs/editor/contrib/documentSymbols/media/snippet-dark.svg new file mode 100644 index 000000000..79799f98c --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/snippet-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/snippet-light.svg b/src/vs/editor/contrib/documentSymbols/media/snippet-light.svg new file mode 100644 index 000000000..45fa3a001 --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/snippet-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/string-dark.svg b/src/vs/editor/contrib/documentSymbols/media/string-dark.svg new file mode 100644 index 000000000..80fb9d656 --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/string-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/string-light.svg b/src/vs/editor/contrib/documentSymbols/media/string-light.svg new file mode 100644 index 000000000..02a0282e9 --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/string-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/structure-dark.svg b/src/vs/editor/contrib/documentSymbols/media/structure-dark.svg new file mode 100644 index 000000000..13766a5dc --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/structure-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/structure-light.svg b/src/vs/editor/contrib/documentSymbols/media/structure-light.svg new file mode 100644 index 000000000..c96bcfa61 --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/structure-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/symbol-icons.css b/src/vs/editor/contrib/documentSymbols/media/symbol-icons.css index 2a6a31185..4e312f7df 100644 --- a/src/vs/editor/contrib/documentSymbols/media/symbol-icons.css +++ b/src/vs/editor/contrib/documentSymbols/media/symbol-icons.css @@ -15,268 +15,269 @@ width: 16px; min-height: 14px; min-width: 16px; + background-position: center; } /* default icons */ .monaco-workbench .symbol-icon { - background-image: url('Field_16x.svg'); + background-image: url('field-light.svg'); background-repeat: no-repeat; } .vs-dark .monaco-workbench .symbol-icon, .hc-black .monaco-workbench .symbol-icon { - background-image: url('Field_16x_darkp.svg'); + background-image: url('field-dark.svg'); } /* constant */ .monaco-workbench .symbol-icon.constant { - background-image: url('Constant_16x.svg'); + background-image: url('constant-light.svg'); } .vs-dark .monaco-workbench .symbol-icon.constant, .hc-black .monaco-workbench .symbol-icon.constant { - background-image: url('Constant_16x_inverse.svg'); + background-image: url('constant-dark.svg'); } /* enum */ .monaco-workbench .symbol-icon.enum { - background-image: url('Enumerator_16x.svg'); + background-image: url('enumerator-light.svg'); } .vs-dark .monaco-workbench .symbol-icon.enum, .hc-black .monaco-workbench .symbol-icon.enum { - background-image: url('Enumerator_inverse_16x.svg'); + background-image: url('enumerator-dark.svg'); } /* enum-member */ .monaco-workbench .symbol-icon.enum-member { - background-image: url('EnumItem_16x.svg'); + background-image: url('enumerator-item-light.svg'); } .vs-dark .monaco-workbench .symbol-icon.enum-member, .hc-black .monaco-workbench .symbol-icon.enum-member { - background-image: url('EnumItem_inverse_16x.svg'); + background-image: url('enumerator-item-dark.svg'); } /* struct */ .monaco-workbench .symbol-icon.struct { - background-image: url('Structure_16x_vscode.svg'); + background-image: url('structure-light.svg'); } .vs-dark .monaco-workbench .symbol-icon.struct, .hc-black .monaco-workbench .symbol-icon.struct { - background-image: url('Structure_16x_vscode_inverse.svg'); + background-image: url('structure-dark.svg'); } /* event */ .monaco-workbench .symbol-icon.event { - background-image: url('Event_16x_vscode.svg'); + background-image: url('event-light.svg'); } .vs-dark .monaco-workbench .symbol-icon.event, .hc-black .monaco-workbench .symbol-icon.event { - background-image: url('Event_16x_vscode_inverse.svg'); + background-image: url('event-dark.svg'); } /* operator */ .monaco-workbench .symbol-icon.operator { - background-image: url('Operator_16x_vscode.svg'); + background-image: url('operator-light.svg'); } .vs-dark .monaco-workbench .symbol-icon.operator, .hc-black .monaco-workbench .symbol-icon.operator { - background-image: url('Operator_16x_vscode_inverse.svg'); + background-image: url('operator-dark.svg'); } /* type paramter */ .monaco-workbench .symbol-icon.type-parameter { - background-image: url('Template_16x_vscode.svg'); + background-image: url('template-light.svg'); } .vs-dark .monaco-workbench .symbol-icon.type-parameter, .hc-black .monaco-workbench .symbol-icon.type-parameter { - background-image: url('Template_16x_vscode_inverse.svg'); + background-image: url('template-dark.svg'); } /* boolean, null */ .monaco-workbench .symbol-icon.boolean { - background-image: url('BooleanData_16x.svg'); + background-image: url('boolean-light.svg'); } .vs-dark .monaco-workbench .symbol-icon.boolean, .hc-black .monaco-workbench .symbol-icon.boolean { - background-image: url('BooleanData_16x_darkp.svg'); + background-image: url('boolean-dark.svg'); } /* null */ .monaco-workbench .symbol-icon.null { - background-image: url('BooleanData_16x.svg'); + background-image: url('boolean-light.svg'); } .vs-dark .monaco-workbench .symbol-icon.null, .hc-black .monaco-workbench .symbol-icon.null { - background-image: url('BooleanData_16x_darkp.svg'); + background-image: url('boolean-dark.svg'); } /* class */ .monaco-workbench .symbol-icon.class { - background-image: url('Class_16x.svg'); + background-image: url('class-light.svg'); } .vs-dark .monaco-workbench .symbol-icon.class, .hc-black .monaco-workbench .symbol-icon.class { - background-image: url('Class_16x_darkp.svg'); + background-image: url('class-dark.svg'); } /* constructor */ .monaco-workbench .symbol-icon.constructor { - background-image: url('Method_16x.svg'); + background-image: url('method-light.svg'); } .vs-dark .monaco-workbench .symbol-icon.constructor, .hc-black .monaco-workbench .symbol-icon.constructor { - background-image: url('Method_16x_darkp.svg'); + background-image: url('method-dark.svg'); } /* file */ .monaco-workbench .symbol-icon.file { - background-image: url('Document_16x.svg'); + background-image: url('file-light.svg'); } .vs-dark .monaco-workbench .symbol-icon.file, .hc-black .monaco-workbench .symbol-icon.file { - background-image: url('Document_16x_darkp.svg'); + background-image: url('file-dark.svg'); } /* field */ .monaco-workbench .symbol-icon.field { - background-image: url('Field_16x.svg'); + background-image: url('field-light.svg'); } .vs-dark .monaco-workbench .symbol-icon.field, .hc-black .monaco-workbench .symbol-icon.field { - background-image: url('Field_16x_darkp.svg'); + background-image: url('field-dark.svg'); } /* variable */ .monaco-workbench .symbol-icon.variable { - background-image: url('LocalVariable_16x_vscode.svg'); + background-image: url('variable-light.svg'); } .vs-dark .monaco-workbench .symbol-icon.variable, .hc-black .monaco-workbench .symbol-icon.variable { - background-image: url('LocalVariable_16x_vscode_inverse.svg'); + background-image: url('variable-dark.svg'); } /* array */ .monaco-workbench .symbol-icon.array { - background-image: url('Indexer_16x.svg'); + background-image: url('indexer-light.svg'); } .vs-dark .monaco-workbench .symbol-icon.array, .hc-black .monaco-workbench .symbol-icon.array { - background-image: url('Indexer_16x_darkp.svg'); + background-image: url('indexer-dark.svg'); } /* keyword */ /* todo@joh not used? */ .monaco-workbench .symbol-icon.keyword { - background-image: url('IntelliSenseKeyword_16x.svg'); + background-image: url('keyword-light.svg'); } .vs-dark .monaco-workbench .symbol-icon.keyword, .hc-black .monaco-workbench .symbol-icon.keyword { - background-image: url('IntelliSenseKeyword_16x_darkp.svg'); + background-image: url('keyword-dark.svg'); } /* interface */ .monaco-workbench .symbol-icon.interface { - background-image: url('Interface_16x.svg'); + background-image: url('interface-light.svg'); } .vs-dark .monaco-workbench .symbol-icon.interface, .hc-black .monaco-workbench .symbol-icon.interface { - background-image: url('Interface_16x_darkp.svg'); + background-image: url('interface-dark.svg'); } /* method */ .monaco-workbench .symbol-icon.method { - background-image: url('Method_16x.svg'); + background-image: url('method-light.svg'); } .vs-dark .monaco-workbench .symbol-icon.method, .hc-black .monaco-workbench .symbol-icon.method { - background-image: url('Method_16x_darkp.svg'); + background-image: url('method-dark.svg'); } /* function */ .monaco-workbench .symbol-icon.function { - background-image: url('Method_16x.svg'); + background-image: url('method-light.svg'); } .vs-dark .monaco-workbench .symbol-icon.function, .hc-black .monaco-workbench .symbol-icon.function { - background-image: url('Method_16x_darkp.svg'); + background-image: url('method-dark.svg'); } /* object */ .monaco-workbench .symbol-icon.object { - background-image: url('Namespace_16x.svg'); + background-image: url('namespace-light.svg'); } .vs-dark .monaco-workbench .symbol-icon.object, .hc-black .monaco-workbench .symbol-icon.object { - background-image: url('Namespace_16x_darkp.svg'); + background-image: url('namespace-dark.svg'); } /* namespace */ .monaco-workbench .symbol-icon.namespace { - background-image: url('Namespace_16x.svg'); + background-image: url('namespace-light.svg'); } .vs-dark .monaco-workbench .symbol-icon.namespace, .hc-black .monaco-workbench .symbol-icon.namespace { - background-image: url('Namespace_16x_darkp.svg'); + background-image: url('namespace-dark.svg'); } /* package */ .monaco-workbench .symbol-icon.package { - background-image: url('Namespace_16x.svg'); + background-image: url('namespace-light.svg'); } .vs-dark .monaco-workbench .symbol-icon.package, .hc-black .monaco-workbench .symbol-icon.package { - background-image: url('Namespace_16x_darkp.svg'); + background-image: url('namespace-dark.svg'); } /* module */ .monaco-workbench .symbol-icon.module { - background-image: url('Namespace_16x.svg'); + background-image: url('namespace-light.svg'); } .vs-dark .monaco-workbench .symbol-icon.module, .hc-black .monaco-workbench .symbol-icon.module { - background-image: url('Namespace_16x_darkp.svg'); + background-image: url('namespace-dark.svg'); } /* number */ .monaco-workbench .symbol-icon.number { - background-image: url('Numeric_16x.svg'); + background-image: url('numeric-light.svg'); } .vs-dark .monaco-workbench .symbol-icon.number, .hc-black .monaco-workbench .symbol-icon.number { - background-image: url('Numeric_16x_darkp.svg'); + background-image: url('numeric-dark.svg'); } /* property */ .monaco-workbench .symbol-icon.property { - background-image: url('Property_16x.svg'); + background-image: url('property-light.svg'); } .vs-dark .monaco-workbench .symbol-icon.property, .hc-black .monaco-workbench .symbol-icon.property { - background-image: url('Property_16x_darkp.svg'); + background-image: url('property-dark.svg'); } /* snippet */ /* todo@joh unused? */ .monaco-workbench .symbol-icon.snippet { - background-image: url('Snippet_16x.svg'); + background-image: url('snippet-light.svg'); } .vs-dark .monaco-workbench .symbol-icon.snippet, .hc-black .monaco-workbench .symbol-icon.snippet { - background-image: url('Snippet_16x_darkp.svg'); + background-image: url('snippet-dark.svg'); } /* string */ .monaco-workbench .symbol-icon.string { - background-image: url('String_16x.svg'); + background-image: url('string-light.svg'); } .vs-dark .monaco-workbench .symbol-icon.string, .hc-black .monaco-workbench .symbol-icon.string { - background-image: url('String_16x_darkp.svg'); + background-image: url('string-dark.svg'); } /* key */ .monaco-workbench .symbol-icon.key { - background-image: url('String_16x.svg'); + background-image: url('string-light.svg'); } .vs-dark .monaco-workbench .symbol-icon.key, .hc-black .monaco-workbench .symbol-icon.key { - background-image: url('String_16x_darkp.svg'); + background-image: url('string-dark.svg'); } diff --git a/src/vs/editor/contrib/documentSymbols/media/template-dark.svg b/src/vs/editor/contrib/documentSymbols/media/template-dark.svg new file mode 100644 index 000000000..425ced36f --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/template-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/template-light.svg b/src/vs/editor/contrib/documentSymbols/media/template-light.svg new file mode 100644 index 000000000..496d8f7c8 --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/template-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/variable-dark.svg b/src/vs/editor/contrib/documentSymbols/media/variable-dark.svg new file mode 100644 index 000000000..687fcabff --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/variable-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/media/variable-light.svg b/src/vs/editor/contrib/documentSymbols/media/variable-light.svg new file mode 100644 index 000000000..ede7e9434 --- /dev/null +++ b/src/vs/editor/contrib/documentSymbols/media/variable-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/documentSymbols/outlineTree.ts b/src/vs/editor/contrib/documentSymbols/outlineTree.ts index 926d6a3da..a77c8d1bd 100644 --- a/src/vs/editor/contrib/documentSymbols/outlineTree.ts +++ b/src/vs/editor/contrib/documentSymbols/outlineTree.ts @@ -13,22 +13,20 @@ import 'vs/css!./media/outlineTree'; import 'vs/css!./media/symbol-icons'; import { Range } from 'vs/editor/common/core/range'; import { SymbolKind, symbolKindToCssClass } from 'vs/editor/common/modes'; -import { OutlineElement, OutlineGroup, OutlineModel, TreeElement } from 'vs/editor/contrib/documentSymbols/outlineModel'; +import { OutlineElement, OutlineGroup, OutlineModel } from 'vs/editor/contrib/documentSymbols/outlineModel'; import { localize } from 'vs/nls'; -import { IKeybindingService, IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding'; import { IconLabel } from 'vs/base/browser/ui/iconLabel/iconLabel'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { OutlineConfigKeys } from 'vs/editor/contrib/documentSymbols/outline'; import { MarkerSeverity } from 'vs/platform/markers/common/markers'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { listErrorForeground, listWarningForeground } from 'vs/platform/theme/common/colorRegistry'; +import { IdleValue } from 'vs/base/common/async'; export type OutlineItem = OutlineGroup | OutlineElement; export class OutlineNavigationLabelProvider implements IKeyboardNavigationLabelProvider { - constructor(@IKeybindingService private readonly _keybindingService: IKeybindingService) { } - getKeyboardNavigationLabel(element: OutlineItem): { toString(): string; } { if (element instanceof OutlineGroup) { return element.provider.displayName || element.id; @@ -36,15 +34,11 @@ export class OutlineNavigationLabelProvider implements IKeyboardNavigationLabelP return element.symbol.name; } } - - mightProducePrintableCharacter(event: IKeyboardEvent): boolean { - return this._keybindingService.mightProducePrintableCharacter(event); - } } export class OutlineIdentityProvider implements IIdentityProvider { - getId(element: TreeElement): { toString(): string; } { + getId(element: OutlineItem): { toString(): string; } { return element.id; } } @@ -215,6 +209,8 @@ export const enum OutlineSortOrder { export class OutlineItemComparator implements ITreeSorter { + private readonly _collator = new IdleValue(() => new Intl.Collator(undefined, { numeric: true })); + constructor( public type: OutlineSortOrder = OutlineSortOrder.ByPosition ) { } @@ -225,11 +221,11 @@ export class OutlineItemComparator implements ITreeSorter { } else if (a instanceof OutlineElement && b instanceof OutlineElement) { if (this.type === OutlineSortOrder.ByKind) { - return a.symbol.kind - b.symbol.kind || a.symbol.name.localeCompare(b.symbol.name); + return a.symbol.kind - b.symbol.kind || this._collator.getValue().compare(a.symbol.name, b.symbol.name); } else if (this.type === OutlineSortOrder.ByName) { - return a.symbol.name.localeCompare(b.symbol.name) || Range.compareRangesUsingStarts(a.symbol.range, b.symbol.range); + return this._collator.getValue().compare(a.symbol.name, b.symbol.name) || Range.compareRangesUsingStarts(a.symbol.range, b.symbol.range); } else if (this.type === OutlineSortOrder.ByPosition) { - return Range.compareRangesUsingStarts(a.symbol.range, b.symbol.range) || a.symbol.name.localeCompare(b.symbol.name); + return Range.compareRangesUsingStarts(a.symbol.range, b.symbol.range) || this._collator.getValue().compare(a.symbol.name, b.symbol.name); } } return 0; diff --git a/src/vs/editor/contrib/find/findController.ts b/src/vs/editor/contrib/find/findController.ts index d51962cdf..739cde26f 100644 --- a/src/vs/editor/contrib/find/findController.ts +++ b/src/vs/editor/contrib/find/findController.ts @@ -112,7 +112,8 @@ export class CommonFindController extends Disposable implements editorCommon.IEd searchScope: null, matchCase: this._storageService.getBoolean('editor.matchCase', StorageScope.WORKSPACE, false), wholeWord: this._storageService.getBoolean('editor.wholeWord', StorageScope.WORKSPACE, false), - isRegex: this._storageService.getBoolean('editor.isRegex', StorageScope.WORKSPACE, false) + isRegex: this._storageService.getBoolean('editor.isRegex', StorageScope.WORKSPACE, false), + preserveCase: this._storageService.getBoolean('editor.preserveCase', StorageScope.WORKSPACE, false) }, false); if (shouldRestartFind) { @@ -170,13 +171,17 @@ export class CommonFindController extends Disposable implements editorCommon.IEd if (e.matchCase) { this._storageService.store('editor.matchCase', this._state.actualMatchCase, StorageScope.WORKSPACE); } + if (e.preserveCase) { + this._storageService.store('editor.preserveCase', this._state.actualPreserveCase, StorageScope.WORKSPACE); + } } private loadQueryState() { this._state.change({ matchCase: this._storageService.getBoolean('editor.matchCase', StorageScope.WORKSPACE, this._state.matchCase), wholeWord: this._storageService.getBoolean('editor.wholeWord', StorageScope.WORKSPACE, this._state.wholeWord), - isRegex: this._storageService.getBoolean('editor.isRegex', StorageScope.WORKSPACE, this._state.isRegex) + isRegex: this._storageService.getBoolean('editor.isRegex', StorageScope.WORKSPACE, this._state.isRegex), + preserveCase: this._storageService.getBoolean('editor.preserveCase', StorageScope.WORKSPACE, this._state.preserveCase) }, false); } @@ -217,6 +222,11 @@ export class CommonFindController extends Disposable implements editorCommon.IEd } } + public togglePreserveCase(): void { + this._state.change({ preserveCase: !this._state.preserveCase }, false); + this.highlightFindOptions(); + } + public toggleSearchScope(): void { if (this._state.searchScope) { this._state.change({ searchScope: null }, true); @@ -422,7 +432,7 @@ export class StartFindAction extends EditorAction { id: FIND_IDS.StartFindAction, label: nls.localize('startFindAction', "Find"), alias: 'Find', - precondition: null, + precondition: undefined, kbOpts: { kbExpr: null, primary: KeyMod.CtrlCmd | KeyCode.KEY_F, @@ -459,7 +469,7 @@ export class StartFindWithSelectionAction extends EditorAction { id: FIND_IDS.StartFindWithSelection, label: nls.localize('startFindWithSelectionAction', "Find With Selection"), alias: 'Find With Selection', - precondition: null, + precondition: undefined, kbOpts: { kbExpr: null, primary: 0, @@ -513,7 +523,7 @@ export class NextMatchFindAction extends MatchFindAction { id: FIND_IDS.NextMatchFindAction, label: nls.localize('findNextMatchAction', "Find Next"), alias: 'Find Next', - precondition: null, + precondition: undefined, kbOpts: { kbExpr: EditorContextKeys.focus, primary: KeyCode.F3, @@ -535,7 +545,7 @@ export class PreviousMatchFindAction extends MatchFindAction { id: FIND_IDS.PreviousMatchFindAction, label: nls.localize('findPreviousMatchAction', "Find Previous"), alias: 'Find Previous', - precondition: null, + precondition: undefined, kbOpts: { kbExpr: EditorContextKeys.focus, primary: KeyMod.Shift | KeyCode.F3, @@ -583,7 +593,7 @@ export class NextSelectionMatchFindAction extends SelectionMatchFindAction { id: FIND_IDS.NextSelectionMatchFindAction, label: nls.localize('nextSelectionMatchFindAction', "Find Next Selection"), alias: 'Find Next Selection', - precondition: null, + precondition: undefined, kbOpts: { kbExpr: EditorContextKeys.focus, primary: KeyMod.CtrlCmd | KeyCode.F3, @@ -604,7 +614,7 @@ export class PreviousSelectionMatchFindAction extends SelectionMatchFindAction { id: FIND_IDS.PreviousSelectionMatchFindAction, label: nls.localize('previousSelectionMatchFindAction', "Find Previous Selection"), alias: 'Find Previous Selection', - precondition: null, + precondition: undefined, kbOpts: { kbExpr: EditorContextKeys.focus, primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.F3, @@ -625,7 +635,7 @@ export class StartFindReplaceAction extends EditorAction { id: FIND_IDS.StartFindReplaceAction, label: nls.localize('startReplace', "Replace"), alias: 'Replace', - precondition: null, + precondition: undefined, kbOpts: { kbExpr: null, primary: KeyMod.CtrlCmd | KeyCode.KEY_H, @@ -704,7 +714,7 @@ registerEditorCommand(new FindCommand({ registerEditorCommand(new FindCommand({ id: FIND_IDS.ToggleCaseSensitiveCommand, - precondition: null, + precondition: undefined, handler: x => x.toggleCaseSensitive(), kbOpts: { weight: KeybindingWeight.EditorContrib + 5, @@ -718,7 +728,7 @@ registerEditorCommand(new FindCommand({ registerEditorCommand(new FindCommand({ id: FIND_IDS.ToggleWholeWordCommand, - precondition: null, + precondition: undefined, handler: x => x.toggleWholeWords(), kbOpts: { weight: KeybindingWeight.EditorContrib + 5, @@ -732,7 +742,7 @@ registerEditorCommand(new FindCommand({ registerEditorCommand(new FindCommand({ id: FIND_IDS.ToggleRegexCommand, - precondition: null, + precondition: undefined, handler: x => x.toggleRegex(), kbOpts: { weight: KeybindingWeight.EditorContrib + 5, @@ -746,7 +756,7 @@ registerEditorCommand(new FindCommand({ registerEditorCommand(new FindCommand({ id: FIND_IDS.ToggleSearchScopeCommand, - precondition: null, + precondition: undefined, handler: x => x.toggleSearchScope(), kbOpts: { weight: KeybindingWeight.EditorContrib + 5, diff --git a/src/vs/editor/contrib/find/findDecorations.ts b/src/vs/editor/contrib/find/findDecorations.ts index bb1159773..ee93bccc3 100644 --- a/src/vs/editor/contrib/find/findDecorations.ts +++ b/src/vs/editor/contrib/find/findDecorations.ts @@ -7,9 +7,9 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import { IActiveCodeEditor } from 'vs/editor/browser/editorBrowser'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; -import { FindMatch, IModelDecorationsChangeAccessor, IModelDeltaDecoration, OverviewRulerLane, TrackedRangeStickiness } from 'vs/editor/common/model'; +import { FindMatch, IModelDecorationsChangeAccessor, IModelDeltaDecoration, OverviewRulerLane, TrackedRangeStickiness, MinimapPosition } from 'vs/editor/common/model'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; -import { overviewRulerFindMatchForeground } from 'vs/platform/theme/common/colorRegistry'; +import { overviewRulerFindMatchForeground, minimapFindMatch } from 'vs/platform/theme/common/colorRegistry'; import { themeColorFromId } from 'vs/platform/theme/common/themeService'; export class FindDecorations implements IDisposable { @@ -269,6 +269,10 @@ export class FindDecorations implements IDisposable { overviewRuler: { color: themeColorFromId(overviewRulerFindMatchForeground), position: OverviewRulerLane.Center + }, + minimap: { + color: themeColorFromId(minimapFindMatch), + position: MinimapPosition.Inline } }); @@ -279,6 +283,10 @@ export class FindDecorations implements IDisposable { overviewRuler: { color: themeColorFromId(overviewRulerFindMatchForeground), position: OverviewRulerLane.Center + }, + minimap: { + color: themeColorFromId(minimapFindMatch), + position: MinimapPosition.Inline } }); diff --git a/src/vs/editor/contrib/find/findModel.ts b/src/vs/editor/contrib/find/findModel.ts index 9264aa9b7..faca23f0a 100644 --- a/src/vs/editor/contrib/find/findModel.ts +++ b/src/vs/editor/contrib/find/findModel.ts @@ -5,7 +5,7 @@ import { RunOnceScheduler, TimeoutTimer } from 'vs/base/common/async'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { dispose, DisposableStore } from 'vs/base/common/lifecycle'; import { IActiveCodeEditor } from 'vs/editor/browser/editorBrowser'; import { ReplaceCommand, ReplaceCommandThatPreservesSelection } from 'vs/editor/common/commands/replaceCommand'; import { CursorChangeReason, ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; @@ -59,6 +59,7 @@ export const FIND_IDS = { ToggleWholeWordCommand: 'toggleFindWholeWord', ToggleRegexCommand: 'toggleFindRegex', ToggleSearchScopeCommand: 'toggleFindInSelection', + TogglePreserveCaseCommand: 'togglePreserveCase', ReplaceOneAction: 'editor.action.replaceOne', ReplaceAllAction: 'editor.action.replaceAll', SelectAllMatchesAction: 'editor.action.selectAllMatches' @@ -71,7 +72,7 @@ export class FindModelBoundToEditorModel { private readonly _editor: IActiveCodeEditor; private readonly _state: FindReplaceState; - private _toDispose: IDisposable[]; + private readonly _toDispose = new DisposableStore(); private readonly _decorations: FindDecorations; private _ignoreModelContentChanged: boolean; private readonly _startSearchingTimer: TimeoutTimer; @@ -82,17 +83,16 @@ export class FindModelBoundToEditorModel { constructor(editor: IActiveCodeEditor, state: FindReplaceState) { this._editor = editor; this._state = state; - this._toDispose = []; this._isDisposed = false; this._startSearchingTimer = new TimeoutTimer(); this._decorations = new FindDecorations(editor); - this._toDispose.push(this._decorations); + this._toDispose.add(this._decorations); this._updateDecorationsScheduler = new RunOnceScheduler(() => this.research(false), 100); - this._toDispose.push(this._updateDecorationsScheduler); + this._toDispose.add(this._updateDecorationsScheduler); - this._toDispose.push(this._editor.onDidChangeCursorPosition((e: ICursorPositionChangedEvent) => { + this._toDispose.add(this._editor.onDidChangeCursorPosition((e: ICursorPositionChangedEvent) => { if ( e.reason === CursorChangeReason.Explicit || e.reason === CursorChangeReason.Undo @@ -103,7 +103,7 @@ export class FindModelBoundToEditorModel { })); this._ignoreModelContentChanged = false; - this._toDispose.push(this._editor.onDidChangeModelContent((e) => { + this._toDispose.add(this._editor.onDidChangeModelContent((e) => { if (this._ignoreModelContentChanged) { return; } @@ -115,7 +115,7 @@ export class FindModelBoundToEditorModel { this._updateDecorationsScheduler.schedule(); })); - this._toDispose.push(this._state.onFindReplaceStateChange((e) => this._onStateChanged(e))); + this._toDispose.add(this._state.onFindReplaceStateChange((e) => this._onStateChanged(e))); this.research(false, this._state.searchScope); } @@ -123,7 +123,7 @@ export class FindModelBoundToEditorModel { public dispose(): void { this._isDisposed = true; dispose(this._startSearchingTimer); - this._toDispose = dispose(this._toDispose); + this._toDispose.dispose(); } private _onStateChanged(e: FindReplaceStateChangedEvent): void { @@ -417,11 +417,11 @@ export class FindModelBoundToEditorModel { let replacePattern = this._getReplacePattern(); let selection = this._editor.getSelection(); - let nextMatch = this._getNextMatch(selection.getStartPosition(), replacePattern.hasReplacementPatterns, false); + let nextMatch = this._getNextMatch(selection.getStartPosition(), true, false); if (nextMatch) { if (selection.equalsRange(nextMatch.range)) { // selection sits on a find match => replace it! - let replaceString = replacePattern.buildReplaceString(nextMatch.matches); + let replaceString = replacePattern.buildReplaceString(nextMatch.matches, this._state.preserveCase); let command = new ReplaceCommand(selection, replaceString); @@ -483,12 +483,14 @@ export class FindModelBoundToEditorModel { const replacePattern = this._getReplacePattern(); let resultText: string; - if (replacePattern.hasReplacementPatterns) { + const preserveCase = this._state.preserveCase; + + if (replacePattern.hasReplacementPatterns || preserveCase) { resultText = modelText.replace(searchRegex, function () { - return replacePattern.buildReplaceString(arguments); + return replacePattern.buildReplaceString(arguments, preserveCase); }); } else { - resultText = modelText.replace(searchRegex, replacePattern.buildReplaceString(null)); + resultText = modelText.replace(searchRegex, replacePattern.buildReplaceString(null, preserveCase)); } let command = new ReplaceCommandThatPreservesSelection(fullModelRange, resultText, this._editor.getSelection()); @@ -498,11 +500,11 @@ export class FindModelBoundToEditorModel { private _regularReplaceAll(findScope: Range | null): void { const replacePattern = this._getReplacePattern(); // Get all the ranges (even more than the highlighted ones) - let matches = this._findMatches(findScope, replacePattern.hasReplacementPatterns, Constants.MAX_SAFE_SMALL_INTEGER); + let matches = this._findMatches(findScope, replacePattern.hasReplacementPatterns || this._state.preserveCase, Constants.MAX_SAFE_SMALL_INTEGER); let replaceStrings: string[] = []; for (let i = 0, len = matches.length; i < len; i++) { - replaceStrings[i] = replacePattern.buildReplaceString(matches[i].matches); + replaceStrings[i] = replacePattern.buildReplaceString(matches[i].matches, this._state.preserveCase); } let command = new ReplaceAllCommand(this._editor.getSelection(), matches.map(m => m.range), replaceStrings); diff --git a/src/vs/editor/contrib/find/findOptionsWidget.ts b/src/vs/editor/contrib/find/findOptionsWidget.ts index 8a61aabd7..76fe78b42 100644 --- a/src/vs/editor/contrib/find/findOptionsWidget.ts +++ b/src/vs/editor/contrib/find/findOptionsWidget.ts @@ -11,7 +11,7 @@ import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, OverlayWidgetPosit import { FIND_IDS } from 'vs/editor/contrib/find/findModel'; import { FindReplaceState } from 'vs/editor/contrib/find/findState'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { contrastBorder, editorWidgetBackground, inputActiveOptionBorder, widgetShadow } from 'vs/platform/theme/common/colorRegistry'; +import { contrastBorder, editorWidgetBackground, inputActiveOptionBorder, inputActiveOptionBackground, widgetShadow } from 'vs/platform/theme/common/colorRegistry'; import { ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; export class FindOptionsWidget extends Widget implements IOverlayWidget { @@ -47,11 +47,13 @@ export class FindOptionsWidget extends Widget implements IOverlayWidget { this._domNode.setAttribute('aria-hidden', 'true'); const inputActiveOptionBorderColor = themeService.getTheme().getColor(inputActiveOptionBorder); + const inputActiveOptionBackgroundColor = themeService.getTheme().getColor(inputActiveOptionBackground); this.caseSensitive = this._register(new CaseSensitiveCheckbox({ appendTitle: this._keybindingLabelFor(FIND_IDS.ToggleCaseSensitiveCommand), isChecked: this._state.matchCase, - inputActiveOptionBorder: inputActiveOptionBorderColor + inputActiveOptionBorder: inputActiveOptionBorderColor, + inputActiveOptionBackground: inputActiveOptionBackgroundColor })); this._domNode.appendChild(this.caseSensitive.domNode); this._register(this.caseSensitive.onChange(() => { @@ -63,7 +65,8 @@ export class FindOptionsWidget extends Widget implements IOverlayWidget { this.wholeWords = this._register(new WholeWordsCheckbox({ appendTitle: this._keybindingLabelFor(FIND_IDS.ToggleWholeWordCommand), isChecked: this._state.wholeWord, - inputActiveOptionBorder: inputActiveOptionBorderColor + inputActiveOptionBorder: inputActiveOptionBorderColor, + inputActiveOptionBackground: inputActiveOptionBackgroundColor })); this._domNode.appendChild(this.wholeWords.domNode); this._register(this.wholeWords.onChange(() => { @@ -75,7 +78,8 @@ export class FindOptionsWidget extends Widget implements IOverlayWidget { this.regex = this._register(new RegexCheckbox({ appendTitle: this._keybindingLabelFor(FIND_IDS.ToggleRegexCommand), isChecked: this._state.isRegex, - inputActiveOptionBorder: inputActiveOptionBorderColor + inputActiveOptionBorder: inputActiveOptionBorderColor, + inputActiveOptionBackground: inputActiveOptionBackgroundColor })); this._domNode.appendChild(this.regex.domNode); this._register(this.regex.onChange(() => { @@ -179,7 +183,10 @@ export class FindOptionsWidget extends Widget implements IOverlayWidget { } private _applyTheme(theme: ITheme) { - let inputStyles = { inputActiveOptionBorder: theme.getColor(inputActiveOptionBorder) }; + let inputStyles = { + inputActiveOptionBorder: theme.getColor(inputActiveOptionBorder), + inputActiveOptionBackground: theme.getColor(inputActiveOptionBackground) + }; this.caseSensitive.style(inputStyles); this.wholeWords.style(inputStyles); this.regex.style(inputStyles); diff --git a/src/vs/editor/contrib/find/findState.ts b/src/vs/editor/contrib/find/findState.ts index 0af1b84cd..777e27314 100644 --- a/src/vs/editor/contrib/find/findState.ts +++ b/src/vs/editor/contrib/find/findState.ts @@ -18,6 +18,7 @@ export interface FindReplaceStateChangedEvent { isRegex: boolean; wholeWord: boolean; matchCase: boolean; + preserveCase: boolean; searchScope: boolean; matchesPosition: boolean; matchesCount: boolean; @@ -41,6 +42,8 @@ export interface INewFindReplaceState { wholeWordOverride?: FindOptionOverride; matchCase?: boolean; matchCaseOverride?: FindOptionOverride; + preserveCase?: boolean; + preserveCaseOverride?: FindOptionOverride; searchScope?: Range | null; } @@ -65,11 +68,13 @@ export class FindReplaceState implements IDisposable { private _wholeWordOverride: FindOptionOverride; private _matchCase: boolean; private _matchCaseOverride: FindOptionOverride; + private _preserveCase: boolean; + private _preserveCaseOverride: FindOptionOverride; private _searchScope: Range | null; private _matchesPosition: number; private _matchesCount: number; private _currentMatch: Range | null; - private readonly _onFindReplaceStateChange: Emitter; + private readonly _onFindReplaceStateChange = new Emitter(); public get searchString(): string { return this._searchString; } public get replaceString(): string { return this._replaceString; } @@ -78,16 +83,18 @@ export class FindReplaceState implements IDisposable { public get isRegex(): boolean { return effectiveOptionValue(this._isRegexOverride, this._isRegex); } public get wholeWord(): boolean { return effectiveOptionValue(this._wholeWordOverride, this._wholeWord); } public get matchCase(): boolean { return effectiveOptionValue(this._matchCaseOverride, this._matchCase); } + public get preserveCase(): boolean { return effectiveOptionValue(this._preserveCaseOverride, this._preserveCase); } public get actualIsRegex(): boolean { return this._isRegex; } public get actualWholeWord(): boolean { return this._wholeWord; } public get actualMatchCase(): boolean { return this._matchCase; } + public get actualPreserveCase(): boolean { return this._preserveCase; } public get searchScope(): Range | null { return this._searchScope; } public get matchesPosition(): number { return this._matchesPosition; } public get matchesCount(): number { return this._matchesCount; } public get currentMatch(): Range | null { return this._currentMatch; } - public get onFindReplaceStateChange(): Event { return this._onFindReplaceStateChange.event; } + public readonly onFindReplaceStateChange: Event = this._onFindReplaceStateChange.event; constructor() { this._searchString = ''; @@ -100,11 +107,12 @@ export class FindReplaceState implements IDisposable { this._wholeWordOverride = FindOptionOverride.NotSet; this._matchCase = false; this._matchCaseOverride = FindOptionOverride.NotSet; + this._preserveCase = false; + this._preserveCaseOverride = FindOptionOverride.NotSet; this._searchScope = null; this._matchesPosition = 0; this._matchesCount = 0; this._currentMatch = null; - this._onFindReplaceStateChange = new Emitter(); } public dispose(): void { @@ -121,6 +129,7 @@ export class FindReplaceState implements IDisposable { isRegex: false, wholeWord: false, matchCase: false, + preserveCase: false, searchScope: false, matchesPosition: false, matchesCount: false, @@ -170,6 +179,7 @@ export class FindReplaceState implements IDisposable { isRegex: false, wholeWord: false, matchCase: false, + preserveCase: false, searchScope: false, matchesPosition: false, matchesCount: false, @@ -180,6 +190,7 @@ export class FindReplaceState implements IDisposable { const oldEffectiveIsRegex = this.isRegex; const oldEffectiveWholeWords = this.wholeWord; const oldEffectiveMatchCase = this.matchCase; + const oldEffectivePreserveCase = this.preserveCase; if (typeof newState.searchString !== 'undefined') { if (this._searchString !== newState.searchString) { @@ -218,6 +229,9 @@ export class FindReplaceState implements IDisposable { if (typeof newState.matchCase !== 'undefined') { this._matchCase = newState.matchCase; } + if (typeof newState.preserveCase !== 'undefined') { + this._preserveCase = newState.preserveCase; + } if (typeof newState.searchScope !== 'undefined') { if (!Range.equalsRange(this._searchScope, newState.searchScope)) { this._searchScope = newState.searchScope; @@ -230,6 +244,7 @@ export class FindReplaceState implements IDisposable { this._isRegexOverride = (typeof newState.isRegexOverride !== 'undefined' ? newState.isRegexOverride : FindOptionOverride.NotSet); this._wholeWordOverride = (typeof newState.wholeWordOverride !== 'undefined' ? newState.wholeWordOverride : FindOptionOverride.NotSet); this._matchCaseOverride = (typeof newState.matchCaseOverride !== 'undefined' ? newState.matchCaseOverride : FindOptionOverride.NotSet); + this._preserveCaseOverride = (typeof newState.preserveCaseOverride !== 'undefined' ? newState.preserveCaseOverride : FindOptionOverride.NotSet); if (oldEffectiveIsRegex !== this.isRegex) { somethingChanged = true; @@ -244,6 +259,11 @@ export class FindReplaceState implements IDisposable { changeEvent.matchCase = true; } + if (oldEffectivePreserveCase !== this.preserveCase) { + somethingChanged = true; + changeEvent.preserveCase = true; + } + if (somethingChanged) { this._onFindReplaceStateChange.fire(changeEvent); } diff --git a/src/vs/editor/contrib/find/findWidget.css b/src/vs/editor/contrib/find/findWidget.css index b6fbab874..7e1140442 100644 --- a/src/vs/editor/contrib/find/findWidget.css +++ b/src/vs/editor/contrib/find/findWidget.css @@ -39,6 +39,11 @@ transition: top 200ms linear; padding: 0 4px; } + +.monaco-editor .find-widget.hiddenEditor { + display: none; +} + /* Find widget when replace is toggled on */ .monaco-editor .find-widget.replaceToggled { top: -74px; /* find input height + replace input height + shadow (10px) */ @@ -79,6 +84,15 @@ height: 25px; } +.monaco-editor .find-widget > .find-part .monaco-inputbox > .wrapper > .input { + width: 100% !important; + padding-right: 66px; +} + +.monaco-editor .find-widget > .replace-part .monaco-inputbox > .wrapper > .input { + padding-right: 22px; +} + .monaco-editor .find-widget > .find-part .monaco-inputbox > .wrapper > .input, .monaco-editor .find-widget > .replace-part .monaco-inputbox > .wrapper > .input { padding-top: 2px; @@ -96,8 +110,8 @@ display: flex; display: -webkit-flex; flex: initial; - margin: 0 1px 0 3px; - padding: 2px 2px 0 2px; + margin: 0 0 0 3px; + padding: 2px 0 0 2px; height: 25px; vertical-align: middle; box-sizing: border-box; @@ -151,11 +165,11 @@ } .monaco-editor .find-widget .previous { - background-image: url('images/previous.svg'); + background-image: url('images/chevron-previous-light.svg'); } .monaco-editor .find-widget .next { - background-image: url('images/next.svg'); + background-image: url('images/chevron-next-light.svg'); } .monaco-editor .find-widget .disabled { @@ -175,8 +189,8 @@ content: ''; display: inline-block; background-repeat: no-repeat; - background-position: 0 0; - background-image: url('images/cancelSelectionFind.svg'); + background-position: center; + background-image: url('images/find-selection-light.svg'); width: 20px; height: 20px; border: none; @@ -200,23 +214,23 @@ } .monaco-editor .find-widget .close-fw { - background-image: url('images/close.svg'); + background-image: url('images/close-light.svg'); } .monaco-editor .find-widget .expand { - background-image: url('images/expando-expanded.svg'); + background-image: url('images/tree-expanded-light.svg'); } .monaco-editor .find-widget .collapse { - background-image: url('images/expando-collapsed.svg'); + background-image: url('images/tree-collapsed-light.svg'); } .monaco-editor .find-widget .replace { - background-image: url('images/replace.svg'); + background-image: url('images/replace-light.svg'); } .monaco-editor .find-widget .replace-all { - background-image: url('images/replace-all.svg'); + background-image: url('images/replace-all-light.svg'); } .monaco-editor .find-widget > .replace-part { @@ -224,12 +238,19 @@ } .monaco-editor .find-widget > .replace-part > .replace-input { + position: relative; display: flex; display: -webkit-flex; vertical-align: middle; width: auto !important; } +.monaco-editor .find-widget > .replace-part > .replace-input > .controls { + position: absolute; + top: 3px; + right: 2px; +} + /* REDUCED */ .monaco-editor .find-widget.reduced-find-widget .matchesCount, .monaco-editor .find-widget.reduced-find-widget .monaco-checkbox { @@ -272,27 +293,23 @@ .monaco-editor.hc-black .find-widget .previous, .monaco-editor.vs-dark .find-widget .previous { - background-image: url('images/previous-inverse.svg'); + background-image: url('images/chevron-previous-dark.svg'); } .monaco-editor.hc-black .find-widget .next, .monaco-editor.vs-dark .find-widget .next { - background-image: url('images/next-inverse.svg'); + background-image: url('images/chevron-next-dark.svg'); } .monaco-editor.hc-black .find-widget .monaco-checkbox .label, .monaco-editor.vs-dark .find-widget .monaco-checkbox .label { - background-image: url('images/cancelSelectionFind-inverse.svg'); + background-image: url('images/find-selection-dark.svg'); } .monaco-editor.vs-dark .find-widget .monaco-checkbox .checkbox:not(:disabled):hover:before + .label { background-color: rgba(255, 255, 255, 0.1); } -.monaco-editor.vs-dark .find-widget .monaco-checkbox .checkbox:checked + .label { - background-color: rgba(255, 255, 255, 0.1); -} - .monaco-editor.hc-black .find-widget .close-fw, .monaco-editor.vs-dark .find-widget .close-fw { background-image: url('images/close-dark.svg'); @@ -300,22 +317,22 @@ .monaco-editor.hc-black .find-widget .replace, .monaco-editor.vs-dark .find-widget .replace { - background-image: url('images/replace-inverse.svg'); + background-image: url('images/replace-dark.svg'); } .monaco-editor.hc-black .find-widget .replace-all, .monaco-editor.vs-dark .find-widget .replace-all { - background-image: url('images/replace-all-inverse.svg'); + background-image: url('images/replace-all-dark.svg'); } .monaco-editor.hc-black .find-widget .expand, .monaco-editor.vs-dark .find-widget .expand { - background-image: url('images/expando-expanded-dark.svg'); + background-image: url('images/tree-expanded-dark.svg'); } .monaco-editor.hc-black .find-widget .collapse, .monaco-editor.vs-dark .find-widget .collapse { - background-image: url('images/expando-collapsed-dark.svg'); + background-image: url('images/tree-collapsed-dark.svg'); } .monaco-editor.hc-black .find-widget .button:not(.disabled):hover, diff --git a/src/vs/editor/contrib/find/findWidget.ts b/src/vs/editor/contrib/find/findWidget.ts index 2fba7cf35..84528f398 100644 --- a/src/vs/editor/contrib/find/findWidget.ts +++ b/src/vs/editor/contrib/find/findWidget.ts @@ -13,6 +13,7 @@ import { FindInput, IFindInputStyles } from 'vs/base/browser/ui/findinput/findIn import { HistoryInputBox, IMessage as InputBoxMessage } from 'vs/base/browser/ui/inputbox/inputBox'; import { IHorizontalSashLayoutProvider, ISashEvent, Orientation, Sash } from 'vs/base/browser/ui/sash/sash'; import { Widget } from 'vs/base/browser/ui/widget'; +import { Checkbox } from 'vs/base/browser/ui/checkbox/checkbox'; import { Delayer } from 'vs/base/common/async'; import { Color } from 'vs/base/common/color'; import { onUnexpectedError } from 'vs/base/common/errors'; @@ -27,10 +28,11 @@ import { CONTEXT_FIND_INPUT_FOCUSED, CONTEXT_REPLACE_INPUT_FOCUSED, FIND_IDS, MA import { FindReplaceState, FindReplaceStateChangedEvent } from 'vs/editor/contrib/find/findState'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { contrastBorder, editorFindMatch, editorFindMatchBorder, editorFindMatchHighlight, editorFindMatchHighlightBorder, editorFindRangeHighlight, editorFindRangeHighlightBorder, editorWidgetBackground, editorWidgetBorder, editorWidgetResizeBorder, errorForeground, inputActiveOptionBorder, inputBackground, inputBorder, inputForeground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, inputValidationInfoBackground, inputValidationInfoBorder, inputValidationInfoForeground, inputValidationWarningBackground, inputValidationWarningBorder, inputValidationWarningForeground, widgetShadow } from 'vs/platform/theme/common/colorRegistry'; +import { contrastBorder, editorFindMatch, editorFindMatchBorder, editorFindMatchHighlight, editorFindMatchHighlightBorder, editorFindRangeHighlight, editorFindRangeHighlightBorder, editorWidgetBackground, editorWidgetBorder, editorWidgetResizeBorder, errorForeground, inputActiveOptionBorder, inputActiveOptionBackground, inputBackground, inputBorder, inputForeground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, inputValidationInfoBackground, inputValidationInfoBorder, inputValidationInfoForeground, inputValidationWarningBackground, inputValidationWarningBorder, inputValidationWarningForeground, widgetShadow, editorWidgetForeground } from 'vs/platform/theme/common/colorRegistry'; import { ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { ContextScopedFindInput, ContextScopedHistoryInputBox } from 'vs/platform/browser/contextScopedHistoryWidget'; import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; +import { alert as alertFn } from 'vs/base/browser/ui/aria/aria'; export interface IFindController { replace(): void; @@ -46,6 +48,7 @@ const NLS_TOGGLE_SELECTION_FIND_TITLE = nls.localize('label.toggleSelectionFind' const NLS_CLOSE_BTN_LABEL = nls.localize('label.closeButton', "Close"); const NLS_REPLACE_INPUT_LABEL = nls.localize('label.replace', "Replace"); const NLS_REPLACE_INPUT_PLACEHOLDER = nls.localize('placeholder.replace', "Replace"); +const NLS_PRESERVE_CASE_LABEL = nls.localize('label.preserveCaseCheckbox', "Preserve Case"); const NLS_REPLACE_BTN_LABEL = nls.localize('label.replaceButton', "Replace"); const NLS_REPLACE_ALL_BTN_LABEL = nls.localize('label.replaceAllButton', "Replace All"); const NLS_TOGGLE_REPLACE_MODE_BTN_LABEL = nls.localize('label.toggleReplaceButton', "Toggle Replace mode"); @@ -100,6 +103,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas private _nextBtn: SimpleButton; private _toggleSelectionFind: SimpleCheckbox; private _closeBtn: SimpleButton; + private _preserveCase: Checkbox; private _replaceBtn: SimpleButton; private _replaceAllBtn: SimpleButton; @@ -372,13 +376,26 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas } else { label = NLS_NO_RESULTS; } + this._matchesCount.appendChild(document.createTextNode(label)); + alertFn(this._getAriaLabel(label, this._state.currentMatch, this._state.searchString), true); MAX_MATCHES_COUNT_WIDTH = Math.max(MAX_MATCHES_COUNT_WIDTH, this._matchesCount.clientWidth); } // ----- actions + private _getAriaLabel(label: string, currentMatch: Range | null, searchString: string): string { + if (label === NLS_NO_RESULTS) { + return searchString === '' + ? nls.localize('ariaSearchNoResultEmpty', "{0} found", label) + : nls.localize('ariaSearchNoResult', "{0} found for {1}", label, searchString); + } + return currentMatch + ? nls.localize('ariaSearchNoResultWithLineNum', "{0} found for {1} at {2}", label, searchString, currentMatch.startLineNumber + ':' + currentMatch.startColumn) + : nls.localize('ariaSearchNoResultWithLineNumNoCurrentMatch', "{0} found for {1}", label, searchString); + } + /** * If 'selection find' is ON we should not disable the button (its function is to cancel 'selection find'). * If 'selection find' is OFF we enable the button only if there is a selection. @@ -560,6 +577,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas private _applyTheme(theme: ITheme) { let inputStyles: IFindInputStyles = { inputActiveOptionBorder: theme.getColor(inputActiveOptionBorder), + inputActiveOptionBackground: theme.getColor(inputActiveOptionBackground), inputBackground: theme.getColor(inputBackground), inputForeground: theme.getColor(inputForeground), inputBorder: theme.getColor(inputBorder), @@ -575,14 +593,26 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas }; this._findInput.style(inputStyles); this._replaceInputBox.style(inputStyles); + this._preserveCase.style(inputStyles); } private _tryUpdateWidgetWidth() { if (!this._isVisible) { return; } - let editorWidth = this._codeEditor.getConfiguration().layoutInfo.width; - let minimapWidth = this._codeEditor.getConfiguration().layoutInfo.minimapWidth; + + const editorContentWidth = this._codeEditor.getConfiguration().layoutInfo.contentWidth; + + if (editorContentWidth <= 0) { + // for example, diff view original editor + dom.addClass(this._domNode, 'hiddenEditor'); + return; + } else if (dom.hasClass(this._domNode, 'hiddenEditor')) { + dom.removeClass(this._domNode, 'hiddenEditor'); + } + + const editorWidth = this._codeEditor.getConfiguration().layoutInfo.width; + const minimapWidth = this._codeEditor.getConfiguration().layoutInfo.minimapWidth; let collapsedFindWidget = false; let reducedFindWidget = false; let narrowFindWidget = false; @@ -898,6 +928,19 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas this._state.change({ replaceString: this._replaceInputBox.value }, false); })); + this._preserveCase = this._register(new Checkbox({ + actionClassName: 'monaco-preserve-case', + title: NLS_PRESERVE_CASE_LABEL, + isChecked: false, + })); + this._preserveCase.checked = !!this._state.preserveCase; + this._register(this._preserveCase.onChange(viaKeyboard => { + if (!viaKeyboard) { + this._state.change({ preserveCase: !this._state.preserveCase }, false); + this._replaceInputBox.focus(); + } + })); + // Replace one button this._replaceBtn = this._register(new SimpleButton({ label: NLS_REPLACE_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.ReplaceOneAction), @@ -922,6 +965,12 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas } })); + let controls = document.createElement('div'); + controls.className = 'controls'; + controls.style.display = 'block'; + controls.appendChild(this._preserveCase.domNode); + replaceInput.appendChild(controls); + let replacePart = document.createElement('div'); replacePart.className = 'replace-part'; replacePart.appendChild(replaceInput); @@ -1193,6 +1242,11 @@ registerThemingParticipant((theme, collector) => { collector.addRule(`.monaco-editor .find-widget { border: 2px solid ${hcBorder}; }`); } + const foreground = theme.getColor(editorWidgetForeground); + if (foreground) { + collector.addRule(`.monaco-editor .find-widget { color: ${foreground}; }`); + } + const error = theme.getColor(errorForeground); if (error) { collector.addRule(`.monaco-editor .find-widget.no-results .matchesCount { color: ${error}; }`); @@ -1212,4 +1266,9 @@ registerThemingParticipant((theme, collector) => { if (inputActiveBorder) { collector.addRule(`.monaco-editor .find-widget .monaco-checkbox .checkbox:checked + .label { border: 1px solid ${inputActiveBorder.toString()}; }`); } + + const inputActiveBackground = theme.getColor(inputActiveOptionBackground); + if (inputActiveBackground) { + collector.addRule(`.monaco-editor .find-widget .monaco-checkbox .checkbox:checked + .label { background-color: ${inputActiveBackground.toString()}; }`); + } }); diff --git a/src/vs/editor/contrib/find/images/cancelSelectionFind-inverse.svg b/src/vs/editor/contrib/find/images/cancelSelectionFind-inverse.svg deleted file mode 100644 index d776fcde9..000000000 --- a/src/vs/editor/contrib/find/images/cancelSelectionFind-inverse.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/src/vs/editor/contrib/find/images/cancelSelectionFind.svg b/src/vs/editor/contrib/find/images/cancelSelectionFind.svg deleted file mode 100644 index cdff5731a..000000000 --- a/src/vs/editor/contrib/find/images/cancelSelectionFind.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/src/vs/editor/contrib/find/images/chevron-next-dark.svg b/src/vs/editor/contrib/find/images/chevron-next-dark.svg new file mode 100644 index 000000000..dbe70d742 --- /dev/null +++ b/src/vs/editor/contrib/find/images/chevron-next-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/find/images/chevron-next-light.svg b/src/vs/editor/contrib/find/images/chevron-next-light.svg new file mode 100644 index 000000000..ec824f41c --- /dev/null +++ b/src/vs/editor/contrib/find/images/chevron-next-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/find/images/chevron-previous-dark.svg b/src/vs/editor/contrib/find/images/chevron-previous-dark.svg new file mode 100644 index 000000000..5db4f79da --- /dev/null +++ b/src/vs/editor/contrib/find/images/chevron-previous-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/find/images/chevron-previous-light.svg b/src/vs/editor/contrib/find/images/chevron-previous-light.svg new file mode 100644 index 000000000..aac3a5020 --- /dev/null +++ b/src/vs/editor/contrib/find/images/chevron-previous-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/find/images/close-dark.svg b/src/vs/editor/contrib/find/images/close-dark.svg index 751e89b3b..75644595d 100644 --- a/src/vs/editor/contrib/find/images/close-dark.svg +++ b/src/vs/editor/contrib/find/images/close-dark.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + diff --git a/src/vs/editor/contrib/find/images/close-light.svg b/src/vs/editor/contrib/find/images/close-light.svg new file mode 100644 index 000000000..cf5f28ca3 --- /dev/null +++ b/src/vs/editor/contrib/find/images/close-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/find/images/close.svg b/src/vs/editor/contrib/find/images/close.svg deleted file mode 100644 index fde34404d..000000000 --- a/src/vs/editor/contrib/find/images/close.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/find/images/expando-collapsed-dark.svg b/src/vs/editor/contrib/find/images/expando-collapsed-dark.svg deleted file mode 100644 index 6f3abfce7..000000000 --- a/src/vs/editor/contrib/find/images/expando-collapsed-dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/find/images/expando-collapsed.svg b/src/vs/editor/contrib/find/images/expando-collapsed.svg deleted file mode 100644 index 5dcb87c77..000000000 --- a/src/vs/editor/contrib/find/images/expando-collapsed.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/find/images/expando-expanded-dark.svg b/src/vs/editor/contrib/find/images/expando-expanded-dark.svg deleted file mode 100644 index 22dfac04f..000000000 --- a/src/vs/editor/contrib/find/images/expando-expanded-dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/find/images/expando-expanded.svg b/src/vs/editor/contrib/find/images/expando-expanded.svg deleted file mode 100644 index e55ccd923..000000000 --- a/src/vs/editor/contrib/find/images/expando-expanded.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/find/images/find-selection-dark.svg b/src/vs/editor/contrib/find/images/find-selection-dark.svg new file mode 100644 index 000000000..6fc07d81a --- /dev/null +++ b/src/vs/editor/contrib/find/images/find-selection-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/find/images/find-selection-light.svg b/src/vs/editor/contrib/find/images/find-selection-light.svg new file mode 100644 index 000000000..3608b15d2 --- /dev/null +++ b/src/vs/editor/contrib/find/images/find-selection-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/find/images/next-inverse.svg b/src/vs/editor/contrib/find/images/next-inverse.svg deleted file mode 100644 index 50482917a..000000000 --- a/src/vs/editor/contrib/find/images/next-inverse.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/find/images/next.svg b/src/vs/editor/contrib/find/images/next.svg deleted file mode 100644 index a2a011453..000000000 --- a/src/vs/editor/contrib/find/images/next.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/find/images/previous-inverse.svg b/src/vs/editor/contrib/find/images/previous-inverse.svg deleted file mode 100644 index 8ff41da5d..000000000 --- a/src/vs/editor/contrib/find/images/previous-inverse.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/find/images/previous.svg b/src/vs/editor/contrib/find/images/previous.svg deleted file mode 100644 index 3c8b367a9..000000000 --- a/src/vs/editor/contrib/find/images/previous.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/src/vs/editor/contrib/find/images/replace-all-dark.svg b/src/vs/editor/contrib/find/images/replace-all-dark.svg new file mode 100644 index 000000000..07bd41a78 --- /dev/null +++ b/src/vs/editor/contrib/find/images/replace-all-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/find/images/replace-all-inverse.svg b/src/vs/editor/contrib/find/images/replace-all-inverse.svg deleted file mode 100644 index 45312b608..000000000 --- a/src/vs/editor/contrib/find/images/replace-all-inverse.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - diff --git a/src/vs/editor/contrib/find/images/replace-all-light.svg b/src/vs/editor/contrib/find/images/replace-all-light.svg new file mode 100644 index 000000000..cd3974fae --- /dev/null +++ b/src/vs/editor/contrib/find/images/replace-all-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/find/images/replace-all.svg b/src/vs/editor/contrib/find/images/replace-all.svg deleted file mode 100644 index 4254f7c6d..000000000 --- a/src/vs/editor/contrib/find/images/replace-all.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - diff --git a/src/vs/editor/contrib/find/images/replace-dark.svg b/src/vs/editor/contrib/find/images/replace-dark.svg new file mode 100644 index 000000000..5882b22c5 --- /dev/null +++ b/src/vs/editor/contrib/find/images/replace-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/find/images/replace-inverse.svg b/src/vs/editor/contrib/find/images/replace-inverse.svg deleted file mode 100644 index 9a59e2637..000000000 --- a/src/vs/editor/contrib/find/images/replace-inverse.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - diff --git a/src/vs/editor/contrib/find/images/replace-light.svg b/src/vs/editor/contrib/find/images/replace-light.svg new file mode 100644 index 000000000..220f2aba4 --- /dev/null +++ b/src/vs/editor/contrib/find/images/replace-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/find/images/replace.svg b/src/vs/editor/contrib/find/images/replace.svg deleted file mode 100644 index 8b1eb0de2..000000000 --- a/src/vs/editor/contrib/find/images/replace.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - diff --git a/src/vs/editor/contrib/find/images/tree-collapsed-dark.svg b/src/vs/editor/contrib/find/images/tree-collapsed-dark.svg new file mode 100644 index 000000000..17de497f3 --- /dev/null +++ b/src/vs/editor/contrib/find/images/tree-collapsed-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/find/images/tree-collapsed-light.svg b/src/vs/editor/contrib/find/images/tree-collapsed-light.svg new file mode 100644 index 000000000..296499b8e --- /dev/null +++ b/src/vs/editor/contrib/find/images/tree-collapsed-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/find/images/tree-expanded-dark.svg b/src/vs/editor/contrib/find/images/tree-expanded-dark.svg new file mode 100644 index 000000000..a1df6a8d4 --- /dev/null +++ b/src/vs/editor/contrib/find/images/tree-expanded-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/find/images/tree-expanded-light.svg b/src/vs/editor/contrib/find/images/tree-expanded-light.svg new file mode 100644 index 000000000..e60e357f5 --- /dev/null +++ b/src/vs/editor/contrib/find/images/tree-expanded-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/find/replacePattern.ts b/src/vs/editor/contrib/find/replacePattern.ts index 3bd09a78e..50e90d7f3 100644 --- a/src/vs/editor/contrib/find/replacePattern.ts +++ b/src/vs/editor/contrib/find/replacePattern.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { CharCode } from 'vs/base/common/charCode'; +import { containsUppercaseCharacter } from 'vs/base/common/strings'; const enum ReplacePatternKind { StaticValue = 0, @@ -48,9 +49,22 @@ export class ReplacePattern { } } - public buildReplaceString(matches: string[] | null): string { + public buildReplaceString(matches: string[] | null, preserveCase?: boolean): string { if (this._state.kind === ReplacePatternKind.StaticValue) { - return this._state.staticValue; + if (preserveCase && matches && (matches[0] !== '')) { + if (matches[0].toUpperCase() === matches[0]) { + return this._state.staticValue.toUpperCase(); + } else if (matches[0].toLowerCase() === matches[0]) { + return this._state.staticValue.toLowerCase(); + } else if (containsUppercaseCharacter(matches[0][0])) { + return this._state.staticValue[0].toUpperCase() + this._state.staticValue.substr(1); + } else { + // we don't understand its pattern yet. + return this._state.staticValue; + } + } else { + return this._state.staticValue; + } } let result = ''; diff --git a/src/vs/editor/contrib/find/simpleFindWidget.css b/src/vs/editor/contrib/find/simpleFindWidget.css index 136970945..4a796be08 100644 --- a/src/vs/editor/contrib/find/simpleFindWidget.css +++ b/src/vs/editor/contrib/find/simpleFindWidget.css @@ -52,25 +52,25 @@ } .monaco-workbench .simple-find-part .button.previous { - background-image: url('images/previous.svg'); + background-image: url('images/chevron-previous-light.svg'); } .monaco-workbench .simple-find-part .button.next { - background-image: url('images/next.svg'); + background-image: url('images/chevron-next-light.svg'); } .monaco-workbench .simple-find-part .button.close-fw { - background-image: url('images/close.svg'); + background-image: url('images/close-light.svg'); } .hc-black .monaco-workbench .simple-find-part .button.previous, .vs-dark .monaco-workbench .simple-find-part .button.previous { - background-image: url('images/previous-inverse.svg'); + background-image: url('images/chevron-previous-dark.svg'); } .hc-black .monaco-workbench .simple-find-part .button.next, .vs-dark .monaco-workbench .simple-find-part .button.next { - background-image: url('images/next-inverse.svg'); + background-image: url('images/chevron-next-dark.svg'); } .hc-black .monaco-workbench .simple-find-part .button.close-fw, @@ -78,7 +78,7 @@ background-image: url('images/close-dark.svg'); } -monaco-workbench .simple-find-part .button.disabled { +.monaco-workbench .simple-find-part .button.disabled { opacity: 0.3; cursor: default; } \ No newline at end of file diff --git a/src/vs/editor/contrib/find/simpleFindWidget.ts b/src/vs/editor/contrib/find/simpleFindWidget.ts index c7833dcc2..e37233661 100644 --- a/src/vs/editor/contrib/find/simpleFindWidget.ts +++ b/src/vs/editor/contrib/find/simpleFindWidget.ts @@ -15,7 +15,7 @@ import { IMessage as InputBoxMessage } from 'vs/base/browser/ui/inputbox/inputBo import { SimpleButton } from 'vs/editor/contrib/find/findWidget'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; -import { editorWidgetBackground, inputActiveOptionBorder, inputBackground, inputBorder, inputForeground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, inputValidationInfoBackground, inputValidationInfoBorder, inputValidationInfoForeground, inputValidationWarningBackground, inputValidationWarningBorder, inputValidationWarningForeground, widgetShadow } from 'vs/platform/theme/common/colorRegistry'; +import { editorWidgetBackground, inputActiveOptionBorder, inputActiveOptionBackground, inputBackground, inputBorder, inputForeground, inputValidationErrorBackground, inputValidationErrorBorder, inputValidationErrorForeground, inputValidationInfoBackground, inputValidationInfoBorder, inputValidationInfoForeground, inputValidationWarningBackground, inputValidationWarningBorder, inputValidationWarningForeground, widgetShadow } from 'vs/platform/theme/common/colorRegistry'; import { ITheme, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { ContextScopedFindInput } from 'vs/platform/browser/contextScopedHistoryWidget'; @@ -33,12 +33,16 @@ export abstract class SimpleFindWidget extends Widget { private readonly _focusTracker: dom.IFocusTracker; private readonly _findInputFocusTracker: dom.IFocusTracker; private readonly _updateHistoryDelayer: Delayer; + private prevBtn: SimpleButton; + private nextBtn: SimpleButton; + private foundMatch: boolean; constructor( @IContextViewService private readonly _contextViewService: IContextViewService, @IContextKeyService contextKeyService: IContextKeyService, private readonly _state: FindReplaceState = new FindReplaceState(), - showOptionButtons?: boolean + showOptionButtons?: boolean, + private readonly _invertDefaultDirection: boolean = false ) { super(); @@ -54,6 +58,8 @@ export abstract class SimpleFindWidget extends Widget { new RegExp(value); return null; } catch (e) { + this.foundMatch = false; + this._updateButtons(); return { content: e.message }; } } @@ -63,7 +69,8 @@ export abstract class SimpleFindWidget extends Widget { this._updateHistoryDelayer = new Delayer(500); this.oninput(this._findInput.domNode, (e) => { - this.onInputChanged(); + this.foundMatch = this.onInputChanged(); + this._updateButtons(); this._delayedUpdateHistory(); }); @@ -87,47 +94,47 @@ export abstract class SimpleFindWidget extends Widget { this._register(this._findInput.onKeyDown((e) => { if (e.equals(KeyCode.Enter)) { - this.find(false); + this.find(this._invertDefaultDirection); e.preventDefault(); return; } if (e.equals(KeyMod.Shift | KeyCode.Enter)) { - this.find(true); + this.find(!this._invertDefaultDirection); e.preventDefault(); return; } })); - const prevBtn = new SimpleButton({ + this.prevBtn = this._register(new SimpleButton({ label: NLS_PREVIOUS_MATCH_BTN_LABEL, className: 'previous', onTrigger: () => { this.find(true); } - }); + })); - const nextBtn = new SimpleButton({ + this.nextBtn = this._register(new SimpleButton({ label: NLS_NEXT_MATCH_BTN_LABEL, className: 'next', onTrigger: () => { this.find(false); } - }); + })); - const closeBtn = new SimpleButton({ + const closeBtn = this._register(new SimpleButton({ label: NLS_CLOSE_BTN_LABEL, className: 'close-fw', onTrigger: () => { this.hide(); } - }); + })); 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(this.prevBtn.domNode); + this._innerDomNode.appendChild(this.nextBtn.domNode); this._innerDomNode.appendChild(closeBtn.domNode); // _domNode wraps _innerDomNode, ensuring that @@ -156,7 +163,7 @@ export abstract class SimpleFindWidget extends Widget { })); } - protected abstract onInputChanged(): void; + protected abstract onInputChanged(): boolean; protected abstract find(previous: boolean): void; protected abstract onFocusTrackerFocus(): void; protected abstract onFocusTrackerBlur(): void; @@ -174,6 +181,7 @@ export abstract class SimpleFindWidget extends Widget { public updateTheme(theme: ITheme): void { const inputStyles: IFindInputStyles = { inputActiveOptionBorder: theme.getColor(inputActiveOptionBorder), + inputActiveOptionBackground: theme.getColor(inputActiveOptionBackground), inputBackground: theme.getColor(inputBackground), inputForeground: theme.getColor(inputForeground), inputBorder: theme.getColor(inputBorder), @@ -213,6 +221,7 @@ export abstract class SimpleFindWidget extends Widget { } this._isVisible = true; + this._updateButtons(); setTimeout(() => { dom.addClass(this._innerDomNode, 'visible'); @@ -243,6 +252,7 @@ export abstract class SimpleFindWidget extends Widget { // Need to delay toggling visibility until after Transition, then visibility hidden - removes from tabIndex list setTimeout(() => { this._isVisible = false; + this._updateButtons(); dom.removeClass(this._innerDomNode, 'visible'); }, 200); } @@ -267,6 +277,12 @@ export abstract class SimpleFindWidget extends Widget { protected _getCaseSensitiveValue(): boolean { return this._findInput.getCaseSensitive(); } + + private _updateButtons() { + let hasInput = this.inputValue.length > 0; + this.prevBtn.setEnabled(this._isVisible && hasInput && this.foundMatch); + this.nextBtn.setEnabled(this._isVisible && hasInput && this.foundMatch); + } } // theming @@ -280,4 +296,4 @@ registerThemingParticipant((theme, collector) => { if (widgetShadowColor) { collector.addRule(`.monaco-workbench .simple-find-part { box-shadow: 0 2px 8px ${widgetShadowColor}; }`); } -}); \ No newline at end of file +}); diff --git a/src/vs/editor/contrib/find/test/findModel.test.ts b/src/vs/editor/contrib/find/test/findModel.test.ts index 9ac679cb0..df936e174 100644 --- a/src/vs/editor/contrib/find/test/findModel.test.ts +++ b/src/vs/editor/contrib/find/test/findModel.test.ts @@ -1947,6 +1947,42 @@ suite('FindModel', () => { findState.dispose(); }); + findTest('replaceAll preserving case', (editor, cursor) => { + let findState = new FindReplaceState(); + findState.change({ searchString: 'hello', replaceString: 'goodbye', isRegex: false, matchCase: false, preserveCase: true }, false); + let findModel = new FindModelBoundToEditorModel(editor, findState); + + assertFindState( + editor, + [1, 1, 1, 1], + null, + [ + [6, 14, 6, 19], + [6, 27, 6, 32], + [7, 14, 7, 19], + [8, 14, 8, 19], + [9, 14, 9, 19], + ] + ); + + findModel.replaceAll(); + + assert.equal(editor.getModel()!.getLineContent(6), ' cout << "goodbye world, Goodbye!" << endl;'); + assert.equal(editor.getModel()!.getLineContent(7), ' cout << "goodbye world again" << endl;'); + assert.equal(editor.getModel()!.getLineContent(8), ' cout << "Goodbye world again" << endl;'); + assert.equal(editor.getModel()!.getLineContent(9), ' cout << "goodbyeworld again" << endl;'); + + assertFindState( + editor, + [1, 1, 1, 1], + null, + [] + ); + + findModel.dispose(); + findState.dispose(); + }); + findTest('issue #18711 replaceAll with empty string', (editor, cursor) => { let findState = new FindReplaceState(); findState.change({ searchString: 'hello', replaceString: '', wholeWord: true }, false); diff --git a/src/vs/editor/contrib/find/test/replacePattern.test.ts b/src/vs/editor/contrib/find/test/replacePattern.test.ts index b36a509e3..d252ac74c 100644 --- a/src/vs/editor/contrib/find/test/replacePattern.test.ts +++ b/src/vs/editor/contrib/find/test/replacePattern.test.ts @@ -153,4 +153,26 @@ suite('Replace Pattern test', () => { let actual = replacePattern.buildReplaceString(matches); assert.equal(actual, 'a{}'); }); + + test('preserve case', () => { + let replacePattern = parseReplaceString('Def'); + let actual = replacePattern.buildReplaceString(['abc'], true); + assert.equal(actual, 'def'); + actual = replacePattern.buildReplaceString(['Abc'], true); + assert.equal(actual, 'Def'); + actual = replacePattern.buildReplaceString(['ABC'], true); + assert.equal(actual, 'DEF'); + + actual = replacePattern.buildReplaceString(['abc', 'Abc'], true); + assert.equal(actual, 'def'); + actual = replacePattern.buildReplaceString(['Abc', 'abc'], true); + assert.equal(actual, 'Def'); + actual = replacePattern.buildReplaceString(['ABC', 'abc'], true); + assert.equal(actual, 'DEF'); + + actual = replacePattern.buildReplaceString(['AbC'], true); + assert.equal(actual, 'Def'); + actual = replacePattern.buildReplaceString(['aBC'], true); + assert.equal(actual, 'Def'); + }); }); diff --git a/src/vs/editor/contrib/folding/arrow-collapse-dark.svg b/src/vs/editor/contrib/folding/arrow-collapse-dark.svg deleted file mode 100644 index 1d7ce3b6b..000000000 --- a/src/vs/editor/contrib/folding/arrow-collapse-dark.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/src/vs/editor/contrib/folding/arrow-collapse.svg b/src/vs/editor/contrib/folding/arrow-collapse.svg deleted file mode 100644 index 9e6896640..000000000 --- a/src/vs/editor/contrib/folding/arrow-collapse.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/src/vs/editor/contrib/folding/arrow-expand-dark.svg b/src/vs/editor/contrib/folding/arrow-expand-dark.svg deleted file mode 100644 index 4d1a5ca84..000000000 --- a/src/vs/editor/contrib/folding/arrow-expand-dark.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/src/vs/editor/contrib/folding/arrow-expand.svg b/src/vs/editor/contrib/folding/arrow-expand.svg deleted file mode 100644 index f1472e275..000000000 --- a/src/vs/editor/contrib/folding/arrow-expand.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/src/vs/editor/contrib/folding/folding.css b/src/vs/editor/contrib/folding/folding.css index b5d3b7049..79511b6c0 100644 --- a/src/vs/editor/contrib/folding/folding.css +++ b/src/vs/editor/contrib/folding/folding.css @@ -14,12 +14,16 @@ } .monaco-editor .margin-view-overlays .folding { - background-image: url('arrow-expand.svg'); + background-image: url('tree-expanded-light.svg'); } .monaco-editor.hc-black .margin-view-overlays .folding, .monaco-editor.vs-dark .margin-view-overlays .folding { - background-image: url('arrow-expand-dark.svg'); + background-image: url('tree-expanded-dark.svg'); +} + +.monaco-editor.hc-black .margin-view-overlays .folding { + background-image: url('tree-expanded-hc.svg'); } .monaco-editor .margin-view-overlays:hover .folding, @@ -28,13 +32,16 @@ } .monaco-editor .margin-view-overlays .folding.collapsed { - background-image: url('arrow-collapse.svg'); + background-image: url('tree-collapsed-light.svg'); opacity: 1; } -.monaco-editor.hc-black .margin-view-overlays .folding.collapsed, .monaco-editor.vs-dark .margin-view-overlays .folding.collapsed { - background-image: url('arrow-collapse-dark.svg'); + background-image: url('tree-collapsed-dark.svg'); +} + +.monaco-editor.hc-black .margin-view-overlays .folding.collapsed { + background-image: url('tree-collapsed-hc.svg'); } .monaco-editor .inline-folded:after { diff --git a/src/vs/editor/contrib/folding/folding.ts b/src/vs/editor/contrib/folding/folding.ts index 24d64b502..9a9ea25c5 100644 --- a/src/vs/editor/contrib/folding/folding.ts +++ b/src/vs/editor/contrib/folding/folding.ts @@ -9,7 +9,7 @@ import * as types from 'vs/base/common/types'; import { escapeRegExpCharacters } from 'vs/base/common/strings'; import { RunOnceScheduler, Delayer, CancelablePromise, createCancelablePromise } from 'vs/base/common/async'; import { KeyCode, KeyMod, KeyChord } from 'vs/base/common/keyCodes'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { ScrollType, IEditorContribution } from 'vs/editor/common/editorCommon'; import { ITextModel } from 'vs/editor/common/model'; import { registerEditorAction, registerEditorContribution, ServicesAccessor, EditorAction, registerInstantiatedEditorAction } from 'vs/editor/browser/editorExtensions'; @@ -31,7 +31,9 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { InitializingRangeProvider, ID_INIT_PROVIDER } from 'vs/editor/contrib/folding/intializingRangeProvider'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { onUnexpectedError } from 'vs/base/common/errors'; +import { RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +const CONTEXT_FOLDING_ENABLED = new RawContextKey('foldingEnabled', false); export const ID = 'editor.contrib.folding'; export interface RangeProvider { @@ -46,7 +48,7 @@ interface FoldingStateMemento { provider?: string; } -export class FoldingController implements IEditorContribution { +export class FoldingController extends Disposable implements IEditorContribution { static MAX_FOLDING_REGIONS = 5000; @@ -73,30 +75,34 @@ export class FoldingController implements IEditorContribution { private foldingModelPromise: Promise | null; private updateScheduler: Delayer | null; - private globalToDispose: IDisposable[]; - + private foldingEnabled: IContextKey; private cursorChangedScheduler: RunOnceScheduler | null; - private localToDispose: IDisposable[]; + private readonly localToDispose = this._register(new DisposableStore()); - constructor(editor: ICodeEditor) { + constructor( + editor: ICodeEditor, + @IContextKeyService private readonly contextKeyService: IContextKeyService + ) { + super(); this.editor = editor; this._isEnabled = this.editor.getConfiguration().contribInfo.folding; this._autoHideFoldingControls = this.editor.getConfiguration().contribInfo.showFoldingControls === 'mouseover'; this._useFoldingProviders = this.editor.getConfiguration().contribInfo.foldingStrategy !== 'indentation'; - this.globalToDispose = []; - this.localToDispose = []; this.foldingDecorationProvider = new FoldingDecorationProvider(editor); this.foldingDecorationProvider.autoHideFoldingControls = this._autoHideFoldingControls; + this.foldingEnabled = CONTEXT_FOLDING_ENABLED.bindTo(this.contextKeyService); + this.foldingEnabled.set(this._isEnabled); - this.globalToDispose.push(this.editor.onDidChangeModel(() => this.onModelChanged())); + this._register(this.editor.onDidChangeModel(() => this.onModelChanged())); - this.globalToDispose.push(this.editor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => { + this._register(this.editor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => { if (e.contribInfo) { let oldIsEnabled = this._isEnabled; this._isEnabled = this.editor.getConfiguration().contribInfo.folding; + this.foldingEnabled.set(this._isEnabled); if (oldIsEnabled !== this._isEnabled) { this.onModelChanged(); } @@ -113,7 +119,6 @@ export class FoldingController implements IEditorContribution { } } })); - this.globalToDispose.push({ dispose: () => dispose(this.localToDispose) }); this.onModelChanged(); } @@ -121,10 +126,6 @@ export class FoldingController implements IEditorContribution { return ID; } - public dispose(): void { - this.globalToDispose = dispose(this.globalToDispose); - } - /** * Store view state. */ @@ -173,7 +174,7 @@ export class FoldingController implements IEditorContribution { } private onModelChanged(): void { - this.localToDispose = dispose(this.localToDispose); + this.localToDispose.clear(); let model = this.editor.getModel(); if (!this._isEnabled || !model || model.isTooLargeForTokenization()) { @@ -182,23 +183,23 @@ export class FoldingController implements IEditorContribution { } this.foldingModel = new FoldingModel(model, this.foldingDecorationProvider); - this.localToDispose.push(this.foldingModel); + this.localToDispose.add(this.foldingModel); this.hiddenRangeModel = new HiddenRangeModel(this.foldingModel); - this.localToDispose.push(this.hiddenRangeModel); - this.localToDispose.push(this.hiddenRangeModel.onDidChange(hr => this.onHiddenRangesChanges(hr))); + this.localToDispose.add(this.hiddenRangeModel); + this.localToDispose.add(this.hiddenRangeModel.onDidChange(hr => this.onHiddenRangesChanges(hr))); this.updateScheduler = new Delayer(200); this.cursorChangedScheduler = new RunOnceScheduler(() => this.revealCursor(), 200); - this.localToDispose.push(this.cursorChangedScheduler); - this.localToDispose.push(FoldingRangeProviderRegistry.onDidChange(() => this.onFoldingStrategyChanged())); - this.localToDispose.push(this.editor.onDidChangeModelLanguageConfiguration(() => this.onFoldingStrategyChanged())); // covers model language changes as well - this.localToDispose.push(this.editor.onDidChangeModelContent(() => this.onModelContentChanged())); - this.localToDispose.push(this.editor.onDidChangeCursorPosition(() => 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({ + this.localToDispose.add(this.cursorChangedScheduler); + this.localToDispose.add(FoldingRangeProviderRegistry.onDidChange(() => this.onFoldingStrategyChanged())); + this.localToDispose.add(this.editor.onDidChangeModelLanguageConfiguration(() => this.onFoldingStrategyChanged())); // covers model language changes as well + this.localToDispose.add(this.editor.onDidChangeModelContent(() => this.onModelContentChanged())); + this.localToDispose.add(this.editor.onDidChangeCursorPosition(() => this.onCursorPositionChanged())); + this.localToDispose.add(this.editor.onMouseDown(e => this.onEditorMouseDown(e))); + this.localToDispose.add(this.editor.onMouseUp(e => this.onEditorMouseUp(e))); + this.localToDispose.add({ dispose: () => { if (this.foldingRegionPromise) { this.foldingRegionPromise.cancel(); @@ -503,7 +504,7 @@ class UnfoldAction extends FoldingAction { id: 'editor.unfold', label: nls.localize('unfoldAction.label', "Unfold"), alias: 'Unfold', - precondition: null, + precondition: CONTEXT_FOLDING_ENABLED, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_CLOSE_SQUARE_BRACKET, @@ -567,7 +568,7 @@ class UnFoldRecursivelyAction extends FoldingAction { id: 'editor.unfoldRecursively', label: nls.localize('unFoldRecursivelyAction.label', "Unfold Recursively"), alias: 'Unfold Recursively', - precondition: null, + precondition: CONTEXT_FOLDING_ENABLED, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.US_CLOSE_SQUARE_BRACKET), @@ -588,7 +589,7 @@ class FoldAction extends FoldingAction { id: 'editor.fold', label: nls.localize('foldAction.label', "Fold"), alias: 'Fold', - precondition: null, + precondition: CONTEXT_FOLDING_ENABLED, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_OPEN_SQUARE_BRACKET, @@ -652,7 +653,7 @@ class FoldRecursivelyAction extends FoldingAction { id: 'editor.foldRecursively', label: nls.localize('foldRecursivelyAction.label', "Fold Recursively"), alias: 'Fold Recursively', - precondition: null, + precondition: CONTEXT_FOLDING_ENABLED, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.US_OPEN_SQUARE_BRACKET), @@ -674,7 +675,7 @@ class FoldAllBlockCommentsAction extends FoldingAction { id: 'editor.foldAllBlockComments', label: nls.localize('foldAllBlockComments.label', "Fold All Block Comments"), alias: 'Fold All Block Comments', - precondition: null, + precondition: CONTEXT_FOLDING_ENABLED, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.US_SLASH), @@ -707,7 +708,7 @@ class FoldAllRegionsAction extends FoldingAction { id: 'editor.foldAllMarkerRegions', label: nls.localize('foldAllMarkerRegions.label', "Fold All Regions"), alias: 'Fold All Regions', - precondition: null, + precondition: CONTEXT_FOLDING_ENABLED, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_8), @@ -740,7 +741,7 @@ class UnfoldAllRegionsAction extends FoldingAction { id: 'editor.unfoldAllMarkerRegions', label: nls.localize('unfoldAllMarkerRegions.label', "Unfold All Regions"), alias: 'Unfold All Regions', - precondition: null, + precondition: CONTEXT_FOLDING_ENABLED, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_9), @@ -773,7 +774,7 @@ class FoldAllAction extends FoldingAction { id: 'editor.foldAll', label: nls.localize('foldAllAction.label', "Fold All"), alias: 'Fold All', - precondition: null, + precondition: CONTEXT_FOLDING_ENABLED, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_0), @@ -794,7 +795,7 @@ class UnfoldAllAction extends FoldingAction { id: 'editor.unfoldAll', label: nls.localize('unfoldAllAction.label', "Unfold All"), alias: 'Unfold All', - precondition: null, + precondition: CONTEXT_FOLDING_ENABLED, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_J), @@ -838,7 +839,7 @@ for (let i = 1; i <= 7; i++) { id: FoldLevelAction.ID(i), label: nls.localize('foldLevelAction.label', "Fold Level {0}", i), alias: `Fold Level ${i}`, - precondition: null, + precondition: CONTEXT_FOLDING_ENABLED, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | (KeyCode.KEY_0 + i)), diff --git a/src/vs/editor/contrib/folding/foldingModel.ts b/src/vs/editor/contrib/folding/foldingModel.ts index 0375be9f1..e81b529d0 100644 --- a/src/vs/editor/contrib/folding/foldingModel.ts +++ b/src/vs/editor/contrib/folding/foldingModel.ts @@ -29,9 +29,9 @@ export class FoldingModel { private _isInitialized: boolean; private _updateEventEmitter = new Emitter(); + public readonly onDidChange: Event = this._updateEventEmitter.event; public get regions(): FoldingRegions { return this._regions; } - public get onDidChange(): Event { return this._updateEventEmitter.event; } public get textModel() { return this._textModel; } public get isInitialized() { return this._isInitialized; } @@ -47,7 +47,7 @@ export class FoldingModel { if (!regions.length) { return; } - let processed = {}; + let processed: { [key: string]: boolean | undefined } = {}; this._decorationProvider.changeDecorations(accessor => { for (let region of regions) { let index = region.regionIndex; diff --git a/src/vs/editor/contrib/folding/tree-collapsed-dark.svg b/src/vs/editor/contrib/folding/tree-collapsed-dark.svg new file mode 100644 index 000000000..243be1451 --- /dev/null +++ b/src/vs/editor/contrib/folding/tree-collapsed-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/folding/tree-collapsed-hc.svg b/src/vs/editor/contrib/folding/tree-collapsed-hc.svg new file mode 100644 index 000000000..40ba72b70 --- /dev/null +++ b/src/vs/editor/contrib/folding/tree-collapsed-hc.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/folding/tree-collapsed-light.svg b/src/vs/editor/contrib/folding/tree-collapsed-light.svg new file mode 100644 index 000000000..0d746558a --- /dev/null +++ b/src/vs/editor/contrib/folding/tree-collapsed-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/folding/tree-expanded-dark.svg b/src/vs/editor/contrib/folding/tree-expanded-dark.svg new file mode 100644 index 000000000..5570923e1 --- /dev/null +++ b/src/vs/editor/contrib/folding/tree-expanded-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/folding/tree-expanded-hc.svg b/src/vs/editor/contrib/folding/tree-expanded-hc.svg new file mode 100644 index 000000000..b37000933 --- /dev/null +++ b/src/vs/editor/contrib/folding/tree-expanded-hc.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/folding/tree-expanded-light.svg b/src/vs/editor/contrib/folding/tree-expanded-light.svg new file mode 100644 index 000000000..939ebc8b9 --- /dev/null +++ b/src/vs/editor/contrib/folding/tree-expanded-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/fontZoom/fontZoom.ts b/src/vs/editor/contrib/fontZoom/fontZoom.ts index b0c971613..b7eefcb8c 100644 --- a/src/vs/editor/contrib/fontZoom/fontZoom.ts +++ b/src/vs/editor/contrib/fontZoom/fontZoom.ts @@ -15,7 +15,7 @@ class EditorFontZoomIn extends EditorAction { id: 'editor.action.fontZoomIn', label: nls.localize('EditorFontZoomIn.label', "Editor Font Zoom In"), alias: 'Editor Font Zoom In', - precondition: null + precondition: undefined }); } @@ -31,7 +31,7 @@ class EditorFontZoomOut extends EditorAction { id: 'editor.action.fontZoomOut', label: nls.localize('EditorFontZoomOut.label', "Editor Font Zoom Out"), alias: 'Editor Font Zoom Out', - precondition: null + precondition: undefined }); } @@ -47,7 +47,7 @@ class EditorFontZoomReset extends EditorAction { id: 'editor.action.fontZoomReset', label: nls.localize('EditorFontZoomReset.label', "Editor Font Zoom Reset"), alias: 'Editor Font Zoom Reset', - precondition: null + precondition: undefined }); } diff --git a/src/vs/editor/contrib/format/format.ts b/src/vs/editor/contrib/format/format.ts index 261d86ba7..cdf9ba122 100644 --- a/src/vs/editor/contrib/format/format.ts +++ b/src/vs/editor/contrib/format/format.ts @@ -8,7 +8,7 @@ import { isNonEmptyArray } from 'vs/base/common/arrays'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import { illegalArgument, onUnexpectedExternalError } from 'vs/base/common/errors'; import { URI } from 'vs/base/common/uri'; -import { CodeEditorStateFlag, EditorState, EditorStateCancellationTokenSource, TextModelCancellationTokenSource } from 'vs/editor/browser/core/editorState'; +import { CodeEditorStateFlag, EditorStateCancellationTokenSource, TextModelCancellationTokenSource } from 'vs/editor/browser/core/editorState'; import { IActiveCodeEditor, isCodeEditor } from 'vs/editor/browser/editorBrowser'; import { registerLanguageCommand, ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { Position } from 'vs/editor/common/core/position'; @@ -143,28 +143,31 @@ export async function formatDocumentRangeWithProvider( const workerService = accessor.get(IEditorWorkerService); let model: ITextModel; - let validate: () => boolean; + let cts: CancellationTokenSource; if (isCodeEditor(editorOrModel)) { model = editorOrModel.getModel(); - const state = new EditorState(editorOrModel, CodeEditorStateFlag.Value | CodeEditorStateFlag.Position); - validate = () => state.validate(editorOrModel); + cts = new EditorStateCancellationTokenSource(editorOrModel, CodeEditorStateFlag.Value | CodeEditorStateFlag.Position, token); } else { model = editorOrModel; - const versionNow = editorOrModel.getVersionId(); - validate = () => versionNow === editorOrModel.getVersionId(); + cts = new TextModelCancellationTokenSource(editorOrModel, token); } - const rawEdits = await provider.provideDocumentRangeFormattingEdits( - model, - range, - model.getFormattingOptions(), - token - ); - - const edits = await workerService.computeMoreMinimalEdits(model.uri, rawEdits); + let edits: TextEdit[] | undefined; + try { + const rawEdits = await provider.provideDocumentRangeFormattingEdits( + model, + range, + model.getFormattingOptions(), + cts.token + ); + edits = await workerService.computeMoreMinimalEdits(model.uri, rawEdits); + + if (cts.token.isCancellationRequested) { + return true; + } - if (!validate()) { - return true; + } finally { + cts.dispose(); } if (!edits || edits.length === 0) { @@ -237,16 +240,22 @@ export async function formatDocumentWithProvider( cts = new TextModelCancellationTokenSource(editorOrModel, token); } - const rawEdits = await provider.provideDocumentFormattingEdits( - model, - model.getFormattingOptions(), - cts.token - ); + let edits: TextEdit[] | undefined; + try { + const rawEdits = await provider.provideDocumentFormattingEdits( + model, + model.getFormattingOptions(), + cts.token + ); + + edits = await workerService.computeMoreMinimalEdits(model.uri, rawEdits); - const edits = await workerService.computeMoreMinimalEdits(model.uri, rawEdits); + if (cts.token.isCancellationRequested) { + return true; + } - if (cts.token.isCancellationRequested) { - return true; + } finally { + cts.dispose(); } if (!edits || edits.length === 0) { diff --git a/src/vs/editor/contrib/format/formatActions.ts b/src/vs/editor/contrib/format/formatActions.ts index 8b31fb82b..8b2798a49 100644 --- a/src/vs/editor/contrib/format/formatActions.ts +++ b/src/vs/editor/contrib/format/formatActions.ts @@ -6,7 +6,7 @@ import { isNonEmptyArray } from 'vs/base/common/arrays'; import { CancellationToken } from 'vs/base/common/cancellation'; import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import { dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { DisposableStore } from 'vs/base/common/lifecycle'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorAction, registerEditorAction, registerEditorContribution, ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; @@ -30,18 +30,18 @@ class FormatOnType implements editorCommon.IEditorContribution { private static readonly ID = 'editor.contrib.autoFormat'; private readonly _editor: ICodeEditor; - private _callOnDispose: IDisposable[] = []; - private _callOnModel: IDisposable[] = []; + private readonly _callOnDispose = new DisposableStore(); + private readonly _callOnModel = new DisposableStore(); constructor( editor: ICodeEditor, @IEditorWorkerService private readonly _workerService: IEditorWorkerService ) { this._editor = editor; - this._callOnDispose.push(editor.onDidChangeConfiguration(() => this._update())); - this._callOnDispose.push(editor.onDidChangeModel(() => this._update())); - this._callOnDispose.push(editor.onDidChangeModelLanguage(() => this._update())); - this._callOnDispose.push(OnTypeFormattingEditProviderRegistry.onDidChange(this._update, this)); + this._callOnDispose.add(editor.onDidChangeConfiguration(() => this._update())); + this._callOnDispose.add(editor.onDidChangeModel(() => this._update())); + this._callOnDispose.add(editor.onDidChangeModelLanguage(() => this._update())); + this._callOnDispose.add(OnTypeFormattingEditProviderRegistry.onDidChange(this._update, this)); } getId(): string { @@ -49,14 +49,14 @@ class FormatOnType implements editorCommon.IEditorContribution { } dispose(): void { - this._callOnDispose = dispose(this._callOnDispose); - this._callOnModel = dispose(this._callOnModel); + this._callOnDispose.dispose(); + this._callOnModel.dispose(); } private _update(): void { // clean up - this._callOnModel = dispose(this._callOnModel); + this._callOnModel.clear(); // we are disabled if (!this._editor.getConfiguration().contribInfo.formatOnType) { @@ -81,7 +81,7 @@ class FormatOnType implements editorCommon.IEditorContribution { for (let ch of support.autoFormatTriggerCharacters) { triggerChars.add(ch.charCodeAt(0)); } - this._callOnModel.push(this._editor.onDidType((text: string) => { + this._callOnModel.add(this._editor.onDidType((text: string) => { let lastCharCode = text.charCodeAt(text.length - 1); if (triggerChars.has(lastCharCode)) { this._trigger(String.fromCharCode(lastCharCode)); @@ -156,20 +156,17 @@ class FormatOnPaste implements editorCommon.IEditorContribution { private static readonly ID = 'editor.contrib.formatOnPaste'; - private _callOnDispose: IDisposable[]; - private _callOnModel: IDisposable[]; + private readonly _callOnDispose = new DisposableStore(); + private readonly _callOnModel = new DisposableStore(); constructor( private readonly editor: ICodeEditor, @IInstantiationService private readonly _instantiationService: IInstantiationService, ) { - this._callOnDispose = []; - this._callOnModel = []; - - this._callOnDispose.push(editor.onDidChangeConfiguration(() => this._update())); - this._callOnDispose.push(editor.onDidChangeModel(() => this._update())); - this._callOnDispose.push(editor.onDidChangeModelLanguage(() => this._update())); - this._callOnDispose.push(DocumentRangeFormattingEditProviderRegistry.onDidChange(this._update, this)); + this._callOnDispose.add(editor.onDidChangeConfiguration(() => this._update())); + this._callOnDispose.add(editor.onDidChangeModel(() => this._update())); + this._callOnDispose.add(editor.onDidChangeModelLanguage(() => this._update())); + this._callOnDispose.add(DocumentRangeFormattingEditProviderRegistry.onDidChange(this._update, this)); } getId(): string { @@ -177,14 +174,14 @@ class FormatOnPaste implements editorCommon.IEditorContribution { } dispose(): void { - this._callOnDispose = dispose(this._callOnDispose); - this._callOnModel = dispose(this._callOnModel); + this._callOnDispose.dispose(); + this._callOnModel.dispose(); } private _update(): void { // clean up - this._callOnModel = dispose(this._callOnModel); + this._callOnModel.clear(); // we are disabled if (!this.editor.getConfiguration().contribInfo.formatOnPaste) { @@ -201,7 +198,7 @@ class FormatOnPaste implements editorCommon.IEditorContribution { return; } - this._callOnModel.push(this.editor.onDidPaste(range => this._trigger(range))); + this._callOnModel.add(this.editor.onDidPaste(range => this._trigger(range))); } private _trigger(range: Range): void { @@ -251,7 +248,7 @@ class FormatSelectionAction extends EditorAction { super({ id: 'editor.action.formatSelection', label: nls.localize('formatSelection.label', "Format Selection"), - alias: 'Format Code', + alias: 'Format Selection', precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasDocumentSelectionFormattingProvider), kbOpts: { kbExpr: ContextKeyExpr.and(EditorContextKeys.editorTextFocus, EditorContextKeys.hasDocumentSelectionFormattingProvider), diff --git a/src/vs/editor/contrib/goToDefinition/goToDefinitionCommands.ts b/src/vs/editor/contrib/goToDefinition/goToDefinitionCommands.ts index 398cb4c88..baad3f0bb 100644 --- a/src/vs/editor/contrib/goToDefinition/goToDefinitionCommands.ts +++ b/src/vs/editor/contrib/goToDefinition/goToDefinitionCommands.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { alert } from 'vs/base/browser/ui/aria/aria'; -import { createCancelablePromise } from 'vs/base/common/async'; +import { createCancelablePromise, raceCancellation } from 'vs/base/common/async'; import { CancellationToken } from 'vs/base/common/cancellation'; import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import * as platform from 'vs/base/common/platform'; @@ -25,10 +25,11 @@ import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { INotificationService } from 'vs/platform/notification/common/notification'; -import { IProgressService } from 'vs/platform/progress/common/progress'; +import { IEditorProgressService } from 'vs/platform/progress/common/progress'; import { getDefinitionsAtPosition, getImplementationsAtPosition, getTypeDefinitionsAtPosition, getDeclarationsAtPosition } from './goToDefinition'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { EditorStateCancellationTokenSource, CodeEditorStateFlag } from 'vs/editor/browser/core/editorState'; +import { ISymbolNavigationService } from 'vs/editor/contrib/goToDefinition/goToDefinitionResultsNavigation'; export class DefinitionActionConfig { @@ -57,16 +58,17 @@ export class DefinitionAction extends EditorAction { } const notificationService = accessor.get(INotificationService); const editorService = accessor.get(ICodeEditorService); - const progressService = accessor.get(IProgressService); + const progressService = accessor.get(IEditorProgressService); + const symbolNavService = accessor.get(ISymbolNavigationService); const model = editor.getModel(); const pos = editor.getPosition(); const cts = new EditorStateCancellationTokenSource(editor, CodeEditorStateFlag.Value | CodeEditorStateFlag.Position); - const definitionPromise = this._getTargetLocationForPosition(model, pos, cts.token).then(async references => { + const definitionPromise = raceCancellation(this._getTargetLocationForPosition(model, pos, cts.token), cts.token).then(async references => { - if (cts.token.isCancellationRequested || model.isDisposed() || editor.getModel() !== model) { + if (!references || model.isDisposed()) { // new model, no more model return; } @@ -102,7 +104,7 @@ export class DefinitionAction extends EditorAction { } else { // handle multile results - return this._onResult(editorService, editor, new ReferencesModel(result)); + return this._onResult(editorService, symbolNavService, editor, new ReferencesModel(result)); } }, (err) => { @@ -130,7 +132,7 @@ export class DefinitionAction extends EditorAction { return model.references.length > 1 ? nls.localize('meta.title', " – {0} definitions", model.references.length) : ''; } - private async _onResult(editorService: ICodeEditorService, editor: ICodeEditor, model: ReferencesModel): Promise { + private async _onResult(editorService: ICodeEditorService, symbolNavService: ISymbolNavigationService, editor: ICodeEditor, model: ReferencesModel): Promise { const msg = model.getAriaMessage(); alert(msg); @@ -150,6 +152,12 @@ export class DefinitionAction extends EditorAction { } else { model.dispose(); } + + // keep remaining locations around when using + // 'goto'-mode + if (gotoLocation.multiple === 'goto') { + symbolNavService.put(next); + } } } @@ -168,7 +176,6 @@ export class DefinitionAction extends EditorAction { resource: reference.uri, options: { selection: Range.collapseToStart(range), - revealIfOpened: true, revealInCenterIfOutsideViewport: true } }, editor, sideBySide); diff --git a/src/vs/editor/contrib/goToDefinition/goToDefinitionMouse.ts b/src/vs/editor/contrib/goToDefinition/goToDefinitionMouse.ts index 737f6c9eb..717c7ba4d 100644 --- a/src/vs/editor/contrib/goToDefinition/goToDefinitionMouse.ts +++ b/src/vs/editor/contrib/goToDefinition/goToDefinitionMouse.ts @@ -10,13 +10,13 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { onUnexpectedError } from 'vs/base/common/errors'; import { MarkdownString } from 'vs/base/common/htmlContent'; import { IModeService } from 'vs/editor/common/services/modeService'; -import { Range } from 'vs/editor/common/core/range'; +import { Range, IRange } from 'vs/editor/common/core/range'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { DefinitionProviderRegistry, LocationLink } from 'vs/editor/common/modes'; import { ICodeEditor, IMouseTarget, MouseTargetType } from 'vs/editor/browser/editorBrowser'; import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import { getDefinitionsAtPosition } from './goToDefinition'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { DisposableStore } from 'vs/base/common/lifecycle'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { editorActiveLinkForeground } from 'vs/platform/theme/common/colorRegistry'; @@ -33,7 +33,7 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC static MAX_SOURCE_PREVIEW_LINES = 8; private readonly editor: ICodeEditor; - private toUnhook: IDisposable[]; + private readonly toUnhook = new DisposableStore(); private decorations: string[]; private currentWordUnderMouse: IWordAtPosition | null; private previousPromise: CancelablePromise | null; @@ -43,19 +43,18 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC @ITextModelService private readonly textModelResolverService: ITextModelService, @IModeService private readonly modeService: IModeService ) { - this.toUnhook = []; this.decorations = []; this.editor = editor; this.previousPromise = null; let linkGesture = new ClickLinkGesture(editor); - this.toUnhook.push(linkGesture); + this.toUnhook.add(linkGesture); - this.toUnhook.push(linkGesture.onMouseMoveOrRelevantKeyDown(([mouseEvent, keyboardEvent]) => { + this.toUnhook.add(linkGesture.onMouseMoveOrRelevantKeyDown(([mouseEvent, keyboardEvent]) => { this.startFindDefinition(mouseEvent, withNullAsUndefined(keyboardEvent)); })); - this.toUnhook.push(linkGesture.onExecute((mouseEvent: ClickLinkMouseEvent) => { + this.toUnhook.add(linkGesture.onExecute((mouseEvent: ClickLinkMouseEvent) => { if (this.isEnabled(mouseEvent)) { this.gotoDefinition(mouseEvent.target, mouseEvent.hasSideBySideModifier).then(() => { this.removeDecorations(); @@ -66,7 +65,7 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC } })); - this.toUnhook.push(linkGesture.onCancel(() => { + this.toUnhook.add(linkGesture.onCancel(() => { this.removeDecorations(); this.currentWordUnderMouse = null; })); @@ -150,7 +149,7 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC return; } - const previewValue = this.getPreviewValue(textEditorModel, startLineNumber); + const previewValue = this.getPreviewValue(textEditorModel, startLineNumber, result); let wordRange: Range; if (result.originSelectionRange) { @@ -159,7 +158,7 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC wordRange = new Range(position.lineNumber, word.startColumn, position.lineNumber, word.endColumn); } - const modeId = this.modeService.getModeIdByFilepathOrFirstLine(textEditorModel.uri.fsPath); + const modeId = this.modeService.getModeIdByFilepathOrFirstLine(textEditorModel.uri); this.addDecoration( wordRange, new MarkdownString().appendCodeblock(modeId ? modeId : '', previewValue) @@ -170,8 +169,8 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC }).then(undefined, onUnexpectedError); } - private getPreviewValue(textEditorModel: ITextModel, startLineNumber: number) { - let rangeToUse = this.getPreviewRangeBasedOnBrackets(textEditorModel, startLineNumber); + private getPreviewValue(textEditorModel: ITextModel, startLineNumber: number, result: LocationLink) { + let rangeToUse = result.targetSelectionRange ? result.range : this.getPreviewRangeBasedOnBrackets(textEditorModel, startLineNumber); const numberOfLinesInRange = rangeToUse.endLineNumber - rangeToUse.startLineNumber; if (numberOfLinesInRange >= GotoDefinitionWithMouseEditorContribution.MAX_SOURCE_PREVIEW_LINES) { rangeToUse = this.getPreviewRangeBasedOnIndentation(textEditorModel, startLineNumber); @@ -181,7 +180,7 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC return previewValue; } - private stripIndentationFromPreviewRange(textEditorModel: ITextModel, startLineNumber: number, previewRange: Range) { + private stripIndentationFromPreviewRange(textEditorModel: ITextModel, startLineNumber: number, previewRange: IRange) { const startIndent = textEditorModel.getLineFirstNonWhitespaceColumn(startLineNumber); let minIndent = startIndent; @@ -294,7 +293,7 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC private gotoDefinition(target: IMouseTarget, sideBySide: boolean): Promise { this.editor.setPosition(target.position!); - const action = new DefinitionAction(new DefinitionActionConfig(sideBySide, false, true, false), { alias: '', label: '', id: '', precondition: null }); + const action = new DefinitionAction(new DefinitionActionConfig(sideBySide, false, true, false), { alias: '', label: '', id: '', precondition: undefined }); return this.editor.invokeWithinContext(accessor => action.run(accessor, this.editor)); } @@ -303,7 +302,7 @@ class GotoDefinitionWithMouseEditorContribution implements editorCommon.IEditorC } public dispose(): void { - this.toUnhook = dispose(this.toUnhook); + this.toUnhook.dispose(); } } diff --git a/src/vs/editor/contrib/goToDefinition/goToDefinitionResultsNavigation.ts b/src/vs/editor/contrib/goToDefinition/goToDefinitionResultsNavigation.ts new file mode 100644 index 000000000..cb35c7217 --- /dev/null +++ b/src/vs/editor/contrib/goToDefinition/goToDefinitionResultsNavigation.ts @@ -0,0 +1,216 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ReferencesModel, OneReference } from 'vs/editor/contrib/referenceSearch/referencesModel'; +import { RawContextKey, IContextKeyService, IContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { createDecorator, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { KeybindingWeight, KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { KeyCode } from 'vs/base/common/keyCodes'; +import { registerEditorCommand, EditorCommand } from 'vs/editor/browser/editorExtensions'; +import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; +import { Range } from 'vs/editor/common/core/range'; +import { dispose, IDisposable, combinedDisposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { Emitter, Event } from 'vs/base/common/event'; +import { localize } from 'vs/nls'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { INotificationService } from 'vs/platform/notification/common/notification'; + +export const ctxHasSymbols = new RawContextKey('hasSymbols', false); + +export const ISymbolNavigationService = createDecorator('ISymbolNavigationService'); + +export interface ISymbolNavigationService { + _serviceBrand: any; + reset(): void; + put(anchor: OneReference): void; + revealNext(source: ICodeEditor): Promise; +} + +class SymbolNavigationService implements ISymbolNavigationService { + + _serviceBrand: any; + + private readonly _ctxHasSymbols: IContextKey; + + private _currentModel?: ReferencesModel = undefined; + private _currentIdx: number = -1; + private _currentState?: IDisposable; + private _currentMessage?: IDisposable; + private _ignoreEditorChange: boolean = false; + + constructor( + @IContextKeyService contextKeyService: IContextKeyService, + @ICodeEditorService private readonly _editorService: ICodeEditorService, + @INotificationService private readonly _notificationService: INotificationService, + @IKeybindingService private readonly _keybindingService: IKeybindingService, + ) { + this._ctxHasSymbols = ctxHasSymbols.bindTo(contextKeyService); + } + + reset(): void { + this._ctxHasSymbols.reset(); + dispose(this._currentState); + dispose(this._currentMessage); + this._currentModel = undefined; + this._currentIdx = -1; + } + + put(anchor: OneReference): void { + const refModel = anchor.parent.parent; + + if (refModel.references.length <= 1) { + this.reset(); + return; + } + + this._currentModel = refModel; + this._currentIdx = refModel.references.indexOf(anchor); + this._ctxHasSymbols.set(true); + this._showMessage(); + + const editorState = new EditorState(this._editorService); + const listener = editorState.onDidChange(_ => { + + if (this._ignoreEditorChange) { + return; + } + + const editor = this._editorService.getActiveCodeEditor(); + if (!editor) { + return; + } + const model = editor.getModel(); + const position = editor.getPosition(); + if (!model || !position) { + return; + } + + let seenUri: boolean = false; + let seenPosition: boolean = false; + for (const reference of refModel.references) { + if (reference.uri.toString() === model.uri.toString()) { + seenUri = true; + seenPosition = seenPosition || Range.containsPosition(reference.range, position); + } else if (seenUri) { + break; + } + } + if (!seenUri || !seenPosition) { + this.reset(); + } + }); + + this._currentState = combinedDisposable(editorState, listener); + } + + revealNext(source: ICodeEditor): Promise { + if (!this._currentModel) { + return Promise.resolve(); + } + + // get next result and advance + this._currentIdx += 1; + this._currentIdx %= this._currentModel.references.length; + const reference = this._currentModel.references[this._currentIdx]; + + // status + this._showMessage(); + + // open editor, ignore events while that happens + this._ignoreEditorChange = true; + return this._editorService.openCodeEditor({ + resource: reference.uri, + options: { + selection: Range.collapseToStart(reference.range), + revealInCenterIfOutsideViewport: true + } + }, source).finally(() => { + this._ignoreEditorChange = false; + }); + + } + + private _showMessage(): void { + + dispose(this._currentMessage); + + const kb = this._keybindingService.lookupKeybinding('editor.gotoNextSymbolFromResult'); + const message = kb + ? localize('location.kb', "Symbol {0} of {1}, {2} for next", this._currentIdx + 1, this._currentModel!.references.length, kb.getLabel()) + : localize('location', "Symbol {0} of {1}", this._currentIdx + 1, this._currentModel!.references.length); + + this._currentMessage = this._notificationService.status(message); + } +} + +registerSingleton(ISymbolNavigationService, SymbolNavigationService, true); + +registerEditorCommand(new class extends EditorCommand { + + constructor() { + super({ + id: 'editor.gotoNextSymbolFromResult', + precondition: ContextKeyExpr.and( + ctxHasSymbols, + ContextKeyExpr.equals('config.editor.gotoLocation.multiple', 'goto') + ), + kbOpts: { + weight: KeybindingWeight.EditorContrib, + primary: KeyCode.F12 + } + }); + } + + runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor): void | Promise { + return accessor.get(ISymbolNavigationService).revealNext(editor); + } +}); + +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: 'editor.gotoNextSymbolFromResult.cancel', + weight: KeybindingWeight.EditorContrib, + when: ctxHasSymbols, + primary: KeyCode.Escape, + handler(accessor) { + accessor.get(ISymbolNavigationService).reset(); + } +}); + +// + +class EditorState { + + private readonly _listener = new Map(); + private readonly _disposables = new DisposableStore(); + + private readonly _onDidChange = new Emitter<{ editor: ICodeEditor }>(); + readonly onDidChange: Event<{ editor: ICodeEditor }> = this._onDidChange.event; + + constructor(@ICodeEditorService editorService: ICodeEditorService) { + this._disposables.add(editorService.onCodeEditorRemove(this._onDidRemoveEditor, this)); + this._disposables.add(editorService.onCodeEditorAdd(this._onDidAddEditor, this)); + editorService.listCodeEditors().forEach(this._onDidAddEditor, this); + } + + dispose(): void { + this._disposables.dispose(); + this._onDidChange.dispose(); + this._listener.forEach(dispose); + } + + private _onDidAddEditor(editor: ICodeEditor): void { + this._listener.set(editor, combinedDisposable( + editor.onDidChangeCursorPosition(_ => this._onDidChange.fire({ editor })), + editor.onDidChangeModelContent(_ => this._onDidChange.fire({ editor })), + )); + } + + private _onDidRemoveEditor(editor: ICodeEditor): void { + dispose(this._listener.get(editor)); + this._listener.delete(editor); + } +} diff --git a/src/vs/editor/contrib/gotoError/gotoError.ts b/src/vs/editor/contrib/gotoError/gotoError.ts index 4a9a2aa11..c16b9be9a 100644 --- a/src/vs/editor/contrib/gotoError/gotoError.ts +++ b/src/vs/editor/contrib/gotoError/gotoError.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import { Emitter } from 'vs/base/common/event'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { DisposableStore } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IMarker, IMarkerService, MarkerSeverity } from 'vs/platform/markers/common/markers'; @@ -32,7 +32,7 @@ class MarkerModel { private readonly _editor: ICodeEditor; private _markers: IMarker[]; private _nextIdx: number; - private _toUnbind: IDisposable[]; + private readonly _toUnbind = new DisposableStore(); private _ignoreSelectionChange: boolean; private readonly _onCurrentMarkerChanged: Emitter; private readonly _onMarkerSetChanged: Emitter; @@ -41,15 +41,14 @@ class MarkerModel { this._editor = editor; this._markers = []; this._nextIdx = -1; - this._toUnbind = []; this._ignoreSelectionChange = false; this._onCurrentMarkerChanged = new Emitter(); this._onMarkerSetChanged = new Emitter(); this.setMarkers(markers); // listen on editor - this._toUnbind.push(this._editor.onDidDispose(() => this.dispose())); - this._toUnbind.push(this._editor.onDidChangeCursorPosition(() => { + this._toUnbind.add(this._editor.onDidDispose(() => this.dispose())); + this._toUnbind.add(this._editor.onDidChangeCursorPosition(() => { if (this._ignoreSelectionChange) { return; } @@ -190,7 +189,7 @@ class MarkerModel { } public dispose(): void { - this._toUnbind = dispose(this._toUnbind); + this._toUnbind.dispose(); } } @@ -206,7 +205,7 @@ export class MarkerController implements editorCommon.IEditorContribution { private _model: MarkerModel | null = null; private _widget: MarkerNavigationWidget | null = null; private readonly _widgetVisible: IContextKey; - private _disposeOnClose: IDisposable[] = []; + private readonly _disposeOnClose = new DisposableStore(); constructor( editor: ICodeEditor, @@ -226,11 +225,12 @@ export class MarkerController implements editorCommon.IEditorContribution { public dispose(): void { this._cleanUp(); + this._disposeOnClose.dispose(); } private _cleanUp(): void { this._widgetVisible.reset(); - this._disposeOnClose = dispose(this._disposeOnClose); + this._disposeOnClose.clear(); this._widget = null; this._model = null; } @@ -255,19 +255,21 @@ export class MarkerController implements editorCommon.IEditorContribution { this._widgetVisible.set(true); this._widget.onDidClose(() => this._cleanUp(), this, this._disposeOnClose); - this._disposeOnClose.push(this._model); - this._disposeOnClose.push(this._widget); - this._disposeOnClose.push(...actions); - this._disposeOnClose.push(this._widget.onDidSelectRelatedInformation(related => { + this._disposeOnClose.add(this._model); + this._disposeOnClose.add(this._widget); + for (const action of actions) { + this._disposeOnClose.add(action); + } + this._disposeOnClose.add(this._widget.onDidSelectRelatedInformation(related => { this._editorService.openCodeEditor({ resource: related.resource, options: { pinned: true, revealIfOpened: true, selection: Range.lift(related).collapseToStart() } }, this._editor).then(undefined, onUnexpectedError); this.closeMarkersNavigation(false); })); - this._disposeOnClose.push(this._editor.onDidChangeModel(() => this._cleanUp())); + this._disposeOnClose.add(this._editor.onDidChangeModel(() => this._cleanUp())); - this._disposeOnClose.push(this._model.onCurrentMarkerChanged(marker => { + this._disposeOnClose.add(this._model.onCurrentMarkerChanged(marker => { if (!marker || !this._model) { this._cleanUp(); } else { @@ -279,7 +281,7 @@ export class MarkerController implements editorCommon.IEditorContribution { }); } })); - this._disposeOnClose.push(this._model.onMarkerSetChanged(() => { + this._disposeOnClose.add(this._model.onMarkerSetChanged(() => { if (!this._widget || !this._widget.position || !this._model) { return; } @@ -428,7 +430,7 @@ export class NextMarkerAction extends MarkerNavigationAction { super(true, false, { id: NextMarkerAction.ID, label: NextMarkerAction.LABEL, - alias: 'Go to Next Error or Warning', + alias: 'Go to Next Problem (Error, Warning, Info)', precondition: EditorContextKeys.writable, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.Alt | KeyCode.F8, weight: KeybindingWeight.EditorContrib } }); @@ -442,7 +444,7 @@ class PrevMarkerAction extends MarkerNavigationAction { super(false, false, { id: PrevMarkerAction.ID, label: PrevMarkerAction.LABEL, - alias: 'Go to Previous Error or Warning', + alias: 'Go to Previous Problem (Error, Warning, Info)', precondition: EditorContextKeys.writable, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.Shift | KeyMod.Alt | KeyCode.F8, weight: KeybindingWeight.EditorContrib } }); @@ -454,7 +456,7 @@ class NextMarkerInFilesAction extends MarkerNavigationAction { super(true, true, { id: 'editor.action.marker.nextInFiles', label: nls.localize('markerAction.nextInFiles.label', "Go to Next Problem in Files (Error, Warning, Info)"), - alias: 'Go to Next Error or Warning in Files', + alias: 'Go to Next Problem in Files (Error, Warning, Info)', precondition: EditorContextKeys.writable, kbOpts: { kbExpr: EditorContextKeys.focus, @@ -470,7 +472,7 @@ class PrevMarkerInFilesAction extends MarkerNavigationAction { super(false, true, { id: 'editor.action.marker.prevInFiles', label: nls.localize('markerAction.previousInFiles.label', "Go to Previous Problem in Files (Error, Warning, Info)"), - alias: 'Go to Previous Error or Warning in Files', + alias: 'Go to Previous Problem in Files (Error, Warning, Info)', precondition: EditorContextKeys.writable, kbOpts: { kbExpr: EditorContextKeys.focus, diff --git a/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts b/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts index b630d4fc2..7d93dc2fb 100644 --- a/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts +++ b/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts @@ -6,15 +6,14 @@ import 'vs/css!./media/gotoErrorWidget'; import * as nls from 'vs/nls'; import * as dom from 'vs/base/browser/dom'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle'; import { IMarker, MarkerSeverity, IRelatedInformation } from 'vs/platform/markers/common/markers'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; -import { registerColor, oneOf, textLinkForeground } from 'vs/platform/theme/common/colorRegistry'; +import { registerColor, oneOf, textLinkForeground, editorErrorForeground, editorErrorBorder, editorWarningForeground, editorWarningBorder, editorInfoForeground, editorInfoBorder } from 'vs/platform/theme/common/colorRegistry'; import { IThemeService, ITheme, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { Color } from 'vs/base/common/color'; -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'; import { ScrollType } from 'vs/editor/common/editorCommon'; @@ -26,7 +25,7 @@ import { basename } from 'vs/base/common/resources'; import { IAction } from 'vs/base/common/actions'; import { IActionBarOptions, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar'; import { peekViewTitleForeground, peekViewTitleInfoForeground } from 'vs/editor/contrib/referenceSearch/referencesWidget'; -import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; +import { SeverityIcon } from 'vs/platform/severityIcon/common/severityIcon'; class MessageWidget { @@ -168,8 +167,9 @@ export class MarkerNavigationWidget extends PeekViewWidget { private _parentContainer: HTMLElement; private _container: HTMLElement; + private _icon: HTMLElement; private _message: MessageWidget; - private _callOnDispose: IDisposable[] = []; + private readonly _callOnDispose = new DisposableStore(); private _severity: MarkerSeverity; private _backgroundColor?: Color; private _onDidSelectRelatedInformation = new Emitter(); @@ -179,7 +179,7 @@ export class MarkerNavigationWidget extends PeekViewWidget { constructor( editor: ICodeEditor, - private readonly actions: IAction[], + private readonly actions: ReadonlyArray, private readonly _themeService: IThemeService ) { super(editor, { showArrow: true, showFrame: true, isAccessible: true }); @@ -187,7 +187,7 @@ export class MarkerNavigationWidget extends PeekViewWidget { this._backgroundColor = Color.white; this._applyTheme(_themeService.getTheme()); - this._callOnDispose.push(_themeService.onThemeChange(this._applyTheme.bind(this))); + this._callOnDispose.add(_themeService.onThemeChange(this._applyTheme.bind(this))); this.create(); } @@ -218,7 +218,7 @@ export class MarkerNavigationWidget extends PeekViewWidget { } dispose(): void { - this._callOnDispose = dispose(this._callOnDispose); + this._callOnDispose.dispose(); super.dispose(); } @@ -231,6 +231,10 @@ export class MarkerNavigationWidget extends PeekViewWidget { this._actionbarWidget.push(this.actions, { label: false, icon: true }); } + protected _fillTitleIcon(container: HTMLElement): void { + this._icon = dom.append(container, dom.$('')); + } + protected _getActionBarOptions(): IActionBarOptions { return { orientation: ActionsOrientation.HORIZONTAL_REVERSE @@ -247,7 +251,7 @@ export class MarkerNavigationWidget extends PeekViewWidget { container.appendChild(this._container); this._message = new MessageWidget(this._container, this.editor, related => this._onDidSelectRelatedInformation.fire(related)); - this._disposables.push(this._message); + this._disposables.add(this._message); } show(where: Position, heightInLines: number): void { @@ -278,19 +282,9 @@ export class MarkerNavigationWidget extends PeekViewWidget { : nls.localize('change', "{0} of {1} problem", markerIdx, markerCount); this.setTitle(basename(model.uri), detail); } - let headingIconClassName = 'error'; - if (this._severity === MarkerSeverity.Warning) { - headingIconClassName = 'warning'; - } else if (this._severity === MarkerSeverity.Info) { - headingIconClassName = 'info'; - } - this.setTitleIcon(headingIconClassName); + this._icon.className = SeverityIcon.className(MarkerSeverity.toSeverity(this._severity)); this.editor.revealPositionInCenter(position, ScrollType.Smooth); - - if (this.editor.getConfiguration().accessibilitySupport !== AccessibilitySupport.Disabled) { - this.focus(); - } } updateMarker(marker: IMarker): void { diff --git a/src/vs/editor/contrib/gotoError/media/gotoErrorWidget.css b/src/vs/editor/contrib/gotoError/media/gotoErrorWidget.css index 5b5b607e8..6680fb166 100644 --- a/src/vs/editor/contrib/gotoError/media/gotoErrorWidget.css +++ b/src/vs/editor/contrib/gotoError/media/gotoErrorWidget.css @@ -5,28 +5,10 @@ /* marker zone */ -.monaco-editor .peekview-widget .head .peekview-title .icon.warning { - background: url('status-warning.svg') center center no-repeat; -} - -.monaco-editor .peekview-widget .head .peekview-title .icon.error { - background: url('status-error.svg') center center no-repeat; -} - -.monaco-editor .peekview-widget .head .peekview-title .icon.info { - background: url('status-info.svg') center center no-repeat; -} - -.vs-dark .monaco-editor .peekview-widget .head .peekview-title .icon.warning { - background: url('status-warning-inverse.svg') center center no-repeat; -} - -.vs-dark .monaco-editor .peekview-widget .head .peekview-title .icon.error { - background: url('status-error-inverse.svg') center center no-repeat; -} - -.vs-dark .monaco-editor .peekview-widget .head .peekview-title .icon.info { - background: url('status-info-inverse.svg') center center no-repeat; +.monaco-editor .peekview-widget .head .peekview-title .severity-icon { + display: inline-block; + vertical-align: text-top; + margin-right: 4px; } .monaco-editor .marker-widget { diff --git a/src/vs/editor/contrib/gotoError/media/status-error-inverse.svg b/src/vs/editor/contrib/gotoError/media/status-error-inverse.svg deleted file mode 100644 index 3c852a7ff..000000000 --- a/src/vs/editor/contrib/gotoError/media/status-error-inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/gotoError/media/status-error.svg b/src/vs/editor/contrib/gotoError/media/status-error.svg deleted file mode 100644 index a1ddb39fe..000000000 --- a/src/vs/editor/contrib/gotoError/media/status-error.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/gotoError/media/status-info-inverse.svg b/src/vs/editor/contrib/gotoError/media/status-info-inverse.svg deleted file mode 100644 index d38c363e0..000000000 --- a/src/vs/editor/contrib/gotoError/media/status-info-inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/gotoError/media/status-info.svg b/src/vs/editor/contrib/gotoError/media/status-info.svg deleted file mode 100644 index 6e2e22f67..000000000 --- a/src/vs/editor/contrib/gotoError/media/status-info.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/gotoError/media/status-warning-inverse.svg b/src/vs/editor/contrib/gotoError/media/status-warning-inverse.svg deleted file mode 100644 index df44e61b3..000000000 --- a/src/vs/editor/contrib/gotoError/media/status-warning-inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/gotoError/media/status-warning.svg b/src/vs/editor/contrib/gotoError/media/status-warning.svg deleted file mode 100644 index f4e2a84b0..000000000 --- a/src/vs/editor/contrib/gotoError/media/status-warning.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/hover/hover.css b/src/vs/editor/contrib/hover/hover.css index ebb85f951..62da9b519 100644 --- a/src/vs/editor/contrib/hover/hover.css +++ b/src/vs/editor/contrib/hover/hover.css @@ -29,6 +29,7 @@ .monaco-editor-hover .markdown-hover > .hover-contents:not(.code-hover-contents) { max-width: 500px; + word-wrap: break-word; } .monaco-editor-hover p, diff --git a/src/vs/editor/contrib/hover/hover.ts b/src/vs/editor/contrib/hover/hover.ts index 8c7f8bd52..8dcf20dd2 100644 --- a/src/vs/editor/contrib/hover/hover.ts +++ b/src/vs/editor/contrib/hover/hover.ts @@ -7,7 +7,7 @@ import 'vs/css!./hover'; import * as nls from 'vs/nls'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IEmptyContentData } from 'vs/editor/browser/controller/mouseTarget'; import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; import { EditorAction, ServicesAccessor, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions'; @@ -25,16 +25,13 @@ import { editorHoverBackground, editorHoverBorder, editorHoverHighlight, textCod import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDecorationService'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService'; -import { ICommandService } from 'vs/platform/commands/common/commands'; import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; export class ModesHoverController implements IEditorContribution { private static readonly ID = 'editor.contrib.hover'; - private _toUnhook: IDisposable[]; + private readonly _toUnhook = new DisposableStore(); private readonly _didChangeConfigurationHandler: IDisposable; private _contentWidget: ModesContentHoverWidget; @@ -68,13 +65,8 @@ export class ModesHoverController implements IEditorContribution { @IModeService private readonly _modeService: IModeService, @IMarkerDecorationsService private readonly _markerDecorationsService: IMarkerDecorationsService, @IKeybindingService private readonly _keybindingService: IKeybindingService, - @IContextMenuService private readonly _contextMenuService: IContextMenuService, - @IBulkEditService private readonly _bulkEditService: IBulkEditService, - @ICommandService private readonly _commandService: ICommandService, @IThemeService private readonly _themeService: IThemeService ) { - this._toUnhook = []; - this._isMouseDown = false; this._hoverClicked = false; @@ -96,22 +88,22 @@ export class ModesHoverController implements IEditorContribution { this._isHoverEnabled = hoverOpts.enabled; this._isHoverSticky = hoverOpts.sticky; if (this._isHoverEnabled) { - this._toUnhook.push(this._editor.onMouseDown((e: IEditorMouseEvent) => this._onEditorMouseDown(e))); - this._toUnhook.push(this._editor.onMouseUp((e: IEditorMouseEvent) => this._onEditorMouseUp(e))); - this._toUnhook.push(this._editor.onMouseMove((e: IEditorMouseEvent) => this._onEditorMouseMove(e))); - this._toUnhook.push(this._editor.onKeyDown((e: IKeyboardEvent) => this._onKeyDown(e))); - this._toUnhook.push(this._editor.onDidChangeModelDecorations(() => this._onModelDecorationsChanged())); + this._toUnhook.add(this._editor.onMouseDown((e: IEditorMouseEvent) => this._onEditorMouseDown(e))); + this._toUnhook.add(this._editor.onMouseUp((e: IEditorMouseEvent) => this._onEditorMouseUp(e))); + this._toUnhook.add(this._editor.onMouseMove((e: IEditorMouseEvent) => this._onEditorMouseMove(e))); + this._toUnhook.add(this._editor.onKeyDown((e: IKeyboardEvent) => this._onKeyDown(e))); + this._toUnhook.add(this._editor.onDidChangeModelDecorations(() => this._onModelDecorationsChanged())); } else { - this._toUnhook.push(this._editor.onMouseMove(hideWidgetsEventHandler)); + this._toUnhook.add(this._editor.onMouseMove(hideWidgetsEventHandler)); } - this._toUnhook.push(this._editor.onMouseLeave(hideWidgetsEventHandler)); - this._toUnhook.push(this._editor.onDidChangeModel(hideWidgetsEventHandler)); - this._toUnhook.push(this._editor.onDidScrollChange((e: IScrollEvent) => this._onEditorScrollChanged(e))); + this._toUnhook.add(this._editor.onMouseLeave(hideWidgetsEventHandler)); + this._toUnhook.add(this._editor.onDidChangeModel(hideWidgetsEventHandler)); + this._toUnhook.add(this._editor.onDidScrollChange((e: IScrollEvent) => this._onEditorScrollChanged(e))); } private _unhookEvents(): void { - this._toUnhook = dispose(this._toUnhook); + this._toUnhook.clear(); } private _onModelDecorationsChanged(): void { @@ -213,7 +205,7 @@ export class ModesHoverController implements IEditorContribution { } private _createHoverWidget() { - this._contentWidget = new ModesContentHoverWidget(this._editor, this._markerDecorationsService, this._themeService, this._keybindingService, this._contextMenuService, this._bulkEditService, this._commandService, this._modeService, this._openerService); + this._contentWidget = new ModesContentHoverWidget(this._editor, this._markerDecorationsService, this._themeService, this._keybindingService, this._modeService, this._openerService); this._glyphWidget = new ModesGlyphHoverWidget(this._editor, this._modeService, this._openerService); } @@ -227,6 +219,7 @@ export class ModesHoverController implements IEditorContribution { public dispose(): void { this._unhookEvents(); + this._toUnhook.dispose(); this._didChangeConfigurationHandler.dispose(); if (this._glyphWidget) { @@ -251,7 +244,7 @@ class ShowHoverAction extends EditorAction { ] }, "Show Hover"), alias: 'Show Hover', - precondition: null, + precondition: undefined, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_I), diff --git a/src/vs/editor/contrib/hover/hoverWidgets.ts b/src/vs/editor/contrib/hover/hoverWidgets.ts index 714525067..6489db5a9 100644 --- a/src/vs/editor/contrib/hover/hoverWidgets.ts +++ b/src/vs/editor/contrib/hover/hoverWidgets.ts @@ -8,7 +8,6 @@ import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; import { Widget } from 'vs/base/browser/ui/widget'; import { KeyCode } from 'vs/base/common/keyCodes'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import * as editorBrowser from 'vs/editor/browser/editorBrowser'; import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; import { Position } from 'vs/editor/common/core/position'; @@ -25,7 +24,6 @@ export class ContentHoverWidget extends Widget implements editorBrowser.IContent protected _showAtRange: Range | null; private _stoleFocus: boolean; private readonly scrollbar: DomScrollableElement; - private disposables: IDisposable[] = []; // Editor.IContentWidget.allowEditorOverflow public allowEditorOverflow = true; @@ -53,7 +51,7 @@ export class ContentHoverWidget extends Widget implements editorBrowser.IContent this._domNode.className = 'monaco-editor-hover-content'; this.scrollbar = new DomScrollableElement(this._domNode, {}); - this.disposables.push(this.scrollbar); + this._register(this.scrollbar); this._containerDomNode.appendChild(this.scrollbar.getDomNode()); this.onkeydown(this._containerDomNode, (e: IKeyboardEvent) => { @@ -129,7 +127,6 @@ export class ContentHoverWidget extends Widget implements editorBrowser.IContent public dispose(): void { this._editor.removeContentWidget(this); - this.disposables = dispose(this.disposables); super.dispose(); } diff --git a/src/vs/editor/contrib/hover/modesContentHover.ts b/src/vs/editor/contrib/hover/modesContentHover.ts index f66e00856..7bc5a7fb0 100644 --- a/src/vs/editor/contrib/hover/modesContentHover.ts +++ b/src/vs/editor/contrib/hover/modesContentHover.ts @@ -8,7 +8,7 @@ import * as dom from 'vs/base/browser/dom'; import { CancellationToken } from 'vs/base/common/cancellation'; import { Color, RGBA } from 'vs/base/common/color'; import { IMarkdownString, MarkdownString, isEmptyMarkdownString, markedStringsEquals } from 'vs/base/common/htmlContent'; -import { Disposable, IDisposable, combinedDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, toDisposable, DisposableStore, combinedDisposable, MutableDisposable } from 'vs/base/common/lifecycle'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { Position } from 'vs/editor/common/core/position'; import { IRange, Range } from 'vs/editor/common/core/range'; @@ -31,16 +31,11 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { IOpenerService, NullOpenerService } from 'vs/platform/opener/common/opener'; import { MarkerController, NextMarkerAction } from 'vs/editor/contrib/gotoError/gotoError'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService'; -import { ICommandService } from 'vs/platform/commands/common/commands'; import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async'; -import { getCodeActions } from 'vs/editor/contrib/codeAction/codeAction'; -import { applyCodeAction, QuickFixAction } from 'vs/editor/contrib/codeAction/codeActionCommands'; -import { Action } from 'vs/base/common/actions'; +import { getCodeActions, CodeActionSet } from 'vs/editor/contrib/codeAction/codeAction'; +import { QuickFixAction, QuickFixController } from 'vs/editor/contrib/codeAction/codeActionCommands'; import { CodeActionKind } from 'vs/editor/contrib/codeAction/codeActionTrigger'; import { IModeService } from 'vs/editor/common/services/modeService'; -import { withNullAsUndefined } from 'vs/base/common/types'; import { IIdentifiedSingleEditOperation } from 'vs/editor/common/model'; const $ = dom.$; @@ -68,14 +63,13 @@ class ModesContentComputer implements IHoverComputer { private readonly _editor: ICodeEditor; private _result: HoverPart[]; - private _range: Range | null; + private _range?: Range; constructor( editor: ICodeEditor, private readonly _markerDecorationsService: IMarkerDecorationsService ) { this._editor = editor; - this._range = null; } setRange(range: Range): void { @@ -183,7 +177,7 @@ class ModesContentComputer implements IHoverComputer { private _getLoadingMessage(): HoverPart { return { - range: withNullAsUndefined(this._range), + range: this._range, contents: [new MarkdownString().appendText(nls.localize('modesContentHover.loading', "Loading..."))] }; } @@ -202,16 +196,13 @@ export class ModesContentHoverWidget extends ContentHoverWidget { private _shouldFocus: boolean; private _colorPicker: ColorPickerWidget | null; - private renderDisposable: IDisposable = Disposable.None; + private readonly renderDisposable = this._register(new MutableDisposable()); constructor( editor: ICodeEditor, markerDecorationsService: IMarkerDecorationsService, private readonly _themeService: IThemeService, private readonly _keybindingService: IKeybindingService, - private readonly _contextMenuService: IContextMenuService, - private readonly _bulkEditService: IBulkEditService, - private readonly _commandService: ICommandService, private readonly _modeService: IModeService, private readonly _openerService: IOpenerService | null = NullOpenerService, ) { @@ -245,8 +236,6 @@ export class ModesContentHoverWidget extends ContentHoverWidget { } dispose(): void { - this.renderDisposable.dispose(); - this.renderDisposable = Disposable.None; this._hoverOperation.cancel(); super.dispose(); } @@ -314,8 +303,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget { this._isChangingDecorations = true; this._highlightDecorations = this._editor.deltaDecorations(this._highlightDecorations, []); this._isChangingDecorations = false; - this.renderDisposable.dispose(); - this.renderDisposable = Disposable.None; + this.renderDisposable.clear(); this._colorPicker = null; } @@ -347,7 +335,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget { let isEmptyHoverContent = true; let containColorPicker = false; - let markdownDisposeables: IDisposable[] = []; + const markdownDisposeables = new DisposableStore(); const markerMessages: MarkerHover[] = []; messages.forEach((msg) => { if (!msg.range) { @@ -438,7 +426,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget { this.updateContents(fragment); this._colorPicker.layout(); - this.renderDisposable = combinedDisposable([colorListener, colorChangeListener, widget, ...markdownDisposeables]); + this.renderDisposable.value = combinedDisposable(colorListener, colorChangeListener, widget, markdownDisposeables); }); } else { if (msg instanceof MarkerHover) { @@ -450,15 +438,14 @@ export class ModesContentHoverWidget extends ContentHoverWidget { .forEach(contents => { const markdownHoverElement = $('div.hover-row.markdown-hover'); const hoverContentsElement = dom.append(markdownHoverElement, $('div.hover-contents')); - const renderer = new MarkdownRenderer(this._editor, this._modeService, this._openerService); - markdownDisposeables.push(renderer.onDidRenderCodeBlock(() => { + const renderer = markdownDisposeables.add(new MarkdownRenderer(this._editor, this._modeService, this._openerService)); + markdownDisposeables.add(renderer.onDidRenderCodeBlock(() => { hoverContentsElement.className = 'hover-contents code-hover-contents'; this.onContentsChange(); })); - const renderedContents = renderer.render(contents); + const renderedContents = markdownDisposeables.add(renderer.render(contents)); hoverContentsElement.appendChild(renderedContents.element); fragment.appendChild(markdownHoverElement); - markdownDisposeables.push(renderedContents); isEmptyHoverContent = false; }); } @@ -528,24 +515,10 @@ export class ModesContentHoverWidget extends ContentHoverWidget { private renderMarkerStatusbar(markerHover: MarkerHover): HTMLElement { const hoverElement = $('div.hover-row.status-bar'); - const disposables: IDisposable[] = []; + const disposables = new DisposableStore(); const actionsElement = dom.append(hoverElement, $('div.actions')); - disposables.push(this.renderAction(actionsElement, { - label: nls.localize('quick fixes', "Quick Fix..."), - commandId: QuickFixAction.Id, - run: async (target) => { - const codeActionsPromise = this.getCodeActions(markerHover.marker); - disposables.push(toDisposable(() => codeActionsPromise.cancel())); - const actions = await codeActionsPromise; - const elementPosition = dom.getDomNodePagePosition(target); - this._contextMenuService.showContextMenu({ - getAnchor: () => ({ x: elementPosition.left + 6, y: elementPosition.top + elementPosition.height + 6 }), - getActions: () => actions - }); - } - })); if (markerHover.marker.severity === MarkerSeverity.Error || markerHover.marker.severity === MarkerSeverity.Warning || markerHover.marker.severity === MarkerSeverity.Info) { - disposables.push(this.renderAction(actionsElement, { + disposables.add(this.renderAction(actionsElement, { label: nls.localize('peek problem', "Peek Problem"), commandId: NextMarkerAction.ID, run: () => { @@ -555,24 +528,61 @@ export class ModesContentHoverWidget extends ContentHoverWidget { } })); } - this.renderDisposable = combinedDisposable(disposables); + + const quickfixPlaceholderElement = dom.append(actionsElement, $('div')); + quickfixPlaceholderElement.style.opacity = '0'; + quickfixPlaceholderElement.style.transition = 'opacity 0.2s'; + setTimeout(() => quickfixPlaceholderElement.style.opacity = '1', 200); + quickfixPlaceholderElement.textContent = nls.localize('checkingForQuickFixes', "Checking for quick fixes..."); + disposables.add(toDisposable(() => quickfixPlaceholderElement.remove())); + + + const codeActionsPromise = this.getCodeActions(markerHover.marker); + disposables.add(toDisposable(() => codeActionsPromise.cancel())); + codeActionsPromise.then(actions => { + quickfixPlaceholderElement.style.transition = ''; + quickfixPlaceholderElement.style.opacity = '1'; + + if (!actions.actions.length) { + actions.dispose(); + quickfixPlaceholderElement.textContent = nls.localize('noQuickFixes', "No quick fixes available"); + return; + } + quickfixPlaceholderElement.remove(); + + let showing = false; + disposables.add(toDisposable(() => { + if (!showing) { + actions.dispose(); + } + })); + + disposables.add(this.renderAction(actionsElement, { + label: nls.localize('quick fixes', "Quick Fix..."), + commandId: QuickFixAction.Id, + run: (target) => { + showing = true; + const controller = QuickFixController.get(this._editor); + const elementPosition = dom.getDomNodePagePosition(target); + controller.showCodeActions(actions, { + x: elementPosition.left + 6, + y: elementPosition.top + elementPosition.height + 6 + }); + } + })); + }); + + this.renderDisposable.value = disposables; return hoverElement; } - private getCodeActions(marker: IMarker): CancelablePromise { - return createCancelablePromise(async cancellationToken => { - const codeActions = await getCodeActions(this._editor.getModel()!, new Range(marker.startLineNumber, marker.startColumn, marker.endLineNumber, marker.endColumn), { type: 'manual', filter: { kind: CodeActionKind.QuickFix } }, cancellationToken); - if (codeActions.actions.length) { - return codeActions.actions.map(codeAction => new Action( - codeAction.command ? codeAction.command.id : codeAction.title, - codeAction.title, - undefined, - true, - () => applyCodeAction(codeAction, this._bulkEditService, this._commandService))); - } - return [ - new Action('', nls.localize('editor.action.quickFix.noneMessage', "No code actions available")) - ]; + private getCodeActions(marker: IMarker): CancelablePromise { + return createCancelablePromise(cancellationToken => { + return getCodeActions( + this._editor.getModel()!, + new Range(marker.startLineNumber, marker.startColumn, marker.endLineNumber, marker.endColumn), + { type: 'manual', filter: { kind: CodeActionKind.QuickFix } }, + cancellationToken); }); } diff --git a/src/vs/editor/contrib/hover/modesGlyphHover.ts b/src/vs/editor/contrib/hover/modesGlyphHover.ts index 2d83df2ce..b2b78438a 100644 --- a/src/vs/editor/contrib/hover/modesGlyphHover.ts +++ b/src/vs/editor/contrib/hover/modesGlyphHover.ts @@ -5,7 +5,7 @@ import { $ } from 'vs/base/browser/dom'; import { IMarkdownString, isEmptyMarkdownString } from 'vs/base/common/htmlContent'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { DisposableStore } from 'vs/base/common/lifecycle'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { HoverOperation, HoverStartMode, IHoverComputer } from 'vs/editor/contrib/hover/hoverOperation'; import { GlyphHoverWidget } from 'vs/editor/contrib/hover/hoverWidgets'; @@ -91,7 +91,7 @@ export class ModesGlyphHoverWidget extends GlyphHoverWidget { private readonly _markdownRenderer: MarkdownRenderer; private readonly _computer: MarginComputer; private readonly _hoverOperation: HoverOperation; - private _renderDisposeables: IDisposable[]; + private readonly _renderDisposeables = this._register(new DisposableStore()); constructor( editor: ICodeEditor, @@ -102,7 +102,7 @@ export class ModesGlyphHoverWidget extends GlyphHoverWidget { this._lastLineNumber = -1; - this._markdownRenderer = new MarkdownRenderer(this._editor, modeService, openerService); + this._markdownRenderer = this._register(new MarkdownRenderer(this._editor, modeService, openerService)); this._computer = new MarginComputer(this._editor); this._hoverOperation = new HoverOperation( @@ -116,7 +116,6 @@ export class ModesGlyphHoverWidget extends GlyphHoverWidget { } public dispose(): void { - this._renderDisposeables = dispose(this._renderDisposeables); this._hoverOperation.cancel(); super.dispose(); } @@ -163,16 +162,15 @@ export class ModesGlyphHoverWidget extends GlyphHoverWidget { } private _renderMessages(lineNumber: number, messages: IHoverMessage[]): void { - dispose(this._renderDisposeables); - this._renderDisposeables = []; + this._renderDisposeables.clear(); const fragment = document.createDocumentFragment(); - messages.forEach((msg) => { + for (const msg of messages) { const renderedContents = this._markdownRenderer.render(msg.value); - this._renderDisposeables.push(renderedContents); + this._renderDisposeables.add(renderedContents); fragment.appendChild($('div.hover-row', undefined, renderedContents.element)); - }); + } this.updateContents(fragment); this.showAt(lineNumber); diff --git a/src/vs/editor/contrib/indentation/indentation.ts b/src/vs/editor/contrib/indentation/indentation.ts index 54edce87b..dc51d0faf 100644 --- a/src/vs/editor/contrib/indentation/indentation.ts +++ b/src/vs/editor/contrib/indentation/indentation.ts @@ -253,7 +253,7 @@ export class IndentUsingTabs extends ChangeIndentationSizeAction { id: IndentUsingTabs.ID, label: nls.localize('indentUsingTabs', "Indent Using Tabs"), alias: 'Indent Using Tabs', - precondition: null + precondition: undefined }); } } @@ -267,7 +267,7 @@ export class IndentUsingSpaces extends ChangeIndentationSizeAction { id: IndentUsingSpaces.ID, label: nls.localize('indentUsingSpaces', "Indent Using Spaces"), alias: 'Indent Using Spaces', - precondition: null + precondition: undefined }); } } @@ -281,7 +281,7 @@ export class DetectIndentation extends EditorAction { id: DetectIndentation.ID, label: nls.localize('detectIndentation', "Detect Indentation from Content"), alias: 'Detect Indentation from Content', - precondition: null + precondition: undefined }); } @@ -589,13 +589,13 @@ export class AutoIndentOnPaste implements IEditorContribution { private shouldIgnoreLine(model: ITextModel, lineNumber: number): boolean { model.forceTokenization(lineNumber); - let nonWhiteSpaceColumn = model.getLineFirstNonWhitespaceColumn(lineNumber); - if (nonWhiteSpaceColumn === 0) { + let nonWhitespaceColumn = model.getLineFirstNonWhitespaceColumn(lineNumber); + if (nonWhitespaceColumn === 0) { return true; } let tokens = model.getLineTokens(lineNumber); if (tokens.getCount() > 0) { - let firstNonWhitespaceTokenIndex = tokens.findTokenIndexAtOffset(nonWhiteSpaceColumn); + let firstNonWhitespaceTokenIndex = tokens.findTokenIndexAtOffset(nonWhitespaceColumn); if (firstNonWhitespaceTokenIndex >= 0 && tokens.getStandardTokenType(firstNonWhitespaceTokenIndex) === StandardTokenType.Comment) { return true; } diff --git a/src/vs/editor/contrib/linesOperations/linesOperations.ts b/src/vs/editor/contrib/linesOperations/linesOperations.ts index e69849055..9fb95158f 100644 --- a/src/vs/editor/contrib/linesOperations/linesOperations.ts +++ b/src/vs/editor/contrib/linesOperations/linesOperations.ts @@ -581,7 +581,7 @@ export class DeleteAllLeftAction extends AbstractDeleteAllToBoundaryAction { return new Range(selection.startLineNumber, 1, selection.startLineNumber, selection.startColumn); } } else { - return selection; + return new Range(selection.startLineNumber, 1, selection.endLineNumber, selection.endColumn); } }); diff --git a/src/vs/editor/contrib/linesOperations/test/linesOperations.test.ts b/src/vs/editor/contrib/linesOperations/test/linesOperations.test.ts index 5d2ef4d05..e9479c0f6 100644 --- a/src/vs/editor/contrib/linesOperations/test/linesOperations.test.ts +++ b/src/vs/editor/contrib/linesOperations/test/linesOperations.test.ts @@ -268,7 +268,7 @@ suite('Editor Contrib - Line Operations', () => { editor.setSelections([new Selection(2, 2, 2, 2), new Selection(2, 4, 2, 5)]); deleteAllLeftAction.run(null!, editor); - assert.equal(model.getLineContent(2), 'ord', '002'); + assert.equal(model.getLineContent(2), 'd', '002'); editor.setSelections([new Selection(3, 2, 3, 5), new Selection(3, 7, 3, 7)]); deleteAllLeftAction.run(null!, editor); @@ -276,11 +276,11 @@ suite('Editor Contrib - Line Operations', () => { editor.setSelections([new Selection(4, 3, 4, 3), new Selection(4, 5, 5, 4)]); deleteAllLeftAction.run(null!, editor); - assert.equal(model.getLineContent(4), 'lljour', '004'); + assert.equal(model.getLineContent(4), 'jour', '004'); editor.setSelections([new Selection(5, 3, 6, 3), new Selection(6, 5, 7, 5), new Selection(7, 7, 7, 7)]); deleteAllLeftAction.run(null!, editor); - assert.equal(model.getLineContent(5), 'horlworld', '005'); + assert.equal(model.getLineContent(5), 'world', '005'); }); }); diff --git a/src/vs/editor/contrib/links/getLinks.ts b/src/vs/editor/contrib/links/getLinks.ts index 574576795..df34eed56 100644 --- a/src/vs/editor/contrib/links/getLinks.ts +++ b/src/vs/editor/contrib/links/getLinks.ts @@ -27,7 +27,8 @@ export class Link implements ILink { toJSON(): ILink { return { range: this.range, - url: this.url + url: this.url, + tooltip: this.tooltip }; } @@ -39,6 +40,10 @@ export class Link implements ILink { return this._link.url; } + get tooltip(): string | undefined { + return this._link.tooltip; + } + resolve(token: CancellationToken): Promise { if (this._link.url) { try { @@ -143,7 +148,14 @@ export function getLinks(model: ITextModel, token: CancellationToken): Promise new LinksList(coalesce(lists))); + return Promise.all(promises).then(() => { + const result = new LinksList(coalesce(lists)); + if (!token.isCancellationRequested) { + return result; + } + result.dispose(); + return new LinksList([]); + }); } diff --git a/src/vs/editor/contrib/links/links.ts b/src/vs/editor/contrib/links/links.ts index 3b94a6906..53ea11773 100644 --- a/src/vs/editor/contrib/links/links.ts +++ b/src/vs/editor/contrib/links/links.ts @@ -9,7 +9,7 @@ import * as async from 'vs/base/common/async'; import { CancellationToken } from 'vs/base/common/cancellation'; import { onUnexpectedError } from 'vs/base/common/errors'; import { MarkdownString } from 'vs/base/common/htmlContent'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { DisposableStore } from 'vs/base/common/lifecycle'; import * as platform from 'vs/base/common/platform'; import { ICodeEditor, MouseTargetType } from 'vs/editor/browser/editorBrowser'; import { EditorAction, ServicesAccessor, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions'; @@ -25,79 +25,43 @@ import { IOpenerService } from 'vs/platform/opener/common/opener'; import { editorActiveLinkForeground } from 'vs/platform/theme/common/colorRegistry'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; -const HOVER_MESSAGE_GENERAL_META = new MarkdownString().appendText( - platform.isMacintosh - ? nls.localize('links.navigate.mac', "Cmd + click to follow link") - : nls.localize('links.navigate', "Ctrl + click to follow link") -); - -const HOVER_MESSAGE_COMMAND_META = new MarkdownString().appendText( - platform.isMacintosh - ? nls.localize('links.command.mac', "Cmd + click to execute command") - : nls.localize('links.command', "Ctrl + click to execute command") -); - -const HOVER_MESSAGE_GENERAL_ALT = new MarkdownString().appendText( - platform.isMacintosh - ? nls.localize('links.navigate.al.mac', "Option + click to follow link") - : nls.localize('links.navigate.al', "Alt + click to follow link") -); - -const HOVER_MESSAGE_COMMAND_ALT = new MarkdownString().appendText( - platform.isMacintosh - ? nls.localize('links.command.al.mac', "Option + click to execute command") - : nls.localize('links.command.al', "Alt + click to execute command") -); +function getHoverMessage(link: Link, useMetaKey: boolean): MarkdownString { + const executeCmd = link.url && /^command:/i.test(link.url.toString()); + + const label = link.tooltip + ? link.tooltip + : executeCmd + ? nls.localize('links.navigate.executeCmd', 'Execute command') + : nls.localize('links.navigate.follow', 'Follow link'); + + const kb = useMetaKey + ? platform.isMacintosh + ? nls.localize('links.navigate.kb.meta.mac', "cmd + click") + : nls.localize('links.navigate.kb.meta', "ctrl + click") + : platform.isMacintosh + ? nls.localize('links.navigate.kb.alt.mac', "option + click") + : nls.localize('links.navigate.kb.alt', "alt + click"); + + if (link.url) { + const hoverMessage = new MarkdownString().appendMarkdown(`[${label}](${link.url.toString()}) (${kb})`); + hoverMessage.isTrusted = true; + return hoverMessage; + } else { + return new MarkdownString().appendText(`${label} (${kb})`); + } +} const decoration = { - meta: ModelDecorationOptions.register({ - stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, - collapseOnReplaceEdit: true, - inlineClassName: 'detected-link', - hoverMessage: HOVER_MESSAGE_GENERAL_META - }), - metaActive: ModelDecorationOptions.register({ - stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, - collapseOnReplaceEdit: true, - inlineClassName: 'detected-link-active', - hoverMessage: HOVER_MESSAGE_GENERAL_META - }), - alt: ModelDecorationOptions.register({ - stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, - collapseOnReplaceEdit: true, - inlineClassName: 'detected-link', - hoverMessage: HOVER_MESSAGE_GENERAL_ALT - }), - altActive: ModelDecorationOptions.register({ - stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, - collapseOnReplaceEdit: true, - inlineClassName: 'detected-link-active', - hoverMessage: HOVER_MESSAGE_GENERAL_ALT - }), - altCommand: ModelDecorationOptions.register({ + general: ModelDecorationOptions.register({ stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, collapseOnReplaceEdit: true, - inlineClassName: 'detected-link', - hoverMessage: HOVER_MESSAGE_COMMAND_ALT + inlineClassName: 'detected-link' }), - altCommandActive: ModelDecorationOptions.register({ + active: ModelDecorationOptions.register({ stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, collapseOnReplaceEdit: true, - inlineClassName: 'detected-link-active', - hoverMessage: HOVER_MESSAGE_COMMAND_ALT - }), - metaCommand: ModelDecorationOptions.register({ - stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, - collapseOnReplaceEdit: true, - inlineClassName: 'detected-link', - hoverMessage: HOVER_MESSAGE_COMMAND_META - }), - metaCommandActive: ModelDecorationOptions.register({ - stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, - collapseOnReplaceEdit: true, - inlineClassName: 'detected-link-active', - hoverMessage: HOVER_MESSAGE_COMMAND_META - }), + inlineClassName: 'detected-link-active' + }) }; @@ -111,19 +75,9 @@ class LinkOccurrence { } private static _getOptions(link: Link, useMetaKey: boolean, isActive: boolean): ModelDecorationOptions { - if (link.url && /^command:/i.test(link.url.toString())) { - if (useMetaKey) { - return (isActive ? decoration.metaCommandActive : decoration.metaCommand); - } else { - return (isActive ? decoration.altCommandActive : decoration.altCommand); - } - } else { - if (useMetaKey) { - return (isActive ? decoration.metaActive : decoration.meta); - } else { - return (isActive ? decoration.altActive : decoration.alt); - } - } + const options = { ... (isActive ? decoration.active : decoration.general) }; + options.hoverMessage = getHoverMessage(link, useMetaKey); + return options; } public decorationId: string; @@ -155,7 +109,7 @@ class LinkDetector implements editorCommon.IEditorContribution { private readonly editor: ICodeEditor; private enabled: boolean; - private listenersToRemove: IDisposable[]; + private readonly listenersToRemove = new DisposableStore(); private readonly timeout: async.TimeoutTimer; private computePromise: async.CancelablePromise | null; private activeLinksList: LinksList | null; @@ -172,22 +126,21 @@ class LinkDetector implements editorCommon.IEditorContribution { this.editor = editor; this.openerService = openerService; this.notificationService = notificationService; - this.listenersToRemove = []; let clickLinkGesture = new ClickLinkGesture(editor); - this.listenersToRemove.push(clickLinkGesture); - this.listenersToRemove.push(clickLinkGesture.onMouseMoveOrRelevantKeyDown(([mouseEvent, keyboardEvent]) => { + this.listenersToRemove.add(clickLinkGesture); + this.listenersToRemove.add(clickLinkGesture.onMouseMoveOrRelevantKeyDown(([mouseEvent, keyboardEvent]) => { this._onEditorMouseMove(mouseEvent, keyboardEvent); })); - this.listenersToRemove.push(clickLinkGesture.onExecute((e) => { + this.listenersToRemove.add(clickLinkGesture.onExecute((e) => { this.onEditorMouseUp(e); })); - this.listenersToRemove.push(clickLinkGesture.onCancel((e) => { + this.listenersToRemove.add(clickLinkGesture.onCancel((e) => { this.cleanUpActiveLinkDecoration(); })); this.enabled = editor.getConfiguration().contribInfo.links; - this.listenersToRemove.push(editor.onDidChangeConfiguration((e) => { + this.listenersToRemove.add(editor.onDidChangeConfiguration((e) => { let enabled = editor.getConfiguration().contribInfo.links; if (this.enabled === enabled) { // No change in our configuration option @@ -204,10 +157,10 @@ class LinkDetector implements editorCommon.IEditorContribution { // Start computing (for the getting enabled case) this.beginCompute(); })); - this.listenersToRemove.push(editor.onDidChangeModelContent((e) => this.onChange())); - this.listenersToRemove.push(editor.onDidChangeModel((e) => this.onModelChanged())); - this.listenersToRemove.push(editor.onDidChangeModelLanguage((e) => this.onModelModeChanged())); - this.listenersToRemove.push(LinkProviderRegistry.onDidChange((e) => this.onModelModeChanged())); + this.listenersToRemove.add(editor.onDidChangeModelContent((e) => this.onChange())); + this.listenersToRemove.add(editor.onDidChangeModel((e) => this.onModelChanged())); + this.listenersToRemove.add(editor.onDidChangeModelLanguage((e) => this.onModelModeChanged())); + this.listenersToRemove.add(LinkProviderRegistry.onDidChange((e) => this.onModelModeChanged())); this.timeout = new async.TimeoutTimer(); this.computePromise = null; @@ -397,7 +350,7 @@ class LinkDetector implements editorCommon.IEditorContribution { } public dispose(): void { - this.listenersToRemove = dispose(this.listenersToRemove); + this.listenersToRemove.dispose(); this.stop(); this.timeout.dispose(); } @@ -410,7 +363,7 @@ class OpenLinkAction extends EditorAction { id: 'editor.action.openLink', label: nls.localize('label', "Open Link"), alias: 'Open Link', - precondition: null + precondition: undefined }); } diff --git a/src/vs/editor/contrib/markdown/markdownRenderer.ts b/src/vs/editor/contrib/markdown/markdownRenderer.ts index e013de91c..5825a919b 100644 --- a/src/vs/editor/contrib/markdown/markdownRenderer.ts +++ b/src/vs/editor/contrib/markdown/markdownRenderer.ts @@ -13,16 +13,16 @@ import { tokenizeToString } from 'vs/editor/common/modes/textToHtmlTokenizer'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { optional } from 'vs/platform/instantiation/common/instantiation'; import { Event, Emitter } from 'vs/base/common/event'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle'; import { TokenizationRegistry } from 'vs/editor/common/modes'; export interface IMarkdownRenderResult extends IDisposable { element: HTMLElement; } -export class MarkdownRenderer { +export class MarkdownRenderer extends Disposable { - private _onDidRenderCodeBlock = new Emitter(); + private _onDidRenderCodeBlock = this._register(new Emitter()); readonly onDidRenderCodeBlock: Event = this._onDidRenderCodeBlock.event; constructor( @@ -30,9 +30,10 @@ export class MarkdownRenderer { @IModeService private readonly _modeService: IModeService, @optional(IOpenerService) private readonly _openerService: IOpenerService | null = NullOpenerService, ) { + super(); } - private getOptions(disposeables: IDisposable[]): RenderOptions { + private getOptions(disposeables: DisposableStore): RenderOptions { return { codeBlockRenderer: (languageAlias, value) => { // In markdown, @@ -78,7 +79,7 @@ export class MarkdownRenderer { } render(markdown: IMarkdownString | undefined): IMarkdownRenderResult { - let disposeables: IDisposable[] = []; + const disposeables = new DisposableStore(); let element: HTMLElement; if (!markdown) { @@ -89,7 +90,7 @@ export class MarkdownRenderer { return { element, - dispose: () => dispose(disposeables) + dispose: () => disposeables.dispose() }; } } diff --git a/src/vs/editor/contrib/message/messageController.ts b/src/vs/editor/contrib/message/messageController.ts index e522a12f8..e57a09874 100644 --- a/src/vs/editor/contrib/message/messageController.ts +++ b/src/vs/editor/contrib/message/messageController.ts @@ -7,7 +7,7 @@ import 'vs/css!./messageController'; import * as nls from 'vs/nls'; import { TimeoutTimer } from 'vs/base/common/async'; import { KeyCode } from 'vs/base/common/keyCodes'; -import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, Disposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle'; import { alert } from 'vs/base/browser/ui/aria/aria'; import { Range } from 'vs/editor/common/core/range'; import * as editorCommon from 'vs/editor/common/editorCommon'; @@ -29,14 +29,16 @@ export class MessageController extends Disposable implements editorCommon.IEdito return editor.getContribution(MessageController._id); } + private readonly closeTimeout = 3000; // close after 3s + getId(): string { return MessageController._id; } private readonly _editor: ICodeEditor; private readonly _visible: IContextKey; - private _messageWidget: MessageWidget; - private _messageListeners: IDisposable[] = []; + private readonly _messageWidget = this._register(new MutableDisposable()); + private readonly _messageListeners = this._register(new DisposableStore()); constructor( editor: ICodeEditor, @@ -62,22 +64,21 @@ export class MessageController extends Disposable implements editorCommon.IEdito alert(message); this._visible.set(true); - dispose(this._messageWidget); - this._messageListeners = dispose(this._messageListeners); - this._messageWidget = new MessageWidget(this._editor, position, message); + this._messageWidget.clear(); + this._messageListeners.clear(); + this._messageWidget.value = new MessageWidget(this._editor, position, message); // close on blur, cursor, model change, dispose - this._messageListeners.push(this._editor.onDidBlurEditorText(() => this.closeMessage())); - this._messageListeners.push(this._editor.onDidChangeCursorPosition(() => this.closeMessage())); - this._messageListeners.push(this._editor.onDidDispose(() => this.closeMessage())); - this._messageListeners.push(this._editor.onDidChangeModel(() => this.closeMessage())); + this._messageListeners.add(this._editor.onDidBlurEditorText(() => this.closeMessage())); + this._messageListeners.add(this._editor.onDidChangeCursorPosition(() => this.closeMessage())); + this._messageListeners.add(this._editor.onDidDispose(() => this.closeMessage())); + this._messageListeners.add(this._editor.onDidChangeModel(() => this.closeMessage())); - // close after 3s - this._messageListeners.push(new TimeoutTimer(() => this.closeMessage(), 3000)); + this._messageListeners.add(new TimeoutTimer(() => this.closeMessage(), this.closeTimeout)); // close on mouse move let bounds: Range; - this._messageListeners.push(this._editor.onMouseMove(e => { + this._messageListeners.add(this._editor.onMouseMove(e => { // outside the text area if (!e.target.position) { return; @@ -95,8 +96,10 @@ export class MessageController extends Disposable implements editorCommon.IEdito closeMessage(): void { this._visible.reset(); - this._messageListeners = dispose(this._messageListeners); - this._messageListeners.push(MessageWidget.fadeOut(this._messageWidget)); + this._messageListeners.clear(); + if (this._messageWidget.value) { + this._messageListeners.add(MessageWidget.fadeOut(this._messageWidget.value)); + } } private _onDidAttemptReadOnlyEdit(): void { diff --git a/src/vs/editor/contrib/multicursor/multicursor.ts b/src/vs/editor/contrib/multicursor/multicursor.ts index 330d68113..ec0925af3 100644 --- a/src/vs/editor/contrib/multicursor/multicursor.ts +++ b/src/vs/editor/contrib/multicursor/multicursor.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import { RunOnceScheduler } from 'vs/base/common/async'; import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorAction, ServicesAccessor, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import { RevealTarget } from 'vs/editor/common/controller/cursorCommon'; @@ -34,7 +34,7 @@ export class InsertCursorAbove extends EditorAction { id: 'editor.action.insertCursorAbove', label: nls.localize('mutlicursor.insertAbove', "Add Cursor Above"), alias: 'Add Cursor Above', - precondition: null, + precondition: undefined, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.UpArrow, @@ -83,7 +83,7 @@ export class InsertCursorBelow extends EditorAction { id: 'editor.action.insertCursorBelow', label: nls.localize('mutlicursor.insertBelow', "Add Cursor Below"), alias: 'Add Cursor Below', - precondition: null, + precondition: undefined, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.DownArrow, @@ -132,7 +132,7 @@ class InsertCursorAtEndOfEachLineSelected extends EditorAction { id: 'editor.action.insertCursorAtEndOfEachLineSelected', label: nls.localize('mutlicursor.insertAtEndOfEachLineSelected', "Add Cursors to Line Ends"), alias: 'Add Cursors to Line Ends', - precondition: null, + precondition: undefined, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_I, @@ -184,7 +184,7 @@ class InsertCursorAtEndOfLineSelected extends EditorAction { id: 'editor.action.addCursorsToBottom', label: nls.localize('mutlicursor.addCursorsToBottom', "Add Cursors To Bottom"), alias: 'Add Cursors To Bottom', - precondition: null + precondition: undefined }); } @@ -214,7 +214,7 @@ class InsertCursorAtTopOfLineSelected extends EditorAction { id: 'editor.action.addCursorsToTop', label: nls.localize('mutlicursor.addCursorsToTop', "Add Cursors To Top"), alias: 'Add Cursors To Top', - precondition: null + precondition: undefined }); } @@ -427,7 +427,7 @@ export class MultiCursorSelectionController extends Disposable implements IEdito private readonly _editor: ICodeEditor; private _ignoreSelectionChange: boolean; private _session: MultiCursorSession | null; - private _sessionDispose: IDisposable[]; + private readonly _sessionDispose = this._register(new DisposableStore()); public static get(editor: ICodeEditor): MultiCursorSelectionController { return editor.getContribution(MultiCursorSelectionController.ID); @@ -438,7 +438,6 @@ export class MultiCursorSelectionController extends Disposable implements IEdito this._editor = editor; this._ignoreSelectionChange = false; this._session = null; - this._sessionDispose = []; } public dispose(): void { @@ -468,27 +467,25 @@ export class MultiCursorSelectionController extends Disposable implements IEdito } findController.getState().change(newState, false); - this._sessionDispose = [ - this._editor.onDidChangeCursorSelection((e) => { - if (this._ignoreSelectionChange) { - return; - } - this._endSession(); - }), - this._editor.onDidBlurEditorText(() => { + this._sessionDispose.add(this._editor.onDidChangeCursorSelection((e) => { + if (this._ignoreSelectionChange) { + return; + } + this._endSession(); + })); + this._sessionDispose.add(this._editor.onDidBlurEditorText(() => { + this._endSession(); + })); + this._sessionDispose.add(findController.getState().onFindReplaceStateChange((e) => { + if (e.matchCase || e.wholeWord) { this._endSession(); - }), - findController.getState().onFindReplaceStateChange((e) => { - if (e.matchCase || e.wholeWord) { - this._endSession(); - } - }) - ]; + } + })); } } private _endSession(): void { - this._sessionDispose = dispose(this._sessionDispose); + this._sessionDispose.clear(); if (this._session && this._session.isDisconnectedFromFindController) { const newState: INewFindReplaceState = { wholeWordOverride: FindOptionOverride.NotSet, @@ -650,7 +647,7 @@ export class AddSelectionToNextFindMatchAction extends MultiCursorSelectionContr id: 'editor.action.addSelectionToNextFindMatch', label: nls.localize('addSelectionToNextFindMatch', "Add Selection To Next Find Match"), alias: 'Add Selection To Next Find Match', - precondition: null, + precondition: undefined, kbOpts: { kbExpr: EditorContextKeys.focus, primary: KeyMod.CtrlCmd | KeyCode.KEY_D, @@ -675,7 +672,7 @@ export class AddSelectionToPreviousFindMatchAction extends MultiCursorSelectionC id: 'editor.action.addSelectionToPreviousFindMatch', label: nls.localize('addSelectionToPreviousFindMatch', "Add Selection To Previous Find Match"), alias: 'Add Selection To Previous Find Match', - precondition: null, + precondition: undefined, menubarOpts: { menuId: MenuId.MenubarSelectionMenu, group: '3_multi', @@ -695,7 +692,7 @@ export class MoveSelectionToNextFindMatchAction extends MultiCursorSelectionCont 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, + precondition: undefined, kbOpts: { kbExpr: EditorContextKeys.focus, primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_D), @@ -714,7 +711,7 @@ export class MoveSelectionToPreviousFindMatchAction extends MultiCursorSelection 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 + precondition: undefined }); } protected _run(multiCursorController: MultiCursorSelectionController, findController: CommonFindController): void { @@ -728,7 +725,7 @@ export class SelectHighlightsAction extends MultiCursorSelectionControllerAction id: 'editor.action.selectHighlights', label: nls.localize('selectAllOccurrencesOfFindMatch', "Select All Occurrences of Find Match"), alias: 'Select All Occurrences of Find Match', - precondition: null, + precondition: undefined, kbOpts: { kbExpr: EditorContextKeys.focus, primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_L, diff --git a/src/vs/editor/contrib/multicursor/test/multicursor.test.ts b/src/vs/editor/contrib/multicursor/test/multicursor.test.ts index f2715cbe0..74068f74c 100644 --- a/src/vs/editor/contrib/multicursor/test/multicursor.test.ts +++ b/src/vs/editor/contrib/multicursor/test/multicursor.test.ts @@ -60,14 +60,15 @@ suite('Multicursor selection', () => { let queryState: { [key: string]: any; } = {}; let serviceCollection = new ServiceCollection(); serviceCollection.set(IStorageService, { - _serviceBrand: undefined, + _serviceBrand: undefined as any, onDidChangeStorage: Event.None, onWillSaveState: Event.None, get: (key: string) => queryState[key], getBoolean: (key: string) => !!queryState[key], getNumber: (key: string) => undefined!, store: (key: string, value: any) => { queryState[key] = value; return Promise.resolve(); }, - remove: (key) => undefined + remove: (key) => undefined, + logStorage: () => undefined } as IStorageService); test('issue #8817: Cursor position changes when you cancel multicursor', () => { diff --git a/src/vs/editor/contrib/parameterHints/parameterHintsModel.ts b/src/vs/editor/contrib/parameterHints/parameterHintsModel.ts index d52dc7948..c34c68a84 100644 --- a/src/vs/editor/contrib/parameterHints/parameterHintsModel.ts +++ b/src/vs/editor/contrib/parameterHints/parameterHintsModel.ts @@ -6,7 +6,7 @@ import { CancelablePromise, createCancelablePromise, Delayer } from 'vs/base/common/async'; import { onUnexpectedError } from 'vs/base/common/errors'; import { Emitter } from 'vs/base/common/event'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; import { CharacterSet } from 'vs/editor/common/core/characterClassifier'; @@ -30,7 +30,7 @@ namespace ParameterHintState { export class Pending { readonly type = Type.Pending; constructor( - readonly request: CancelablePromise + readonly request: CancelablePromise ) { } } @@ -54,6 +54,7 @@ export class ParameterHintsModel extends Disposable { private readonly editor: ICodeEditor; private enabled: boolean; private _state: ParameterHintState.State = ParameterHintState.Default; + private readonly _lastSignatureHelpResult = this._register(new MutableDisposable()); private triggerChars = new CharacterSet(); private retriggerChars = new CharacterSet(); @@ -92,7 +93,6 @@ export class ParameterHintsModel extends Disposable { } cancel(silent: boolean = false): void { - this.state = ParameterHintState.Default; this.throttledDelayer.cancel(); @@ -181,14 +181,22 @@ export class ParameterHintsModel extends Disposable { return this.state.request.then(result => { // Check that we are still resolving the correct signature help if (triggerId !== this.triggerId) { + if (result) { + result.dispose(); + } return false; } - if (!result || !result.signatures || result.signatures.length === 0) { + if (!result || !result.value.signatures || result.value.signatures.length === 0) { + if (result) { + result.dispose(); + } + this._lastSignatureHelpResult.clear(); this.cancel(); return false; } else { - this.state = new ParameterHintState.Active(result); + this.state = new ParameterHintState.Active(result.value); + this._lastSignatureHelpResult.value = result; this._onChangedHints.fire(this.state.hints); return true; } diff --git a/src/vs/editor/contrib/parameterHints/parameterHintsWidget.ts b/src/vs/editor/contrib/parameterHints/parameterHintsWidget.ts index 5c365daeb..53bf31abc 100644 --- a/src/vs/editor/contrib/parameterHints/parameterHintsWidget.ts +++ b/src/vs/editor/contrib/parameterHints/parameterHintsWidget.ts @@ -8,7 +8,7 @@ import { domEvent, stop } from 'vs/base/browser/event'; import * as aria from 'vs/base/browser/ui/aria/aria'; import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; import { Event } from 'vs/base/common/event'; -import { dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, Disposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle'; import 'vs/css!./parameterHints'; import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; @@ -25,13 +25,13 @@ import { ParameterHintsModel, TriggerContext } from 'vs/editor/contrib/parameter const $ = dom.$; -export class ParameterHintsWidget implements IContentWidget, IDisposable { +export class ParameterHintsWidget extends Disposable implements IContentWidget, IDisposable { private static readonly ID = 'editor.widget.parameterHintsWidget'; private readonly markdownRenderer: MarkdownRenderer; - private renderDisposeables: IDisposable[]; - private model: ParameterHintsModel | null; + private readonly renderDisposeables = this._register(new DisposableStore()); + private readonly model = this._register(new MutableDisposable()); private readonly keyVisible: IContextKey; private readonly keyMultipleSignatures: IContextKey; private element: HTMLElement; @@ -41,7 +41,6 @@ export class ParameterHintsWidget implements IContentWidget, IDisposable { private visible: boolean; private announcedLabel: string | null; private scrollbar: DomScrollableElement; - private disposables: IDisposable[]; // Editor.IContentWidget.allowEditorOverflow allowEditorOverflow = true; @@ -52,14 +51,14 @@ export class ParameterHintsWidget implements IContentWidget, IDisposable { @IOpenerService openerService: IOpenerService, @IModeService modeService: IModeService, ) { - this.markdownRenderer = new MarkdownRenderer(editor, modeService, openerService); - this.model = new ParameterHintsModel(editor); + super(); + this.markdownRenderer = this._register(new MarkdownRenderer(editor, modeService, openerService)); + this.model.value = new ParameterHintsModel(editor); this.keyVisible = Context.Visible.bindTo(contextKeyService); this.keyMultipleSignatures = Context.MultipleSignatures.bindTo(contextKeyService); this.visible = false; - this.disposables = []; - this.disposables.push(this.model.onChangedHints(newParameterHints => { + this._register(this.model.value.onChangedHints(newParameterHints => { if (newParameterHints) { this.show(); this.render(newParameterHints); @@ -79,16 +78,16 @@ export class ParameterHintsWidget implements IContentWidget, IDisposable { const next = dom.append(buttons, $('.button.next')); const onPreviousClick = stop(domEvent(previous, 'click')); - onPreviousClick(this.previous, this, this.disposables); + this._register(onPreviousClick(this.previous, this)); const onNextClick = stop(domEvent(next, 'click')); - onNextClick(this.next, this, this.disposables); + this._register(onNextClick(this.next, this)); this.overloads = dom.append(wrapper, $('.overloads')); const body = $('.body'); this.scrollbar = new DomScrollableElement(body, {}); - this.disposables.push(this.scrollbar); + this._register(this.scrollbar); wrapper.appendChild(this.scrollbar.getDomNode()); this.signature = dom.append(body, $('.signature')); @@ -99,7 +98,7 @@ export class ParameterHintsWidget implements IContentWidget, IDisposable { this.hide(); this.element.style.userSelect = 'text'; - this.disposables.push(this.editor.onDidChangeCursorSelection(e => { + this._register(this.editor.onDidChangeCursorSelection(e => { if (this.visible) { this.editor.layoutContentWidget(this); } @@ -112,11 +111,11 @@ export class ParameterHintsWidget implements IContentWidget, IDisposable { updateFont(); - Event.chain(this.editor.onDidChangeConfiguration.bind(this.editor)) + this._register(Event.chain(this.editor.onDidChangeConfiguration.bind(this.editor)) .filter(e => e.fontInfo) - .on(updateFont, null, this.disposables); + .on(updateFont, null)); - this.disposables.push(this.editor.onDidLayoutChange(e => this.updateMaxHeight())); + this._register(this.editor.onDidLayoutChange(e => this.updateMaxHeight())); this.updateMaxHeight(); } @@ -190,8 +189,7 @@ export class ParameterHintsWidget implements IContentWidget, IDisposable { this.renderParameters(code, signature, hints.activeParameter); } - dispose(this.renderDisposeables); - this.renderDisposeables = []; + this.renderDisposeables.clear(); const activeParameter = signature.parameters[hints.activeParameter]; @@ -202,7 +200,7 @@ export class ParameterHintsWidget implements IContentWidget, IDisposable { } else { const renderedContents = this.markdownRenderer.render(activeParameter.documentation); dom.addClass(renderedContents.element, 'markdown-docs'); - this.renderDisposeables.push(renderedContents); + this.renderDisposeables.add(renderedContents); documentation.appendChild(renderedContents.element); } dom.append(this.docs, $('p', {}, documentation)); @@ -216,7 +214,7 @@ export class ParameterHintsWidget implements IContentWidget, IDisposable { } else { const renderedContents = this.markdownRenderer.render(signature.documentation); dom.addClass(renderedContents.element, 'markdown-docs'); - this.renderDisposeables.push(renderedContents); + this.renderDisposeables.add(renderedContents); dom.append(this.docs, renderedContents.element); } @@ -284,22 +282,22 @@ export class ParameterHintsWidget implements IContentWidget, IDisposable { } next(): void { - if (this.model) { + if (this.model.value) { this.editor.focus(); - this.model.next(); + this.model.value.next(); } } previous(): void { - if (this.model) { + if (this.model.value) { this.editor.focus(); - this.model.previous(); + this.model.value.previous(); } } cancel(): void { - if (this.model) { - this.model.cancel(); + if (this.model.value) { + this.model.value.cancel(); } } @@ -312,8 +310,8 @@ export class ParameterHintsWidget implements IContentWidget, IDisposable { } trigger(context: TriggerContext): void { - if (this.model) { - this.model.trigger(context, 0); + if (this.model.value) { + this.model.value.trigger(context, 0); } } @@ -321,16 +319,6 @@ export class ParameterHintsWidget implements IContentWidget, IDisposable { const height = Math.max(this.editor.getLayoutInfo().height / 4, 250); this.element.style.maxHeight = `${height}px`; } - - dispose(): void { - this.disposables = dispose(this.disposables); - this.renderDisposeables = dispose(this.renderDisposeables); - - if (this.model) { - this.model.dispose(); - this.model = null; - } - } } registerThemingParticipant((theme, collector) => { diff --git a/src/vs/editor/contrib/parameterHints/provideSignatureHelp.ts b/src/vs/editor/contrib/parameterHints/provideSignatureHelp.ts index 87ea878ab..8aaf09f8b 100644 --- a/src/vs/editor/contrib/parameterHints/provideSignatureHelp.ts +++ b/src/vs/editor/contrib/parameterHints/provideSignatureHelp.ts @@ -17,18 +17,32 @@ export const Context = { MultipleSignatures: new RawContextKey('parameterHintsMultipleSignatures', false), }; -export function provideSignatureHelp(model: ITextModel, position: Position, context: modes.SignatureHelpContext, token: CancellationToken): Promise { +export function provideSignatureHelp( + model: ITextModel, + position: Position, + context: modes.SignatureHelpContext, + token: CancellationToken +): Promise { const supports = modes.SignatureHelpProviderRegistry.ordered(model); return first(supports.map(support => () => { - return Promise.resolve(support.provideSignatureHelp(model, position, token, context)).catch(onUnexpectedExternalError); + return Promise.resolve(support.provideSignatureHelp(model, position, token, context)) + .catch(e => onUnexpectedExternalError(e)); })); } -registerDefaultLanguageCommand('_executeSignatureHelpProvider', (model, position, args) => - provideSignatureHelp(model, position, { +registerDefaultLanguageCommand('_executeSignatureHelpProvider', async (model, position, args) => { + const result = await provideSignatureHelp(model, position, { triggerKind: modes.SignatureHelpTriggerKind.Invoke, isRetrigger: false, triggerCharacter: args['triggerCharacter'] - }, CancellationToken.None)); + }, CancellationToken.None); + + if (!result) { + return undefined; + } + + setTimeout(() => result.dispose(), 0); + return result.value; +}); diff --git a/src/vs/editor/contrib/parameterHints/test/parameterHintsModel.test.ts b/src/vs/editor/contrib/parameterHints/test/parameterHintsModel.test.ts index 2a26052de..a6ffca40e 100644 --- a/src/vs/editor/contrib/parameterHints/test/parameterHintsModel.test.ts +++ b/src/vs/editor/contrib/parameterHints/test/parameterHintsModel.test.ts @@ -5,7 +5,7 @@ import * as assert from 'assert'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { DisposableStore } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { Position } from 'vs/editor/common/core/position'; import { Handler } from 'vs/editor/common/editorCommon'; @@ -23,7 +23,7 @@ const mockFile = URI.parse('test:somefile.ttt'); const mockFileSelector = { scheme: 'test' }; -const emptySigHelpResult = { +const emptySigHelp: modes.SignatureHelp = { signatures: [{ label: 'none', parameters: [] @@ -31,11 +31,21 @@ const emptySigHelpResult = { activeParameter: 0, activeSignature: 0 }; + +const emptySigHelpResult: modes.SignatureHelpResult = { + value: emptySigHelp, + dispose: () => { } +}; + suite('ParameterHintsModel', () => { - let disposables: IDisposable[] = []; + const disposables = new DisposableStore(); - setup(function () { - disposables = dispose(disposables); + setup(() => { + disposables.clear(); + }); + + teardown(() => { + disposables.clear(); }); function createMockEditor(fileContents: string) { @@ -47,8 +57,8 @@ suite('ParameterHintsModel', () => { [IStorageService, new InMemoryStorageService()] ) }); - disposables.push(textModel); - disposables.push(editor); + disposables.add(textModel); + disposables.add(editor); return editor; } @@ -56,9 +66,9 @@ suite('ParameterHintsModel', () => { const triggerChar = '('; const editor = createMockEditor(''); - disposables.push(new ParameterHintsModel(editor)); + disposables.add(new ParameterHintsModel(editor)); - disposables.push(modes.SignatureHelpProviderRegistry.register(mockFileSelector, new class implements modes.SignatureHelpProvider { + disposables.add(modes.SignatureHelpProviderRegistry.register(mockFileSelector, new class implements modes.SignatureHelpProvider { signatureHelpTriggerCharacters = [triggerChar]; signatureHelpRetriggerCharacters = []; @@ -77,14 +87,14 @@ suite('ParameterHintsModel', () => { const triggerChar = '('; const editor = createMockEditor(''); - disposables.push(new ParameterHintsModel(editor)); + disposables.add(new ParameterHintsModel(editor)); let invokeCount = 0; - disposables.push(modes.SignatureHelpProviderRegistry.register(mockFileSelector, new class implements modes.SignatureHelpProvider { + disposables.add(modes.SignatureHelpProviderRegistry.register(mockFileSelector, new class implements modes.SignatureHelpProvider { signatureHelpTriggerCharacters = [triggerChar]; signatureHelpRetriggerCharacters = []; - provideSignatureHelp(_model: ITextModel, _position: Position, _token: CancellationToken, context: modes.SignatureHelpContext): modes.SignatureHelp | Promise { + provideSignatureHelp(_model: ITextModel, _position: Position, _token: CancellationToken, context: modes.SignatureHelpContext): modes.SignatureHelpResult | Promise { ++invokeCount; if (invokeCount === 1) { assert.strictEqual(context.triggerKind, modes.SignatureHelpTriggerKind.TriggerCharacter); @@ -99,7 +109,7 @@ suite('ParameterHintsModel', () => { assert.strictEqual(context.triggerKind, modes.SignatureHelpTriggerKind.TriggerCharacter); assert.strictEqual(context.isRetrigger, true); assert.strictEqual(context.triggerCharacter, triggerChar); - assert.strictEqual(context.activeSignatureHelp, emptySigHelpResult); + assert.strictEqual(context.activeSignatureHelp, emptySigHelp); done(); } @@ -115,14 +125,14 @@ suite('ParameterHintsModel', () => { const editor = createMockEditor(''); const hintModel = new ParameterHintsModel(editor); - disposables.push(hintModel); + disposables.add(hintModel); let invokeCount = 0; - disposables.push(modes.SignatureHelpProviderRegistry.register(mockFileSelector, new class implements modes.SignatureHelpProvider { + disposables.add(modes.SignatureHelpProviderRegistry.register(mockFileSelector, new class implements modes.SignatureHelpProvider { signatureHelpTriggerCharacters = [triggerChar]; signatureHelpRetriggerCharacters = []; - provideSignatureHelp(_model: ITextModel, _position: Position, _token: CancellationToken, context: modes.SignatureHelpContext): modes.SignatureHelp | Promise { + provideSignatureHelp(_model: ITextModel, _position: Position, _token: CancellationToken, context: modes.SignatureHelpContext): modes.SignatureHelpResult | Promise { ++invokeCount; if (invokeCount === 1) { assert.strictEqual(context.triggerKind, modes.SignatureHelpTriggerKind.TriggerCharacter); @@ -150,10 +160,10 @@ suite('ParameterHintsModel', () => { test('Provider should get last trigger character when triggered multiple times and only be invoked once', (done) => { const editor = createMockEditor(''); - disposables.push(new ParameterHintsModel(editor, 5)); + disposables.add(new ParameterHintsModel(editor, 5)); let invokeCount = 0; - disposables.push(modes.SignatureHelpProviderRegistry.register(mockFileSelector, new class implements modes.SignatureHelpProvider { + disposables.add(modes.SignatureHelpProviderRegistry.register(mockFileSelector, new class implements modes.SignatureHelpProvider { signatureHelpTriggerCharacters = ['a', 'b', 'c']; signatureHelpRetriggerCharacters = []; @@ -181,14 +191,14 @@ suite('ParameterHintsModel', () => { test('Provider should be retriggered if already active', (done) => { const editor = createMockEditor(''); - disposables.push(new ParameterHintsModel(editor, 5)); + disposables.add(new ParameterHintsModel(editor, 5)); let invokeCount = 0; - disposables.push(modes.SignatureHelpProviderRegistry.register(mockFileSelector, new class implements modes.SignatureHelpProvider { + disposables.add(modes.SignatureHelpProviderRegistry.register(mockFileSelector, new class implements modes.SignatureHelpProvider { signatureHelpTriggerCharacters = ['a', 'b']; signatureHelpRetriggerCharacters = []; - provideSignatureHelp(_model: ITextModel, _position: Position, _token: CancellationToken, context: modes.SignatureHelpContext): modes.SignatureHelp | Promise { + provideSignatureHelp(_model: ITextModel, _position: Position, _token: CancellationToken, context: modes.SignatureHelpContext): modes.SignatureHelpResult | Promise { ++invokeCount; if (invokeCount === 1) { assert.strictEqual(context.triggerKind, modes.SignatureHelpTriggerKind.TriggerCharacter); @@ -223,7 +233,7 @@ suite('ParameterHintsModel', () => { signatureHelpRetriggerCharacters = []; - provideSignatureHelp(_model: ITextModel, _position: Position, token: CancellationToken): modes.SignatureHelp | Promise { + provideSignatureHelp(_model: ITextModel, _position: Position, token: CancellationToken): modes.SignatureHelpResult | Promise { const count = invokeCount++; token.onCancellationRequested(() => { didRequestCancellationOf = count; }); @@ -232,22 +242,25 @@ suite('ParameterHintsModel', () => { hintsModel.trigger({ triggerKind: modes.SignatureHelpTriggerKind.Invoke }, 0); } - return new Promise(resolve => { + return new Promise(resolve => { setTimeout(() => { resolve({ - signatures: [{ - label: '' + count, - parameters: [] - }], - activeParameter: 0, - activeSignature: 0 + value: { + signatures: [{ + label: '' + count, + parameters: [] + }], + activeParameter: 0, + activeSignature: 0 + }, + dispose: () => { } }); }, 100); }); } }; - disposables.push(modes.SignatureHelpProviderRegistry.register(mockFileSelector, longRunningProvider)); + disposables.add(modes.SignatureHelpProviderRegistry.register(mockFileSelector, longRunningProvider)); hintsModel.trigger({ triggerKind: modes.SignatureHelpTriggerKind.Invoke }, 0); assert.strictEqual(-1, didRequestCancellationOf); @@ -269,14 +282,14 @@ suite('ParameterHintsModel', () => { const retriggerChar = 'b'; const editor = createMockEditor(''); - disposables.push(new ParameterHintsModel(editor, 5)); + disposables.add(new ParameterHintsModel(editor, 5)); let invokeCount = 0; - disposables.push(modes.SignatureHelpProviderRegistry.register(mockFileSelector, new class implements modes.SignatureHelpProvider { + disposables.add(modes.SignatureHelpProviderRegistry.register(mockFileSelector, new class implements modes.SignatureHelpProvider { signatureHelpTriggerCharacters = [triggerChar]; signatureHelpRetriggerCharacters = [retriggerChar]; - provideSignatureHelp(_model: ITextModel, _position: Position, _token: CancellationToken, context: modes.SignatureHelpContext): modes.SignatureHelp | Promise { + provideSignatureHelp(_model: ITextModel, _position: Position, _token: CancellationToken, context: modes.SignatureHelpContext): modes.SignatureHelpResult | Promise { ++invokeCount; if (invokeCount === 1) { assert.strictEqual(context.triggerKind, modes.SignatureHelpTriggerKind.TriggerCharacter); @@ -312,26 +325,29 @@ suite('ParameterHintsModel', () => { const editor = createMockEditor(''); const model = new ParameterHintsModel(editor, 5); - disposables.push(model); + disposables.add(model); - disposables.push(modes.SignatureHelpProviderRegistry.register(mockFileSelector, new class implements modes.SignatureHelpProvider { + disposables.add(modes.SignatureHelpProviderRegistry.register(mockFileSelector, new class implements modes.SignatureHelpProvider { signatureHelpTriggerCharacters = [triggerChar]; signatureHelpRetriggerCharacters = []; - async provideSignatureHelp(_model: ITextModel, _position: Position, _token: CancellationToken, context: modes.SignatureHelpContext): Promise { + async provideSignatureHelp(_model: ITextModel, _position: Position, _token: CancellationToken, context: modes.SignatureHelpContext): Promise { if (!context.isRetrigger) { // retrigger after delay for widget to show up setTimeout(() => editor.trigger('keyboard', Handler.Type, { text: triggerChar }), 50); return { - activeParameter: 0, - activeSignature: 0, - signatures: [{ - label: firstProviderId, - parameters: [ - { label: paramterLabel } - ] - }] + value: { + activeParameter: 0, + activeSignature: 0, + signatures: [{ + label: firstProviderId, + parameters: [ + { label: paramterLabel } + ] + }] + }, + dispose: () => { } }; } @@ -339,19 +355,22 @@ suite('ParameterHintsModel', () => { } })); - disposables.push(modes.SignatureHelpProviderRegistry.register(mockFileSelector, new class implements modes.SignatureHelpProvider { + disposables.add(modes.SignatureHelpProviderRegistry.register(mockFileSelector, new class implements modes.SignatureHelpProvider { signatureHelpTriggerCharacters = [triggerChar]; signatureHelpRetriggerCharacters = []; - async provideSignatureHelp(_model: ITextModel, _position: Position, _token: CancellationToken, context: modes.SignatureHelpContext): Promise { + async provideSignatureHelp(_model: ITextModel, _position: Position, _token: CancellationToken, context: modes.SignatureHelpContext): Promise { if (context.isRetrigger) { return { - activeParameter: 0, - activeSignature: context.activeSignatureHelp ? context.activeSignatureHelp.activeSignature + 1 : 0, - signatures: [{ - label: secondProviderId, - parameters: context.activeSignatureHelp ? context.activeSignatureHelp.signatures[0].parameters : [] - }] + value: { + activeParameter: 0, + activeSignature: context.activeSignatureHelp ? context.activeSignatureHelp.activeSignature + 1 : 0, + signatures: [{ + label: secondProviderId, + parameters: context.activeSignatureHelp ? context.activeSignatureHelp.signatures[0].parameters : [] + }] + }, + dispose: () => { } }; } @@ -361,23 +380,23 @@ suite('ParameterHintsModel', () => { editor.trigger('keyboard', Handler.Type, { text: triggerChar }); - const firstHint = await getNextHint(model); - assert.strictEqual(firstHint!.signatures[0].label, firstProviderId); - assert.strictEqual(firstHint!.activeSignature, 0); - assert.strictEqual(firstHint!.signatures[0].parameters[0].label, paramterLabel); + const firstHint = (await getNextHint(model))!.value; + assert.strictEqual(firstHint.signatures[0].label, firstProviderId); + assert.strictEqual(firstHint.activeSignature, 0); + assert.strictEqual(firstHint.signatures[0].parameters[0].label, paramterLabel); - const secondHint = await getNextHint(model); - assert.strictEqual(secondHint!.signatures[0].label, secondProviderId); - assert.strictEqual(secondHint!.activeSignature, 1); - assert.strictEqual(secondHint!.signatures[0].parameters[0].label, paramterLabel); + const secondHint = (await getNextHint(model))!.value; + assert.strictEqual(secondHint.signatures[0].label, secondProviderId); + assert.strictEqual(secondHint.activeSignature, 1); + assert.strictEqual(secondHint.signatures[0].parameters[0].label, paramterLabel); }); }); function getNextHint(model: ParameterHintsModel) { - return new Promise(resolve => { + return new Promise(resolve => { const sub = model.onChangedHints(e => { sub.dispose(); - return resolve(e); + return resolve(e ? { value: e, dispose: () => { } } : undefined); }); }); } diff --git a/src/vs/editor/contrib/referenceSearch/media/chevron-down-hc.svg b/src/vs/editor/contrib/referenceSearch/media/chevron-down-hc.svg deleted file mode 100644 index eca0994a7..000000000 --- a/src/vs/editor/contrib/referenceSearch/media/chevron-down-hc.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/src/vs/editor/contrib/referenceSearch/media/chevron-down-inverse.svg b/src/vs/editor/contrib/referenceSearch/media/chevron-down-inverse.svg deleted file mode 100644 index 0671cba2f..000000000 --- a/src/vs/editor/contrib/referenceSearch/media/chevron-down-inverse.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/src/vs/editor/contrib/referenceSearch/media/chevron-down.svg b/src/vs/editor/contrib/referenceSearch/media/chevron-down.svg deleted file mode 100644 index 9514d8f31..000000000 --- a/src/vs/editor/contrib/referenceSearch/media/chevron-down.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/src/vs/editor/contrib/referenceSearch/media/chevron-next-dark.svg b/src/vs/editor/contrib/referenceSearch/media/chevron-next-dark.svg new file mode 100644 index 000000000..455532ddb --- /dev/null +++ b/src/vs/editor/contrib/referenceSearch/media/chevron-next-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/referenceSearch/media/chevron-next-light.svg b/src/vs/editor/contrib/referenceSearch/media/chevron-next-light.svg new file mode 100644 index 000000000..a443086f3 --- /dev/null +++ b/src/vs/editor/contrib/referenceSearch/media/chevron-next-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/referenceSearch/media/chevron-previous-dark.svg b/src/vs/editor/contrib/referenceSearch/media/chevron-previous-dark.svg new file mode 100644 index 000000000..5ca352601 --- /dev/null +++ b/src/vs/editor/contrib/referenceSearch/media/chevron-previous-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/referenceSearch/media/chevron-previous-light.svg b/src/vs/editor/contrib/referenceSearch/media/chevron-previous-light.svg new file mode 100644 index 000000000..87e179a7f --- /dev/null +++ b/src/vs/editor/contrib/referenceSearch/media/chevron-previous-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/referenceSearch/media/chevron-up-hc.svg b/src/vs/editor/contrib/referenceSearch/media/chevron-up-hc.svg deleted file mode 100644 index 1c668f52b..000000000 --- a/src/vs/editor/contrib/referenceSearch/media/chevron-up-hc.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/src/vs/editor/contrib/referenceSearch/media/chevron-up-inverse-hc.svg b/src/vs/editor/contrib/referenceSearch/media/chevron-up-inverse-hc.svg deleted file mode 100644 index 1c668f52b..000000000 --- a/src/vs/editor/contrib/referenceSearch/media/chevron-up-inverse-hc.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/src/vs/editor/contrib/referenceSearch/media/chevron-up-inverse.svg b/src/vs/editor/contrib/referenceSearch/media/chevron-up-inverse.svg deleted file mode 100644 index 31bdf3dee..000000000 --- a/src/vs/editor/contrib/referenceSearch/media/chevron-up-inverse.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/src/vs/editor/contrib/referenceSearch/media/chevron-up.svg b/src/vs/editor/contrib/referenceSearch/media/chevron-up.svg deleted file mode 100644 index 7e38887f5..000000000 --- a/src/vs/editor/contrib/referenceSearch/media/chevron-up.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/src/vs/editor/contrib/referenceSearch/media/close-dark.svg b/src/vs/editor/contrib/referenceSearch/media/close-dark.svg new file mode 100644 index 000000000..bffa4e9da --- /dev/null +++ b/src/vs/editor/contrib/referenceSearch/media/close-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/referenceSearch/media/close-inverse.svg b/src/vs/editor/contrib/referenceSearch/media/close-inverse.svg deleted file mode 100644 index 751e89b3b..000000000 --- a/src/vs/editor/contrib/referenceSearch/media/close-inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/referenceSearch/media/close-light.svg b/src/vs/editor/contrib/referenceSearch/media/close-light.svg new file mode 100644 index 000000000..b44dee661 --- /dev/null +++ b/src/vs/editor/contrib/referenceSearch/media/close-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/referenceSearch/media/close.svg b/src/vs/editor/contrib/referenceSearch/media/close.svg deleted file mode 100644 index fde34404d..000000000 --- a/src/vs/editor/contrib/referenceSearch/media/close.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/referenceSearch/media/peekViewWidget.css b/src/vs/editor/contrib/referenceSearch/media/peekViewWidget.css index 67fb333dd..8b5b64413 100644 --- a/src/vs/editor/contrib/referenceSearch/media/peekViewWidget.css +++ b/src/vs/editor/contrib/referenceSearch/media/peekViewWidget.css @@ -19,14 +19,6 @@ cursor: pointer; } -.monaco-editor .peekview-widget .head .peekview-title .icon { - display: inline-block; - height: 16px; - width: 16px; - vertical-align: text-bottom; - margin-right: 4px; -} - .monaco-editor .peekview-widget .head .peekview-title .dirname:not(:empty) { font-size: 0.9em; margin-left: 0.5em; @@ -65,7 +57,7 @@ } .monaco-editor .peekview-widget .head .peekview-actions .action-label.icon.close-peekview-action { - background: url('close.svg') center center no-repeat; + background: url('close-light.svg') center center no-repeat; } .monaco-editor .peekview-widget > .body { @@ -78,30 +70,23 @@ .monaco-editor.hc-black .peekview-widget .head .peekview-actions .action-label.icon.close-peekview-action, .monaco-editor.vs-dark .peekview-widget .head .peekview-actions .action-label.icon.close-peekview-action { - background: url('close-inverse.svg') center center no-repeat; + background: url('close-dark.svg') center center no-repeat; } .monaco-editor .peekview-widget .peekview-actions .icon.chevron-up { - background: url('chevron-up-inverse.svg') center center no-repeat; -} - -.vs-dark .monaco-editor .peekview-widget .peekview-actions .icon.chevron-up { - background: url('chevron-up.svg') center center no-repeat; + background: url('chevron-previous-light.svg') center center no-repeat; } +.vs-dark .monaco-editor .peekview-widget .peekview-actions .icon.chevron-up, .hc-black .monaco-editor .peekview-widget .peekview-actions .icon.chevron-up { - background: url('chevron-up-inverse-hc.svg') center center no-repeat; + background: url('chevron-previous-dark.svg') center center no-repeat; } .monaco-editor .peekview-widget .peekview-actions .icon.chevron-down { - background: url('chevron-down-inverse.svg') center center no-repeat; -} - -.vs-dark .monaco-editor .peekview-widget .peekview-actions .icon.chevron-down { - background: url('chevron-down.svg') center center no-repeat; + background: url('chevron-next-light.svg') center center no-repeat; } +.vs-dark .monaco-editor .peekview-widget .peekview-actions .icon.chevron-down, .hc-black .monaco-editor .peekview-widget .peekview-actions .icon.chevron-down { - background: url('chevron-down-hc.svg') center center no-repeat; -} - + background: url('chevron-next-dark.svg') center center no-repeat; +} \ No newline at end of file diff --git a/src/vs/editor/contrib/referenceSearch/peekViewWidget.ts b/src/vs/editor/contrib/referenceSearch/peekViewWidget.ts index a2c2f81aa..c40368e03 100644 --- a/src/vs/editor/contrib/referenceSearch/peekViewWidget.ts +++ b/src/vs/editor/contrib/referenceSearch/peekViewWidget.ts @@ -85,7 +85,6 @@ export abstract class PeekViewWidget extends ZoneWidget { private _onDidClose = new Emitter(); protected _headElement: HTMLDivElement; - protected _headingIcon: HTMLElement; protected _primaryHeading: HTMLElement; protected _secondaryHeading: HTMLElement; protected _metaHeading: HTMLElement; @@ -155,18 +154,18 @@ export abstract class PeekViewWidget extends ZoneWidget { dom.append(this._headElement, titleElement); dom.addStandardDisposableListener(titleElement, 'click', event => this._onTitleClick(event)); - this._headingIcon = dom.$('span'); + this._fillTitleIcon(titleElement); this._primaryHeading = dom.$('span.filename'); this._secondaryHeading = dom.$('span.dirname'); this._metaHeading = dom.$('span.meta'); - dom.append(titleElement, this._headingIcon, this._primaryHeading, this._secondaryHeading, this._metaHeading); + dom.append(titleElement, this._primaryHeading, this._secondaryHeading, this._metaHeading); const actionsContainer = dom.$('.peekview-actions'); dom.append(this._headElement, actionsContainer); const actionBarOptions = this._getActionBarOptions(); this._actionbarWidget = new ActionBar(actionsContainer, actionBarOptions); - this._disposables.push(this._actionbarWidget); + this._disposables.add(this._actionbarWidget); this._actionbarWidget.push(new Action('peekview.close', nls.localize('label.close', "Close"), 'close-peekview-action', true, () => { this.dispose(); @@ -174,6 +173,9 @@ export abstract class PeekViewWidget extends ZoneWidget { }), { label: false, icon: true }); } + protected _fillTitleIcon(container: HTMLElement): void { + } + protected _getActionBarOptions(): IActionBarOptions { return {}; } @@ -182,10 +184,6 @@ export abstract class PeekViewWidget extends ZoneWidget { // implement me } - public setTitleIcon(iconClassName: string): void { - this._headingIcon.className = iconClassName ? `icon ${iconClassName}` : ''; - } - public setTitle(primaryHeading: string, secondaryHeading?: string): void { this._primaryHeading.innerHTML = strings.escape(primaryHeading); this._primaryHeading.setAttribute('aria-label', primaryHeading); diff --git a/src/vs/editor/contrib/referenceSearch/referenceSearch.ts b/src/vs/editor/contrib/referenceSearch/referenceSearch.ts index fcee1228e..97d8aa5db 100644 --- a/src/vs/editor/contrib/referenceSearch/referenceSearch.ts +++ b/src/vs/editor/contrib/referenceSearch/referenceSearch.ts @@ -27,6 +27,7 @@ import { CommandsRegistry, ICommandHandler } from 'vs/platform/commands/common/c import { URI } from 'vs/base/common/uri'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { CancellationToken } from 'vs/base/common/cancellation'; +import { coalesce, flatten } from 'vs/base/common/arrays'; export const defaultReferenceSearchOptions: RequestOptions = { getMetaTitle(model) { @@ -61,7 +62,7 @@ export class ReferenceAction extends EditorAction { super({ id: 'editor.action.referenceSearch.trigger', label: nls.localize('references.action.label', "Peek References"), - alias: 'Find All References', // leave the alias? + alias: 'Peek References', precondition: ContextKeyExpr.and( EditorContextKeys.hasReferenceProvider, PeekContext.notInPeekEditor, @@ -287,15 +288,7 @@ export function provideReferences(model: ITextModel, position: Position, token: }); }); - return Promise.all(promises).then(references => { - let result: Location[] = []; - for (let ref of references) { - if (ref) { - result.push(...ref); - } - } - return result; - }); + return Promise.all(promises).then(references => flatten(coalesce(references))); } registerDefaultLanguageCommand('_executeReferenceProvider', (model, position) => provideReferences(model, position, CancellationToken.None)); diff --git a/src/vs/editor/contrib/referenceSearch/referencesController.ts b/src/vs/editor/contrib/referenceSearch/referencesController.ts index 928a3809a..0f756a445 100644 --- a/src/vs/editor/contrib/referenceSearch/referencesController.ts +++ b/src/vs/editor/contrib/referenceSearch/referencesController.ts @@ -5,7 +5,7 @@ import * as nls from 'vs/nls'; import { onUnexpectedError } from 'vs/base/common/errors'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { dispose, DisposableStore } from 'vs/base/common/lifecycle'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; @@ -32,11 +32,11 @@ export abstract class ReferencesController implements editorCommon.IEditorContri private static readonly ID = 'editor.contrib.referencesController'; + private readonly _disposables = new DisposableStore(); private readonly _editor: ICodeEditor; private _widget: ReferenceWidget | null; private _model: ReferencesModel | null; private _requestIdPool = 0; - private _disposables: IDisposable[] = []; private _ignoreModelChangeEvent = false; private readonly _referenceSearchVisible: IContextKey; @@ -91,8 +91,8 @@ export abstract class ReferencesController implements editorCommon.IEditorContri this._referenceSearchVisible.set(true); // close the widget on model/mode changes - this._disposables.push(this._editor.onDidChangeModelLanguage(() => { this.closeWidget(); })); - this._disposables.push(this._editor.onDidChangeModel(() => { + this._disposables.add(this._editor.onDidChangeModelLanguage(() => { this.closeWidget(); })); + this._disposables.add(this._editor.onDidChangeModel(() => { if (!this._ignoreModelChangeEvent) { this.closeWidget(); } @@ -103,7 +103,7 @@ export abstract class ReferencesController implements editorCommon.IEditorContri this._widget.setTitle(nls.localize('labelLoading', "Loading...")); this._widget.show(range); - this._disposables.push(this._widget.onDidClose(() => { + this._disposables.add(this._widget.onDidClose(() => { modelPromise.cancel(); if (this._widget) { this._storageService.store(storageKey, JSON.stringify(this._widget.layoutData), StorageScope.GLOBAL); @@ -112,7 +112,7 @@ export abstract class ReferencesController implements editorCommon.IEditorContri this.closeWidget(); })); - this._disposables.push(this._widget.onDidSelectReference(event => { + this._disposables.add(this._widget.onDidSelectReference(event => { let { element, kind } = event; switch (kind) { case 'open': @@ -205,7 +205,7 @@ export abstract class ReferencesController implements editorCommon.IEditorContri this._widget = null; } this._referenceSearchVisible.reset(); - this._disposables = dispose(this._disposables); + this._disposables.clear(); if (this._model) { dispose(this._model); this._model = null; diff --git a/src/vs/editor/contrib/referenceSearch/referencesModel.ts b/src/vs/editor/contrib/referenceSearch/referencesModel.ts index 29b3d8aa0..591092048 100644 --- a/src/vs/editor/contrib/referenceSearch/referencesModel.ts +++ b/src/vs/editor/contrib/referenceSearch/referencesModel.ts @@ -6,7 +6,7 @@ import { localize } from 'vs/nls'; import { Event, Emitter } from 'vs/base/common/event'; import { basename } from 'vs/base/common/resources'; -import { IDisposable, dispose, IReference } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, IReference, DisposableStore } from 'vs/base/common/lifecycle'; import * as strings from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; import { defaultGenerator } from 'vs/base/common/idGenerator'; @@ -14,6 +14,7 @@ import { Range, IRange } from 'vs/editor/common/core/range'; import { Location, LocationLink } from 'vs/editor/common/modes'; import { ITextModelService, ITextEditorModel } from 'vs/editor/common/services/resolverService'; import { Position } from 'vs/editor/common/core/position'; +import { IMatch } from 'vs/base/common/filters'; export class OneReference { readonly id: string; @@ -61,7 +62,7 @@ export class FilePreview implements IDisposable { dispose(this._modelReference); } - preview(range: IRange, n: number = 8): { before: string; inside: string; after: string } | undefined { + preview(range: IRange, n: number = 8): { value: string; highlight: IMatch } | undefined { const model = this._modelReference.object.textEditorModel; if (!model) { @@ -73,13 +74,14 @@ export class FilePreview implements IDisposable { const beforeRange = new Range(startLineNumber, word.startColumn, startLineNumber, startColumn); const afterRange = new Range(endLineNumber, endColumn, endLineNumber, Number.MAX_VALUE); - const ret = { - before: model.getValueInRange(beforeRange).replace(/^\s+/, strings.empty), - inside: model.getValueInRange(range), - after: model.getValueInRange(afterRange).replace(/\s+$/, strings.empty) - }; + const before = model.getValueInRange(beforeRange).replace(/^\s+/, strings.empty); + const inside = model.getValueInRange(range); + const after = model.getValueInRange(afterRange).replace(/\s+$/, strings.empty); - return ret; + return { + value: before + inside + after, + highlight: { start: before.length, end: before.length + inside.length } + }; } } @@ -164,7 +166,7 @@ export class FileReferences implements IDisposable { export class ReferencesModel implements IDisposable { - private readonly _disposables: IDisposable[]; + private readonly _disposables = new DisposableStore(); readonly groups: FileReferences[] = []; readonly references: OneReference[] = []; @@ -172,7 +174,7 @@ export class ReferencesModel implements IDisposable { readonly onDidChangeReferenceRange: Event = this._onDidChangeReferenceRange.event; constructor(references: LocationLink[]) { - this._disposables = []; + // grouping and sorting const [providersFirst] = references; references.sort(ReferencesModel._compareReferences); @@ -190,7 +192,7 @@ export class ReferencesModel implements IDisposable { || !Range.equalsRange(ref.range, current.children[current.children.length - 1].range)) { let oneRef = new OneReference(current, ref.targetSelectionRange || ref.range, providersFirst === ref); - this._disposables.push(oneRef.onRefChanged((e) => this._onDidChangeReferenceRange.fire(e))); + this._disposables.add(oneRef.onRefChanged((e) => this._onDidChangeReferenceRange.fire(e))); this.references.push(oneRef); current.children.push(oneRef); } @@ -280,9 +282,8 @@ export class ReferencesModel implements IDisposable { dispose(): void { dispose(this.groups); - dispose(this._disposables); + this._disposables.dispose(); this.groups.length = 0; - this._disposables.length = 0; } private static _compareReferences(a: Location, b: Location): number { diff --git a/src/vs/editor/contrib/referenceSearch/referencesTree.ts b/src/vs/editor/contrib/referenceSearch/referencesTree.ts index 2a8388900..e563158bd 100644 --- a/src/vs/editor/contrib/referenceSearch/referencesTree.ts +++ b/src/vs/editor/contrib/referenceSearch/referencesTree.ts @@ -15,7 +15,6 @@ import * as dom from 'vs/base/browser/dom'; import { localize } from 'vs/nls'; import { getBaseLabel } from 'vs/base/common/labels'; import { dirname, basename } from 'vs/base/common/resources'; -import { escape } from 'vs/base/common/strings'; import { Disposable } from 'vs/base/common/lifecycle'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget'; @@ -23,6 +22,7 @@ import { IListVirtualDelegate, IKeyboardNavigationLabelProvider, IIdentityProvid import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { FuzzyScore, createMatches, IMatch } from 'vs/base/common/filters'; +import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel'; //#region data source @@ -82,8 +82,14 @@ export class StringRepresentationProvider implements IKeyboardNavigationLabelPro constructor(@IKeybindingService private readonly _keybindingService: IKeybindingService) { } getKeyboardNavigationLabel(element: TreeElement): { toString(): string; } { - // todo@joao `OneReference` elements are lazy and their "real" label - // isn't known yet + if (element instanceof OneReference) { + const { preview } = element.parent; + const parts = preview && preview.preview(element.range); + if (parts) { + return parts.value; + } + } + // FileReferences or unresolved OneReference return basename(element.uri); } @@ -161,31 +167,29 @@ export class FileReferencesRenderer implements ITreeRenderer, index: number, templateData: OneReferenceTemplate): void { - templateData.set(element.element); + renderElement(node: ITreeNode, index: number, templateData: OneReferenceTemplate): void { + templateData.set(node.element, node.filterData); } disposeTemplate(): void { - // } } diff --git a/src/vs/editor/contrib/referenceSearch/referencesWidget.ts b/src/vs/editor/contrib/referenceSearch/referencesWidget.ts index cfb4b6f93..20fc37f55 100644 --- a/src/vs/editor/contrib/referenceSearch/referencesWidget.ts +++ b/src/vs/editor/contrib/referenceSearch/referencesWidget.ts @@ -8,7 +8,7 @@ import { IMouseEvent } from 'vs/base/browser/mouseEvent'; import { Orientation } from 'vs/base/browser/ui/sash/sash'; import { Color } from 'vs/base/common/color'; import { Emitter, Event } from 'vs/base/common/event'; -import { dispose, IDisposable, IReference } from 'vs/base/common/lifecycle'; +import { dispose, IDisposable, IReference, DisposableStore } from 'vs/base/common/lifecycle'; import { Schemas } from 'vs/base/common/network'; import { basenameOrAuthority, dirname } from 'vs/base/common/resources'; import 'vs/css!./media/referencesWidget'; @@ -47,22 +47,22 @@ class DecorationsManager implements IDisposable { private _decorations = new Map(); private _decorationIgnoreSet = new Set(); - private _callOnDispose: IDisposable[] = []; - private _callOnModelChange: IDisposable[] = []; + private readonly _callOnDispose = new DisposableStore(); + private readonly _callOnModelChange = new DisposableStore(); constructor(private _editor: ICodeEditor, private _model: ReferencesModel) { - this._callOnDispose.push(this._editor.onDidChangeModel(() => this._onModelChanged())); + this._callOnDispose.add(this._editor.onDidChangeModel(() => this._onModelChanged())); this._onModelChanged(); } public dispose(): void { - this._callOnModelChange = dispose(this._callOnModelChange); - this._callOnDispose = dispose(this._callOnDispose); + this._callOnModelChange.dispose(); + this._callOnDispose.dispose(); this.removeDecorations(); } private _onModelChanged(): void { - this._callOnModelChange = dispose(this._callOnModelChange); + this._callOnModelChange.clear(); const model = this._editor.getModel(); if (model) { for (const ref of this._model.groups) { @@ -78,7 +78,7 @@ class DecorationsManager implements IDisposable { if (!this._editor.hasModel()) { return; } - this._callOnModelChange.push(this._editor.getModel().onDidChangeDecorations((event) => this._onDecorationChanged())); + this._callOnModelChange.add(this._editor.getModel().onDidChangeDecorations((event) => this._onDecorationChanged())); const newDecorations: IModelDeltaDecoration[] = []; const newDecorationsActualIndex: number[] = []; @@ -194,8 +194,8 @@ export class ReferenceWidget extends PeekViewWidget { private _model: ReferencesModel | undefined; private _decorationsManager: DecorationsManager; - private _disposeOnNewModel: IDisposable[] = []; - private _callOnDispose: IDisposable[] = []; + private readonly _disposeOnNewModel = new DisposableStore(); + private readonly _callOnDispose = new DisposableStore(); private _onDidSelectReference = new Emitter(); private _tree: WorkbenchAsyncDataTree; @@ -222,15 +222,19 @@ export class ReferenceWidget extends PeekViewWidget { super(editor, { showFrame: false, showArrow: true, isResizeable: true, isAccessible: true }); this._applyTheme(themeService.getTheme()); - this._callOnDispose.push(themeService.onThemeChange(this._applyTheme.bind(this))); + this._callOnDispose.add(themeService.onThemeChange(this._applyTheme.bind(this))); this._peekViewService.addExclusiveWidget(editor, this); this.create(); } dispose(): void { this.setModel(undefined); - this._callOnDispose = dispose(this._callOnDispose); - dispose(this._preview, this._previewNotAvailableMessage, this._tree, this._previewModelReference); + this._callOnDispose.dispose(); + this._disposeOnNewModel.dispose(); + dispose(this._preview); + dispose(this._previewNotAvailableMessage); + dispose(this._tree); + dispose(this._previewModelReference); this._splitView.dispose(); super.dispose(); } @@ -344,11 +348,11 @@ export class ReferenceWidget extends PeekViewWidget { } }, Sizing.Distribute); - this._splitView.onDidSashChange(() => { + this._disposables.add(this._splitView.onDidSashChange(() => { if (this._dim.width) { this.layoutData.ratio = this._splitView.getViewSize(0) / this._dim.width; } - }, undefined, this._disposables); + }, undefined)); // listen on selection and focus let onEvent = (element: any, kind: 'show' | 'goto' | 'side') => { @@ -421,7 +425,7 @@ export class ReferenceWidget extends PeekViewWidget { public setModel(newModel: ReferencesModel | undefined): Promise { // clean up - this._disposeOnNewModel = dispose(this._disposeOnNewModel); + this._disposeOnNewModel.clear(); this._model = newModel; if (this._model) { return this._onNewModel(); @@ -443,13 +447,13 @@ export class ReferenceWidget extends PeekViewWidget { dom.hide(this._messageContainer); this._decorationsManager = new DecorationsManager(this._preview, this._model); - this._disposeOnNewModel.push(this._decorationsManager); + this._disposeOnNewModel.add(this._decorationsManager); // listen on model changes - this._disposeOnNewModel.push(this._model.onDidChangeReferenceRange(reference => this._tree.rerender(reference))); + this._disposeOnNewModel.add(this._model.onDidChangeReferenceRange(reference => this._tree.rerender(reference))); // listen on editor - this._disposeOnNewModel.push(this._preview.onMouseDown(e => { + this._disposeOnNewModel.add(this._preview.onMouseDown(e => { const { event, target } = e; if (event.detail !== 2) { return; @@ -566,7 +570,7 @@ export const peekViewEditorMatchHighlightBorder = registerColor('peekViewEditor. registerThemingParticipant((theme, collector) => { const findMatchHighlightColor = theme.getColor(peekViewResultsMatchHighlight); if (findMatchHighlightColor) { - collector.addRule(`.monaco-editor .reference-zone-widget .ref-tree .referenceMatch { background-color: ${findMatchHighlightColor}; }`); + collector.addRule(`.monaco-editor .reference-zone-widget .ref-tree .referenceMatch .highlight { background-color: ${findMatchHighlightColor}; }`); } const referenceHighlightColor = theme.getColor(peekViewEditorMatchHighlight); if (referenceHighlightColor) { @@ -578,7 +582,7 @@ registerThemingParticipant((theme, collector) => { } const hcOutline = theme.getColor(activeContrastBorder); if (hcOutline) { - collector.addRule(`.monaco-editor .reference-zone-widget .ref-tree .referenceMatch { border: 1px dotted ${hcOutline}; box-sizing: border-box; }`); + collector.addRule(`.monaco-editor .reference-zone-widget .ref-tree .referenceMatch .highlight { border: 1px dotted ${hcOutline}; box-sizing: border-box; }`); } const resultsBackground = theme.getColor(peekViewResultsBackground); if (resultsBackground) { diff --git a/src/vs/editor/contrib/rename/rename.ts b/src/vs/editor/contrib/rename/rename.ts index 460fcc040..ab0698289 100644 --- a/src/vs/editor/contrib/rename/rename.ts +++ b/src/vs/editor/contrib/rename/rename.ts @@ -7,7 +7,7 @@ import * as nls from 'vs/nls'; import { illegalArgument, onUnexpectedError } from 'vs/base/common/errors'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { IProgressService } from 'vs/platform/progress/common/progress'; +import { IEditorProgressService } from 'vs/platform/progress/common/progress'; import { registerEditorAction, registerEditorContribution, ServicesAccessor, EditorAction, EditorCommand, registerEditorCommand, registerDefaultLanguageCommand } from 'vs/editor/browser/editorExtensions'; import { IEditorContribution } from 'vs/editor/common/editorCommon'; import { ITextModel } from 'vs/editor/common/model'; @@ -114,7 +114,7 @@ class RenameController extends Disposable implements IEditorContribution { private readonly editor: ICodeEditor, @INotificationService private readonly _notificationService: INotificationService, @IBulkEditService private readonly _bulkEditService: IBulkEditService, - @IProgressService private readonly _progressService: IProgressService, + @IEditorProgressService private readonly _progressService: IEditorProgressService, @IContextKeyService private readonly _contextKeyService: IContextKeyService, @IThemeService private readonly _themeService: IThemeService, ) { diff --git a/src/vs/editor/contrib/rename/renameInputField.ts b/src/vs/editor/contrib/rename/renameInputField.ts index b1dce91bf..85e4c9569 100644 --- a/src/vs/editor/contrib/rename/renameInputField.ts +++ b/src/vs/editor/contrib/rename/renameInputField.ts @@ -3,8 +3,8 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import 'vs/css!./renameInputField'; +import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; import { Position } from 'vs/editor/common/core/position'; import { IRange, Range } from 'vs/editor/common/core/range'; @@ -24,10 +24,10 @@ export class RenameInputField implements IContentWidget, IDisposable { private _inputField: HTMLInputElement; private _visible: boolean; private readonly _visibleContextKey: IContextKey; - private _disposables: IDisposable[] = []; + private readonly _disposables = new DisposableStore(); // Editor.IContentWidget.allowEditorOverflow - public allowEditorOverflow: boolean = true; + allowEditorOverflow: boolean = true; constructor( editor: ICodeEditor, @@ -39,13 +39,13 @@ export class RenameInputField implements IContentWidget, IDisposable { this._editor = editor; this._editor.addContentWidget(this); - this._disposables.push(editor.onDidChangeConfiguration(e => { + this._disposables.add(editor.onDidChangeConfiguration(e => { if (e.fontInfo) { this.updateFont(); } })); - this._disposables.push(themeService.onThemeChange(theme => this.onThemeChange(theme))); + this._disposables.add(themeService.onThemeChange(theme => this.onThemeChange(theme))); } private onThemeChange(theme: ITheme): void { @@ -53,7 +53,7 @@ export class RenameInputField implements IContentWidget, IDisposable { } public dispose(): void { - this._disposables = dispose(this._disposables); + this._disposables.dispose(); this._editor.removeContentWidget(this); } @@ -138,9 +138,9 @@ export class RenameInputField implements IContentWidget, IDisposable { this._inputField.setAttribute('selectionEnd', selectionEnd.toString()); this._inputField.size = Math.max((where.endColumn - where.startColumn) * 1.1, 20); - const disposeOnDone: IDisposable[] = []; + const disposeOnDone = new DisposableStore(); const always = () => { - dispose(disposeOnDone); + disposeOnDone.dispose(); this._hide(); }; @@ -172,8 +172,8 @@ export class RenameInputField implements IContentWidget, IDisposable { } }; - disposeOnDone.push(this._editor.onDidChangeCursorSelection(onCursorChanged)); - disposeOnDone.push(this._editor.onDidBlurEditorWidget(() => this.cancelInput(false))); + disposeOnDone.add(this._editor.onDidChangeCursorSelection(onCursorChanged)); + disposeOnDone.add(this._editor.onDidBlurEditorWidget(() => this.cancelInput(false))); this._show(); diff --git a/src/vs/editor/contrib/smartSelect/bracketSelections.ts b/src/vs/editor/contrib/smartSelect/bracketSelections.ts index 6bd8d8842..728c4573f 100644 --- a/src/vs/editor/contrib/smartSelect/bracketSelections.ts +++ b/src/vs/editor/contrib/smartSelect/bracketSelections.ts @@ -115,8 +115,8 @@ export class BracketSelectionRangeProvider implements SelectionRangeProvider { } const innerBracket = Range.fromPositions(bracket.range.getEndPosition(), closing!.getStartPosition()); const outerBracket = Range.fromPositions(bracket.range.getStartPosition(), closing!.getEndPosition()); - bucket.push({ range: innerBracket, kind: 'statement.brackets' }); - bucket.push({ range: outerBracket, kind: 'statement.brackets.full' }); + bucket.push({ range: innerBracket }); + bucket.push({ range: outerBracket }); BracketSelectionRangeProvider._addBracketLeading(model, outerBracket, bucket); } } @@ -135,8 +135,8 @@ export class BracketSelectionRangeProvider implements SelectionRangeProvider { const startLine = bracket.startLineNumber; const column = model.getLineFirstNonWhitespaceColumn(startLine); if (column !== 0 && column !== bracket.startColumn) { - bucket.push({ range: Range.fromPositions(new Position(startLine, column), bracket.getEndPosition()), kind: 'statement.brackets.leading' }); - bucket.push({ range: Range.fromPositions(new Position(startLine, 1), bracket.getEndPosition()), kind: 'statement.brackets.leading.full' }); + bucket.push({ range: Range.fromPositions(new Position(startLine, column), bracket.getEndPosition()) }); + bucket.push({ range: Range.fromPositions(new Position(startLine, 1), bracket.getEndPosition()) }); } // xxxxxxxx @@ -147,8 +147,8 @@ export class BracketSelectionRangeProvider implements SelectionRangeProvider { if (aboveLine > 0) { const column = model.getLineFirstNonWhitespaceColumn(aboveLine); if (column === bracket.startColumn && column !== model.getLineLastNonWhitespaceColumn(aboveLine)) { - bucket.push({ range: Range.fromPositions(new Position(aboveLine, column), bracket.getEndPosition()), kind: 'statement.brackets.leading' }); - bucket.push({ range: Range.fromPositions(new Position(aboveLine, 1), bracket.getEndPosition()), kind: 'statement.brackets.leading.full' }); + bucket.push({ range: Range.fromPositions(new Position(aboveLine, column), bracket.getEndPosition()) }); + bucket.push({ range: Range.fromPositions(new Position(aboveLine, 1), bracket.getEndPosition()) }); } } } diff --git a/src/vs/editor/contrib/smartSelect/smartSelect.ts b/src/vs/editor/contrib/smartSelect/smartSelect.ts index f8edd2156..4fe561f4c 100644 --- a/src/vs/editor/contrib/smartSelect/smartSelect.ts +++ b/src/vs/editor/contrib/smartSelect/smartSelect.ts @@ -161,7 +161,7 @@ class GrowSelectionAction extends AbstractSmartSelect { id: 'editor.action.smartSelect.expand', label: nls.localize('smartSelect.expand', "Expand Selection"), alias: 'Expand Selection', - precondition: null, + precondition: undefined, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.Shift | KeyMod.Alt | KeyCode.RightArrow, @@ -187,7 +187,7 @@ class ShrinkSelectionAction extends AbstractSmartSelect { id: 'editor.action.smartSelect.shrink', label: nls.localize('smartSelect.shrink', "Shrink Selection"), alias: 'Shrink Selection', - precondition: null, + precondition: undefined, kbOpts: { kbExpr: EditorContextKeys.editorTextFocus, primary: KeyMod.Shift | KeyMod.Alt | KeyCode.LeftArrow, @@ -284,12 +284,12 @@ export function provideSelectionRanges(model: ITextModel, positions: Position[], if (cur.startLineNumber !== prev.startLineNumber || cur.endLineNumber !== prev.endLineNumber) { // add line/block range without leading/failing whitespace const rangeNoWhitespace = new Range(prev.startLineNumber, model.getLineFirstNonWhitespaceColumn(prev.startLineNumber), prev.endLineNumber, model.getLineLastNonWhitespaceColumn(prev.endLineNumber)); - if (rangeNoWhitespace.containsRange(prev) && !rangeNoWhitespace.equalsRange(prev)) { + if (rangeNoWhitespace.containsRange(prev) && !rangeNoWhitespace.equalsRange(prev) && cur.containsRange(rangeNoWhitespace) && !cur.equalsRange(rangeNoWhitespace)) { oneRangesWithTrivia.push(rangeNoWhitespace); } // add line/block range const rangeFull = new Range(prev.startLineNumber, 1, prev.endLineNumber, model.getLineMaxColumn(prev.endLineNumber)); - if (rangeFull.containsRange(prev) && !rangeFull.equalsRange(rangeNoWhitespace)) { + if (rangeFull.containsRange(prev) && !rangeFull.equalsRange(rangeNoWhitespace) && cur.containsRange(rangeFull) && !cur.equalsRange(rangeFull)) { oneRangesWithTrivia.push(rangeFull); } } diff --git a/src/vs/editor/contrib/smartSelect/test/smartSelect.test.ts b/src/vs/editor/contrib/smartSelect/test/smartSelect.test.ts index de3a2ed6a..4263a1b4a 100644 --- a/src/vs/editor/contrib/smartSelect/test/smartSelect.test.ts +++ b/src/vs/editor/contrib/smartSelect/test/smartSelect.test.ts @@ -6,7 +6,7 @@ import * as assert from 'assert'; import { URI } from 'vs/base/common/uri'; import { Range, IRange } from 'vs/editor/common/core/range'; import { Position } from 'vs/editor/common/core/position'; -import { LanguageIdentifier, SelectionRangeProvider } from 'vs/editor/common/modes'; +import { LanguageIdentifier, SelectionRangeProvider, SelectionRangeRegistry } from 'vs/editor/common/modes'; import { MockMode, StaticLanguageSelector } from 'vs/editor/test/common/mocks/mockMode'; import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; @@ -320,4 +320,25 @@ suite('SmartSelect', () => { new Range(1, 1, 1, 21), ); }); + + test('Smart select: only add line ranges if they’re contained by the next range #73850', async function () { + + const reg = SelectionRangeRegistry.register('*', { + provideSelectionRanges() { + return [[ + { range: { startLineNumber: 1, startColumn: 10, endLineNumber: 1, endColumn: 11 } }, + { range: { startLineNumber: 1, startColumn: 10, endLineNumber: 3, endColumn: 2 } }, + { range: { startLineNumber: 1, startColumn: 1, endLineNumber: 3, endColumn: 2 } }, + ]]; + } + }); + + await assertGetRangesToPosition(['type T = {', '\tx: number', '}'], 1, 10, [ + new Range(1, 1, 3, 2), // all + new Range(1, 10, 3, 2), // { ... } + new Range(1, 10, 1, 11), // { + ]); + + reg.dispose(); + }); }); diff --git a/src/vs/editor/contrib/smartSelect/wordSelections.ts b/src/vs/editor/contrib/smartSelect/wordSelections.ts index 1dcabbd65..7402202af 100644 --- a/src/vs/editor/contrib/smartSelect/wordSelections.ts +++ b/src/vs/editor/contrib/smartSelect/wordSelections.ts @@ -20,7 +20,7 @@ export class WordSelectionRangeProvider implements SelectionRangeProvider { this._addInWordRanges(bucket, model, position); this._addWordRanges(bucket, model, position); this._addWhitespaceLine(bucket, model, position); - bucket.push({ range: model.getFullModelRange(), kind: 'statement.all' }); + bucket.push({ range: model.getFullModelRange() }); } return result; } @@ -65,14 +65,14 @@ export class WordSelectionRangeProvider implements SelectionRangeProvider { } if (start < end) { - bucket.push({ range: new Range(pos.lineNumber, startColumn + start, pos.lineNumber, startColumn + end), kind: 'statement.word.part' }); + bucket.push({ range: new Range(pos.lineNumber, startColumn + start, pos.lineNumber, startColumn + end) }); } } private _addWordRanges(bucket: SelectionRange[], model: ITextModel, pos: Position): void { const word = model.getWordAtPosition(pos); if (word) { - bucket.push({ range: new Range(pos.lineNumber, word.startColumn, pos.lineNumber, word.endColumn), kind: 'statement.word' }); + bucket.push({ range: new Range(pos.lineNumber, word.startColumn, pos.lineNumber, word.endColumn) }); } } @@ -81,7 +81,7 @@ export class WordSelectionRangeProvider implements SelectionRangeProvider { && model.getLineFirstNonWhitespaceColumn(pos.lineNumber) === 0 && model.getLineLastNonWhitespaceColumn(pos.lineNumber) === 0 ) { - bucket.push({ range: new Range(pos.lineNumber, 1, pos.lineNumber, model.getLineMaxColumn(pos.lineNumber)), kind: 'statement.line' }); + bucket.push({ range: new Range(pos.lineNumber, 1, pos.lineNumber, model.getLineMaxColumn(pos.lineNumber)) }); } } } diff --git a/src/vs/editor/contrib/snippet/snippetController2.ts b/src/vs/editor/contrib/snippet/snippetController2.ts index daccfa9ee..c24659b44 100644 --- a/src/vs/editor/contrib/snippet/snippetController2.ts +++ b/src/vs/editor/contrib/snippet/snippetController2.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import { dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { dispose, DisposableStore } from 'vs/base/common/lifecycle'; import { repeat } from 'vs/base/common/strings'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorCommand, registerEditorCommand, registerEditorContribution } from 'vs/editor/browser/editorExtensions'; @@ -20,6 +20,24 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis import { ILogService } from 'vs/platform/log/common/log'; import { SnippetSession } from './snippetSession'; +export interface ISnippetInsertOptions { + overwriteBefore: number; + overwriteAfter: number; + adjustWhitespace: boolean; + undoStopBefore: boolean; + undoStopAfter: boolean; + clipboardText: string | undefined; +} + +const _defaultOptions: ISnippetInsertOptions = { + overwriteBefore: 0, + overwriteAfter: 0, + undoStopBefore: true, + undoStopAfter: true, + adjustWhitespace: true, + clipboardText: undefined +}; + export class SnippetController2 implements IEditorContribution { static get(editor: ICodeEditor): SnippetController2 { @@ -35,7 +53,7 @@ export class SnippetController2 implements IEditorContribution { private readonly _hasPrevTabstop: IContextKey; private _session?: SnippetSession; - private _snippetListener: IDisposable[] = []; + private _snippetListener = new DisposableStore(); private _modelVersionId: number; private _currentChoice?: Choice; @@ -54,6 +72,7 @@ export class SnippetController2 implements IEditorContribution { this._hasPrevTabstop.reset(); this._hasNextTabstop.reset(); dispose(this._session); + this._snippetListener.dispose(); } getId(): string { @@ -62,15 +81,13 @@ export class SnippetController2 implements IEditorContribution { insert( template: string, - overwriteBefore: number = 0, overwriteAfter: number = 0, - undoStopBefore: boolean = true, undoStopAfter: boolean = true, - adjustWhitespace: boolean = true, + opts?: Partial ): void { // this is here to find out more about the yet-not-understood // error that sometimes happens when we fail to inserted a nested // snippet try { - this._doInsert(template, overwriteBefore, overwriteAfter, undoStopBefore, undoStopAfter, adjustWhitespace); + this._doInsert(template, typeof opts === 'undefined' ? _defaultOptions : { ..._defaultOptions, ...opts }); } catch (e) { this.cancel(); @@ -83,9 +100,7 @@ export class SnippetController2 implements IEditorContribution { private _doInsert( template: string, - overwriteBefore: number = 0, overwriteAfter: number = 0, - undoStopBefore: boolean = true, undoStopAfter: boolean = true, - adjustWhitespace: boolean = true, + opts: ISnippetInsertOptions ): void { if (!this._editor.hasModel()) { return; @@ -93,31 +108,29 @@ export class SnippetController2 implements IEditorContribution { // don't listen while inserting the snippet // as that is the inflight state causing cancelation - this._snippetListener = dispose(this._snippetListener); + this._snippetListener.clear(); - if (undoStopBefore) { + if (opts.undoStopBefore) { this._editor.getModel().pushStackElement(); } if (!this._session) { this._modelVersionId = this._editor.getModel().getAlternativeVersionId(); - this._session = new SnippetSession(this._editor, template, overwriteBefore, overwriteAfter, adjustWhitespace); + this._session = new SnippetSession(this._editor, template, opts); this._session.insert(); } else { - this._session.merge(template, overwriteBefore, overwriteAfter, adjustWhitespace); + this._session.merge(template, opts); } - if (undoStopAfter) { + if (opts.undoStopAfter) { this._editor.getModel().pushStackElement(); } this._updateState(); - this._snippetListener = [ - this._editor.onDidChangeModelContent(e => e.isFlush && this.cancel()), - this._editor.onDidChangeModel(() => this.cancel()), - this._editor.onDidChangeCursorSelection(() => this._updateState()) - ]; + this._snippetListener.add(this._editor.onDidChangeModelContent(e => e.isFlush && this.cancel())); + this._snippetListener.add(this._editor.onDidChangeModel(() => this.cancel())); + this._snippetListener.add(this._editor.onDidChangeCursorSelection(() => this._updateState())); } private _updateState(): void { @@ -197,7 +210,7 @@ export class SnippetController2 implements IEditorContribution { this._inSnippet.reset(); this._hasPrevTabstop.reset(); this._hasNextTabstop.reset(); - dispose(this._snippetListener); + this._snippetListener.clear(); dispose(this._session); this._session = undefined; this._modelVersionId = -1; diff --git a/src/vs/editor/contrib/snippet/snippetSession.ts b/src/vs/editor/contrib/snippet/snippetSession.ts index e96f4d80e..6140e4485 100644 --- a/src/vs/editor/contrib/snippet/snippetSession.ts +++ b/src/vs/editor/contrib/snippet/snippetSession.ts @@ -17,11 +17,12 @@ import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { optional } from 'vs/platform/instantiation/common/instantiation'; -import { Choice, Placeholder, SnippetParser, Text, TextmateSnippet } from './snippetParser'; +import { Choice, Placeholder, SnippetParser, Text, TextmateSnippet, Marker } from './snippetParser'; import { ClipboardBasedVariableResolver, CompositeSnippetVariableResolver, ModelBasedVariableResolver, SelectionBasedVariableResolver, TimeBasedVariableResolver, CommentBasedVariableResolver, WorkspaceBasedVariableResolver } from './snippetVariables'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import * as colors from 'vs/platform/theme/common/colorRegistry'; import { withNullAsUndefined } from 'vs/base/common/types'; +import { ILabelService } from 'vs/platform/label/common/label'; registerThemingParticipant((theme, collector) => { @@ -122,14 +123,14 @@ export class OneSnippet { } } - let skipThisPlaceholder = false; + let couldSkipThisPlaceholder = false; if (fwd === true && this._placeholderGroupsIdx < this._placeholderGroups.length - 1) { this._placeholderGroupsIdx += 1; - skipThisPlaceholder = true; + couldSkipThisPlaceholder = true; } else if (fwd === false && this._placeholderGroupsIdx > 0) { this._placeholderGroupsIdx -= 1; - skipThisPlaceholder = true; + couldSkipThisPlaceholder = true; } else { // the selection of the current placeholder might @@ -154,7 +155,7 @@ export class OneSnippet { // consider to skip this placeholder index when the decoration // range is empty but when the placeholder wasn't. that's a strong // hint that the placeholder has been deleted. (all placeholder must match this) - skipThisPlaceholder = skipThisPlaceholder && (range.isEmpty() && placeholder.toString().length > 0); + couldSkipThisPlaceholder = couldSkipThisPlaceholder && this._hasPlaceholderBeenCollapsed(placeholder); accessor.changeDecorationOptions(id, placeholder.isFinalTabstop ? OneSnippet._decor.activeFinal : OneSnippet._decor.active); activePlaceholders.add(placeholder); @@ -177,7 +178,25 @@ export class OneSnippet { return selections; })!; - return !skipThisPlaceholder ? newSelections : this.move(fwd); + return !couldSkipThisPlaceholder ? newSelections : this.move(fwd); + } + + private _hasPlaceholderBeenCollapsed(placeholder: Placeholder): boolean { + // A placeholder is empty when it wasn't empty when authored but + // when its tracking decoration is empty. This also applies to all + // potential parent placeholders + let marker: Marker | undefined = placeholder; + while (marker) { + if (marker instanceof Placeholder) { + const id = this._placeholderDecorations.get(marker)!; + const range = this._editor.getModel().getDecorationRange(id)!; + if (range.isEmpty() && marker.toString().length > 0) { + return true; + } + } + marker = marker.parent; + } + return false; } get isAtFirstPlaceholder() { @@ -297,6 +316,20 @@ export class OneSnippet { } } +export interface ISnippetSessionInsertOptions { + overwriteBefore: number; + overwriteAfter: number; + adjustWhitespace: boolean; + clipboardText: string | undefined; +} + +const _defaultOptions: ISnippetSessionInsertOptions = { + overwriteBefore: 0, + overwriteAfter: 0, + adjustWhitespace: true, + clipboardText: undefined +}; + export class SnippetSession { static adjustWhitespace(model: ITextModel, position: IPosition, snippet: TextmateSnippet): void { @@ -345,7 +378,7 @@ export class SnippetSession { return selection; } - static createEditsAndSnippets(editor: IActiveCodeEditor, template: string, overwriteBefore: number, overwriteAfter: number, enforceFinalTabstop: boolean, adjustWhitespace: boolean): { edits: IIdentifiedSingleEditOperation[], snippets: OneSnippet[] } { + static createEditsAndSnippets(editor: IActiveCodeEditor, template: string, overwriteBefore: number, overwriteAfter: number, enforceFinalTabstop: boolean, adjustWhitespace: boolean, clipboardText: string | undefined): { edits: IIdentifiedSingleEditOperation[], snippets: OneSnippet[] } { const edits: IIdentifiedSingleEditOperation[] = []; const snippets: OneSnippet[] = []; @@ -354,9 +387,11 @@ export class SnippetSession { } const model = editor.getModel(); - const modelBasedVariableResolver = new ModelBasedVariableResolver(model); - const clipboardService = editor.invokeWithinContext(accessor => accessor.get(IClipboardService, optional)); const workspaceService = editor.invokeWithinContext(accessor => accessor.get(IWorkspaceContextService, optional)); + const modelBasedVariableResolver = editor.invokeWithinContext(accessor => new ModelBasedVariableResolver(accessor.get(ILabelService, optional), model)); + + const clipboardService = editor.invokeWithinContext(accessor => accessor.get(IClipboardService, optional)); + clipboardText = clipboardText || clipboardService && clipboardService.readTextSync(); let delta = 0; @@ -409,7 +444,7 @@ export class SnippetSession { snippet.resolveVariables(new CompositeSnippetVariableResolver([ modelBasedVariableResolver, - new ClipboardBasedVariableResolver(clipboardService, idx, indexedSelections.length), + new ClipboardBasedVariableResolver(clipboardText, idx, indexedSelections.length), new SelectionBasedVariableResolver(model, selection), new CommentBasedVariableResolver(model), new TimeBasedVariableResolver, @@ -432,17 +467,13 @@ export class SnippetSession { private readonly _editor: IActiveCodeEditor; private readonly _template: string; private readonly _templateMerges: [number, number, string][] = []; - private readonly _overwriteBefore: number; - private readonly _overwriteAfter: number; - private readonly _adjustWhitespace: boolean; + private readonly _options: ISnippetSessionInsertOptions; private _snippets: OneSnippet[] = []; - constructor(editor: IActiveCodeEditor, template: string, overwriteBefore: number = 0, overwriteAfter: number = 0, adjustWhitespace: boolean = true) { + constructor(editor: IActiveCodeEditor, template: string, options: ISnippetSessionInsertOptions = _defaultOptions) { this._editor = editor; this._template = template; - this._overwriteBefore = overwriteBefore; - this._overwriteAfter = overwriteAfter; - this._adjustWhitespace = adjustWhitespace; + this._options = options; } dispose(): void { @@ -461,7 +492,7 @@ export class SnippetSession { const model = this._editor.getModel(); // make insert edit and start with first selections - const { edits, snippets } = SnippetSession.createEditsAndSnippets(this._editor, this._template, this._overwriteBefore, this._overwriteAfter, false, this._adjustWhitespace); + const { edits, snippets } = SnippetSession.createEditsAndSnippets(this._editor, this._template, this._options.overwriteBefore, this._options.overwriteAfter, false, this._options.adjustWhitespace, this._options.clipboardText); this._snippets = snippets; const selections = model.pushEditOperations(this._editor.getSelections(), edits, undoEdits => { @@ -475,12 +506,12 @@ export class SnippetSession { this._editor.revealRange(selections[0]); } - merge(template: string, overwriteBefore: number = 0, overwriteAfter: number = 0, adjustWhitespace: boolean = true): void { + merge(template: string, options: ISnippetSessionInsertOptions = _defaultOptions): void { if (!this._editor.hasModel()) { return; } this._templateMerges.push([this._snippets[0]._nestingLevel, this._snippets[0]._placeholderGroupsIdx, template]); - const { edits, snippets } = SnippetSession.createEditsAndSnippets(this._editor, template, overwriteBefore, overwriteAfter, true, adjustWhitespace); + const { edits, snippets } = SnippetSession.createEditsAndSnippets(this._editor, template, options.overwriteBefore, options.overwriteAfter, true, options.adjustWhitespace, options.clipboardText); this._editor.setSelections(this._editor.getModel().pushEditOperations(this._editor.getSelections(), edits, undoEdits => { diff --git a/src/vs/editor/contrib/snippet/snippetVariables.ts b/src/vs/editor/contrib/snippet/snippetVariables.ts index 0cca7a56f..b56f15882 100644 --- a/src/vs/editor/contrib/snippet/snippetVariables.ts +++ b/src/vs/editor/contrib/snippet/snippetVariables.ts @@ -4,17 +4,18 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; -import { basename, dirname } from 'vs/base/common/path'; +import * as path from 'vs/base/common/path'; +import { dirname } from 'vs/base/common/resources'; import { ITextModel } from 'vs/editor/common/model'; import { Selection } from 'vs/editor/common/core/selection'; import { VariableResolver, Variable, Text } from 'vs/editor/contrib/snippet/snippetParser'; import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; import { getLeadingWhitespace, commonPrefixLength, isFalsyOrWhitespace, pad, endsWith } from 'vs/base/common/strings'; -import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { isSingleFolderWorkspaceIdentifier, toWorkspaceIdentifier, WORKSPACE_EXTENSION } from 'vs/platform/workspaces/common/workspaces'; +import { ILabelService } from 'vs/platform/label/common/label'; -export const KnownSnippetVariableNames = Object.freeze({ +export const KnownSnippetVariableNames: { [key: string]: true } = Object.freeze({ 'CURRENT_YEAR': true, 'CURRENT_YEAR_SHORT': true, 'CURRENT_MONTH': true, @@ -126,6 +127,7 @@ export class SelectionBasedVariableResolver implements VariableResolver { export class ModelBasedVariableResolver implements VariableResolver { constructor( + private readonly _labelService: ILabelService | undefined, private readonly _model: ITextModel ) { // @@ -136,10 +138,10 @@ export class ModelBasedVariableResolver implements VariableResolver { const { name } = variable; if (name === 'TM_FILENAME') { - return basename(this._model.uri.fsPath); + return path.basename(this._model.uri.fsPath); } else if (name === 'TM_FILENAME_BASE') { - const name = basename(this._model.uri.fsPath); + const name = path.basename(this._model.uri.fsPath); const idx = name.lastIndexOf('.'); if (idx <= 0) { return name; @@ -147,12 +149,14 @@ export class ModelBasedVariableResolver implements VariableResolver { return name.slice(0, idx); } - } else if (name === 'TM_DIRECTORY') { - const dir = dirname(this._model.uri.fsPath); - return dir !== '.' ? dir : ''; + } else if (name === 'TM_DIRECTORY' && this._labelService) { + if (path.dirname(this._model.uri.fsPath) === '.') { + return ''; + } + return this._labelService.getUriLabel(dirname(this._model.uri)); - } else if (name === 'TM_FILEPATH') { - return this._model.uri.fsPath; + } else if (name === 'TM_FILEPATH' && this._labelService) { + return this._labelService.getUriLabel(this._model.uri); } return undefined; @@ -162,7 +166,7 @@ export class ModelBasedVariableResolver implements VariableResolver { export class ClipboardBasedVariableResolver implements VariableResolver { constructor( - private readonly _clipboardService: IClipboardService, + private readonly _clipboardText: string | undefined, private readonly _selectionIdx: number, private readonly _selectionCount: number ) { @@ -170,20 +174,19 @@ export class ClipboardBasedVariableResolver implements VariableResolver { } resolve(variable: Variable): string | undefined { - if (variable.name !== 'CLIPBOARD' || !this._clipboardService) { + if (variable.name !== 'CLIPBOARD') { return undefined; } - const text = this._clipboardService.readText(); - if (!text) { + if (!this._clipboardText) { return undefined; } - const lines = text.split(/\r\n|\n|\r/).filter(s => !isFalsyOrWhitespace(s)); + const lines = this._clipboardText.split(/\r\n|\n|\r/).filter(s => !isFalsyOrWhitespace(s)); if (lines.length === this._selectionCount) { return lines[this._selectionIdx]; } else { - return text; + return this._clipboardText; } } } @@ -250,7 +253,7 @@ export class TimeBasedVariableResolver implements VariableResolver { export class WorkspaceBasedVariableResolver implements VariableResolver { constructor( - private readonly _workspaceService: IWorkspaceContextService, + private readonly _workspaceService: IWorkspaceContextService | undefined, ) { // } @@ -266,13 +269,13 @@ export class WorkspaceBasedVariableResolver implements VariableResolver { } if (isSingleFolderWorkspaceIdentifier(workspaceIdentifier)) { - return basename(workspaceIdentifier.path); + return path.basename(workspaceIdentifier.path); } - let filename = basename(workspaceIdentifier.configPath.path); + let filename = path.basename(workspaceIdentifier.configPath.path); if (endsWith(filename, WORKSPACE_EXTENSION)) { filename = filename.substr(0, filename.length - WORKSPACE_EXTENSION.length - 1); } return filename; } -} \ No newline at end of file +} diff --git a/src/vs/editor/contrib/snippet/test/snippetController2.old.test.ts b/src/vs/editor/contrib/snippet/test/snippetController2.old.test.ts index 9770cb364..c9751d050 100644 --- a/src/vs/editor/contrib/snippet/test/snippetController2.old.test.ts +++ b/src/vs/editor/contrib/snippet/test/snippetController2.old.test.ts @@ -62,7 +62,7 @@ suite('SnippetController', () => { snippetTest((editor, cursor, template, snippetController) => { editor.setPosition({ lineNumber: 4, column: 2 }); - snippetController.insert(template, 0, 0); + snippetController.insert(template); assert.equal(editor.getModel()!.getLineContent(4), '\tfor (var index; index < array.length; index++) {'); assert.equal(editor.getModel()!.getLineContent(5), '\t\tvar element = array[index];'); assert.equal(editor.getModel()!.getLineContent(6), '\t\t'); @@ -98,7 +98,7 @@ suite('SnippetController', () => { snippetTest((editor, cursor, template, snippetController) => { editor.setPosition({ lineNumber: 4, column: 2 }); - snippetController.insert(template, 0, 0); + snippetController.insert(template); assert.equal(editor.getModel()!.getLineContent(4), '\tfor (var index; index < array.length; index++) {'); assert.equal(editor.getModel()!.getLineContent(5), '\t\tvar element = array[index];'); assert.equal(editor.getModel()!.getLineContent(6), '\t\t'); @@ -180,7 +180,7 @@ suite('SnippetController', () => { test('Stops when calling model.setValue()', () => { snippetTest((editor, cursor, codeSnippet, snippetController) => { editor.setPosition({ lineNumber: 4, column: 2 }); - snippetController.insert(codeSnippet, 0, 0); + snippetController.insert(codeSnippet); editor.getModel()!.setValue('goodbye'); @@ -191,7 +191,7 @@ suite('SnippetController', () => { test('Stops when undoing', () => { snippetTest((editor, cursor, codeSnippet, snippetController) => { editor.setPosition({ lineNumber: 4, column: 2 }); - snippetController.insert(codeSnippet, 0, 0); + snippetController.insert(codeSnippet); editor.getModel()!.undo(); @@ -202,7 +202,7 @@ suite('SnippetController', () => { test('Stops when moving cursor outside', () => { snippetTest((editor, cursor, codeSnippet, snippetController) => { editor.setPosition({ lineNumber: 4, column: 2 }); - snippetController.insert(codeSnippet, 0, 0); + snippetController.insert(codeSnippet); editor.setPosition({ lineNumber: 1, column: 1 }); @@ -213,7 +213,7 @@ suite('SnippetController', () => { test('Stops when disconnecting editor model', () => { snippetTest((editor, cursor, codeSnippet, snippetController) => { editor.setPosition({ lineNumber: 4, column: 2 }); - snippetController.insert(codeSnippet, 0, 0); + snippetController.insert(codeSnippet); editor.setModel(null); @@ -224,7 +224,7 @@ suite('SnippetController', () => { test('Stops when disposing editor', () => { snippetTest((editor, cursor, codeSnippet, snippetController) => { editor.setPosition({ lineNumber: 4, column: 2 }); - snippetController.insert(codeSnippet, 0, 0); + snippetController.insert(codeSnippet); snippetController.dispose(); @@ -240,7 +240,7 @@ suite('SnippetController', () => { ]); codeSnippet = 'foo$0'; - snippetController.insert(codeSnippet, 0, 0); + snippetController.insert(codeSnippet); assert.equal(editor.getSelections()!.length, 2); const [first, second] = editor.getSelections()!; @@ -255,7 +255,7 @@ suite('SnippetController', () => { ]); codeSnippet = 'foo$0bar'; - snippetController.insert(codeSnippet, 0, 0); + snippetController.insert(codeSnippet); assert.equal(editor.getSelections()!.length, 2); const [first, second] = editor.getSelections()!; @@ -270,7 +270,7 @@ suite('SnippetController', () => { ]); codeSnippet = 'foo$0bar'; - snippetController.insert(codeSnippet, 0, 0); + snippetController.insert(codeSnippet); assert.equal(editor.getSelections()!.length, 2); const [first, second] = editor.getSelections()!; @@ -285,7 +285,7 @@ suite('SnippetController', () => { ]); codeSnippet = 'foo\n$0\nbar'; - snippetController.insert(codeSnippet, 0, 0); + snippetController.insert(codeSnippet); assert.equal(editor.getSelections()!.length, 2); const [first, second] = editor.getSelections()!; @@ -300,7 +300,7 @@ suite('SnippetController', () => { ]); codeSnippet = 'foo\n$0\nbar'; - snippetController.insert(codeSnippet, 0, 0); + snippetController.insert(codeSnippet); assert.equal(editor.getSelections()!.length, 2); const [first, second] = editor.getSelections()!; @@ -314,7 +314,7 @@ suite('SnippetController', () => { ]); codeSnippet = 'xo$0r'; - snippetController.insert(codeSnippet, 1, 0); + snippetController.insert(codeSnippet, { overwriteBefore: 1 }); assert.equal(editor.getSelections()!.length, 1); assert.ok(editor.getSelection()!.equalsRange({ startLineNumber: 2, startColumn: 8, endColumn: 8, endLineNumber: 2 })); @@ -327,7 +327,7 @@ suite('SnippetController', () => { editor.setSelection(new Selection(1, 19, 1, 19)); codeSnippet = '{{% url_**$1** %}}'; - controller.insert(codeSnippet, 2, 0); + controller.insert(codeSnippet, { overwriteBefore: 2 }); assert.equal(editor.getSelections()!.length, 1); assert.ok(editor.getSelection()!.equalsRange({ startLineNumber: 1, startColumn: 27, endLineNumber: 1, endColumn: 27 })); @@ -345,7 +345,7 @@ suite('SnippetController', () => { '});' ].join('\n'); - controller.insert(codeSnippet, 2, 0); + controller.insert(codeSnippet, { overwriteBefore: 2 }); assert.equal(editor.getSelections()!.length, 1); assert.ok(editor.getSelection()!.equalsRange({ startLineNumber: 2, startColumn: 2, endLineNumber: 2, endColumn: 2 }), editor.getSelection()!.toString()); @@ -363,7 +363,7 @@ suite('SnippetController', () => { '});' ].join('\n'); - controller.insert(codeSnippet, 2, 0); + controller.insert(codeSnippet, { overwriteBefore: 2 }); assert.equal(editor.getSelections()!.length, 1); assert.ok(editor.getSelection()!.equalsRange({ startLineNumber: 2, startColumn: 1, endLineNumber: 2, endColumn: 1 }), editor.getSelection()!.toString()); @@ -379,7 +379,7 @@ suite('SnippetController', () => { 'aft${1}er' ].join('\n'); - controller.insert(codeSnippet, 8, 0); + controller.insert(codeSnippet, { overwriteBefore: 8 }); assert.equal(editor.getModel()!.getValue(), 'after'); assert.equal(editor.getSelections()!.length, 1); @@ -403,7 +403,7 @@ suite('SnippetController', () => { '});' ].join('\n'); - controller.insert(codeSnippet, 2, 0); + controller.insert(codeSnippet, { overwriteBefore: 2 }); assert.equal(editor.getSelections()!.length, 2); const [first, second] = editor.getSelections()!; @@ -428,7 +428,7 @@ suite('SnippetController', () => { '});' ].join('\n'); - controller.insert(codeSnippet, 2, 0); + controller.insert(codeSnippet, { overwriteBefore: 2 }); assert.equal(editor.getSelections()!.length, 1); const [first] = editor.getSelections()!; @@ -448,7 +448,7 @@ suite('SnippetController', () => { codeSnippet = 'afterEach'; - controller.insert(codeSnippet, 2, 0); + controller.insert(codeSnippet, { overwriteBefore: 2 }); assert.ok(editor.getSelection()!.equalsRange({ startLineNumber: 1, startColumn: 10, endLineNumber: 1, endColumn: 10 })); @@ -465,7 +465,7 @@ suite('SnippetController', () => { ]); codeSnippet = '_foo'; - controller.insert(codeSnippet, 1, 0); + controller.insert(codeSnippet, { overwriteBefore: 1 }); assert.equal(editor.getModel()!.getValue(), 'this._foo\nabc_foo'); }, ['this._', 'abc']); @@ -478,7 +478,7 @@ suite('SnippetController', () => { ]); codeSnippet = 'XX'; - controller.insert(codeSnippet, 1, 0); + controller.insert(codeSnippet, { overwriteBefore: 1 }); assert.equal(editor.getModel()!.getValue(), 'this.XX\nabcXX'); }, ['this._', 'abc']); @@ -492,7 +492,7 @@ suite('SnippetController', () => { ]); codeSnippet = '_foo'; - controller.insert(codeSnippet, 1, 0); + controller.insert(codeSnippet, { overwriteBefore: 1 }); assert.equal(editor.getModel()!.getValue(), 'this._foo\nabc_foo\ndef_foo'); }, ['this._', 'abc', 'def_']); @@ -506,7 +506,7 @@ suite('SnippetController', () => { ]); codeSnippet = '._foo'; - controller.insert(codeSnippet, 2, 0); + controller.insert(codeSnippet, { overwriteBefore: 2 }); assert.equal(editor.getModel()!.getValue(), 'this._foo\nabc._foo\ndef._foo'); }, ['this._', 'abc', 'def._']); @@ -520,7 +520,7 @@ suite('SnippetController', () => { ]); codeSnippet = '._foo'; - controller.insert(codeSnippet, 2, 0); + controller.insert(codeSnippet, { overwriteBefore: 2 }); assert.equal(editor.getModel()!.getValue(), 'this._foo\nabc._foo\ndef._foo'); }, ['this._', 'abc', 'def._']); @@ -534,7 +534,7 @@ suite('SnippetController', () => { ]); codeSnippet = '._foo'; - controller.insert(codeSnippet, 2, 0); + controller.insert(codeSnippet, { overwriteBefore: 2 }); assert.equal(editor.getModel()!.getValue(), 'this._._foo\na._foo\ndef._._foo'); }, ['this._', 'abc', 'def._']); @@ -550,7 +550,7 @@ suite('SnippetController', () => { ]); codeSnippet = 'document'; - controller.insert(codeSnippet, 3, 0); + controller.insert(codeSnippet, { overwriteBefore: 3 }); assert.equal(editor.getModel()!.getValue(), '{document}\n{document && true}'); }, ['{foo}', '{foo && true}']); @@ -565,7 +565,7 @@ suite('SnippetController', () => { ]); codeSnippet = 'for (var ${1:i}=0; ${1:i} { ]); codeSnippet = 'for (let ${1:i}=0; ${1:i} { editor.setSelection(new Selection(2, 5, 2, 5)); - const session = new SnippetSession(editor, 'abc\n foo\n bar\n$0', 0, 0, false); + const session = new SnippetSession(editor, 'abc\n foo\n bar\n$0', { overwriteBefore: 0, overwriteAfter: 0, adjustWhitespace: false, clipboardText: undefined }); session.insert(); assert.equal(editor.getModel()!.getValue(), 'function foo() {\n abc\n foo\n bar\nconsole.log(a);\n}'); }); @@ -648,7 +648,7 @@ suite('SnippetSession', function () { assert.ok(actual.equalsSelection(new Selection(1, 9, 1, 12))); editor.setSelections([new Selection(1, 9, 1, 12)]); - new SnippetSession(editor, 'far', 3, 0).insert(); + new SnippetSession(editor, 'far', { overwriteBefore: 3, overwriteAfter: 0, adjustWhitespace: true, clipboardText: undefined }).insert(); assert.equal(model.getValue(), 'console.far'); }); }); diff --git a/src/vs/editor/contrib/snippet/test/snippetVariables.test.ts b/src/vs/editor/contrib/snippet/test/snippetVariables.test.ts index 0b44a9c6a..7a5367085 100644 --- a/src/vs/editor/contrib/snippet/test/snippetVariables.test.ts +++ b/src/vs/editor/contrib/snippet/test/snippetVariables.test.ts @@ -9,11 +9,18 @@ import { Selection } from 'vs/editor/common/core/selection'; import { SelectionBasedVariableResolver, CompositeSnippetVariableResolver, ModelBasedVariableResolver, ClipboardBasedVariableResolver, TimeBasedVariableResolver, WorkspaceBasedVariableResolver } from 'vs/editor/contrib/snippet/snippetVariables'; import { SnippetParser, Variable, VariableResolver } from 'vs/editor/contrib/snippet/snippetParser'; import { TextModel } from 'vs/editor/common/model/textModel'; -import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { Workspace, toWorkspaceFolders, IWorkspace, IWorkspaceContextService, toWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; +import { ILabelService } from 'vs/platform/label/common/label'; +import { mock } from 'vs/editor/contrib/suggest/test/suggestModel.test'; suite('Snippet Variables Resolver', function () { + const labelService = new class extends mock() { + getUriLabel(uri: URI) { + return uri.fsPath; + } + }; + let model: TextModel; let resolver: VariableResolver; @@ -25,7 +32,7 @@ suite('Snippet Variables Resolver', function () { ].join('\n'), undefined, undefined, URI.parse('file:///foo/files/text.txt')); resolver = new CompositeSnippetVariableResolver([ - new ModelBasedVariableResolver(model), + new ModelBasedVariableResolver(labelService, model), new SelectionBasedVariableResolver(model, new Selection(1, 1, 1, 1)), ]); }); @@ -59,6 +66,7 @@ suite('Snippet Variables Resolver', function () { } resolver = new ModelBasedVariableResolver( + labelService, TextModel.createFromString('', undefined, undefined, URI.parse('http://www.pb.o/abc/def/ghi')) ); assertVariableResolve(resolver, 'TM_FILENAME', 'ghi'); @@ -68,6 +76,7 @@ suite('Snippet Variables Resolver', function () { } resolver = new ModelBasedVariableResolver( + labelService, TextModel.createFromString('', undefined, undefined, URI.parse('mem:fff.ts')) ); assertVariableResolve(resolver, 'TM_DIRECTORY', ''); @@ -75,6 +84,21 @@ suite('Snippet Variables Resolver', function () { }); + test('Path delimiters in code snippet variables aren\'t specific to remote OS #76840', function () { + + const labelService = new class extends mock() { + getUriLabel(uri: URI) { + return uri.fsPath.replace(/\/|\\/g, '|'); + } + }; + + const model = TextModel.createFromString([].join('\n'), undefined, undefined, URI.parse('foo:///foo/files/text.txt')); + + const resolver = new CompositeSnippetVariableResolver([new ModelBasedVariableResolver(labelService, model)]); + + assertVariableResolve(resolver, 'TM_FILEPATH', '|foo|files|text.txt'); + }); + test('editor variables, selection', function () { resolver = new SelectionBasedVariableResolver(model, new Selection(1, 2, 2, 3)); @@ -119,16 +143,19 @@ suite('Snippet Variables Resolver', function () { assertVariableResolve(resolver, 'TM_FILENAME_BASE', 'text'); resolver = new ModelBasedVariableResolver( + labelService, TextModel.createFromString('', undefined, undefined, URI.parse('http://www.pb.o/abc/def/ghi')) ); assertVariableResolve(resolver, 'TM_FILENAME_BASE', 'ghi'); resolver = new ModelBasedVariableResolver( + labelService, TextModel.createFromString('', undefined, undefined, URI.parse('mem:.git')) ); assertVariableResolve(resolver, 'TM_FILENAME_BASE', '.git'); resolver = new ModelBasedVariableResolver( + labelService, TextModel.createFromString('', undefined, undefined, URI.parse('mem:foo.')) ); assertVariableResolve(resolver, 'TM_FILENAME_BASE', 'foo'); @@ -209,63 +236,26 @@ suite('Snippet Variables Resolver', function () { test('Add variable to insert value from clipboard to a snippet #40153', function () { - let readTextResult: string | null | undefined; - const clipboardService = new class implements IClipboardService { - _serviceBrand: any; - readText(): any { return readTextResult; } - _throw = () => { throw new Error(); }; - writeText = this._throw; - readFindText = this._throw; - writeFindText = this._throw; - writeResources = this._throw; - readResources = this._throw; - hasResources = this._throw; - }; - let resolver = new ClipboardBasedVariableResolver(clipboardService, 1, 0); - - readTextResult = undefined; - assertVariableResolve(resolver, 'CLIPBOARD', undefined); + assertVariableResolve(new ClipboardBasedVariableResolver(undefined, 1, 0), 'CLIPBOARD', undefined); - readTextResult = null; - assertVariableResolve(resolver, 'CLIPBOARD', undefined); + assertVariableResolve(new ClipboardBasedVariableResolver(null!, 1, 0), 'CLIPBOARD', undefined); - readTextResult = ''; - assertVariableResolve(resolver, 'CLIPBOARD', undefined); + assertVariableResolve(new ClipboardBasedVariableResolver('', 1, 0), 'CLIPBOARD', undefined); - readTextResult = 'foo'; - assertVariableResolve(resolver, 'CLIPBOARD', 'foo'); + assertVariableResolve(new ClipboardBasedVariableResolver('foo', 1, 0), 'CLIPBOARD', 'foo'); - assertVariableResolve(resolver, 'foo', undefined); - assertVariableResolve(resolver, 'cLIPBOARD', undefined); + assertVariableResolve(new ClipboardBasedVariableResolver('foo', 1, 0), 'foo', undefined); + assertVariableResolve(new ClipboardBasedVariableResolver('foo', 1, 0), 'cLIPBOARD', undefined); }); test('Add variable to insert value from clipboard to a snippet #40153', function () { - let readTextResult: string; - let resolver: VariableResolver; - const clipboardService = new class implements IClipboardService { - _serviceBrand: any; - readText(): string { return readTextResult; } - _throw = () => { throw new Error(); }; - writeText = this._throw; - readFindText = this._throw; - writeFindText = this._throw; - writeResources = this._throw; - readResources = this._throw; - hasResources = this._throw; - }; + assertVariableResolve(new ClipboardBasedVariableResolver('line1', 1, 2), 'CLIPBOARD', 'line1'); + assertVariableResolve(new ClipboardBasedVariableResolver('line1\nline2\nline3', 1, 2), 'CLIPBOARD', 'line1\nline2\nline3'); - resolver = new ClipboardBasedVariableResolver(clipboardService, 1, 2); - readTextResult = 'line1'; - assertVariableResolve(resolver, 'CLIPBOARD', 'line1'); - readTextResult = 'line1\nline2\nline3'; - assertVariableResolve(resolver, 'CLIPBOARD', 'line1\nline2\nline3'); - - readTextResult = 'line1\nline2'; - assertVariableResolve(resolver, 'CLIPBOARD', 'line2'); - readTextResult = 'line1\nline2'; - resolver = new ClipboardBasedVariableResolver(clipboardService, 0, 2); - assertVariableResolve(resolver, 'CLIPBOARD', 'line1'); + assertVariableResolve(new ClipboardBasedVariableResolver('line1\nline2', 1, 2), 'CLIPBOARD', 'line2'); + resolver = new ClipboardBasedVariableResolver('line1\nline2', 0, 2); + assertVariableResolve(new ClipboardBasedVariableResolver('line1\nline2', 0, 2), 'CLIPBOARD', 'line1'); }); @@ -336,4 +326,4 @@ suite('Snippet Variables Resolver', function () { workspace = new Workspace('', toWorkspaceFolders([{ path: 'folderName' }], workspaceConfigPath), workspaceConfigPath); assertVariableResolve(resolver, 'WORKSPACE_NAME', 'testWorkspace'); }); -}); \ No newline at end of file +}); diff --git a/src/vs/editor/contrib/suggest/completionModel.ts b/src/vs/editor/contrib/suggest/completionModel.ts index 9d23376cf..29673ee64 100644 --- a/src/vs/editor/contrib/suggest/completionModel.ts +++ b/src/vs/editor/contrib/suggest/completionModel.ts @@ -3,13 +3,13 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { fuzzyScore, fuzzyScoreGracefulAggressive, anyScore, FuzzyScorer, FuzzyScore } from 'vs/base/common/filters'; -import { isDisposable } from 'vs/base/common/lifecycle'; -import { CompletionList, CompletionItemProvider, CompletionItemKind } from 'vs/editor/common/modes'; +import { fuzzyScore, fuzzyScoreGracefulAggressive, FuzzyScorer, FuzzyScore, anyScore } from 'vs/base/common/filters'; +import { CompletionItemProvider, CompletionItemKind } from 'vs/editor/common/modes'; import { CompletionItem } from './suggest'; import { InternalSuggestOptions, EDITOR_DEFAULTS } from 'vs/editor/common/config/editorOptions'; import { WordDistance } from 'vs/editor/contrib/suggest/wordDistance'; import { CharCode } from 'vs/base/common/charCode'; +import { compareIgnoreCase } from 'vs/base/common/strings'; type StrictCompletionItem = Required; @@ -74,18 +74,6 @@ 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; } @@ -215,8 +203,15 @@ export class CompletionModel { if (!match) { continue; // NO match } - item.score = anyScore(word, wordLow, 0, item.completion.label, item.labelLow, 0); - item.score[0] = match[0]; // use score from filterText + if (compareIgnoreCase(item.completion.filterText, item.completion.label) === 0) { + // filterText and label are actually the same -> use good highlights + item.score = match; + } else { + // re-run the scorer on the label in the hope of a result BUT use the rank + // of the filterText-match + item.score = anyScore(word, wordLow, wordPos, item.completion.label, item.labelLow, 0); + item.score[0] = match[0]; // use score from filterText + } } else { // by default match `word` against the `label` diff --git a/src/vs/editor/contrib/suggest/media/Class_16x.svg b/src/vs/editor/contrib/suggest/media/Class_16x.svg deleted file mode 100755 index 5ef1c6f80..000000000 --- a/src/vs/editor/contrib/suggest/media/Class_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/Class_inverse_16x.svg b/src/vs/editor/contrib/suggest/media/Class_inverse_16x.svg deleted file mode 100755 index c43aad29e..000000000 --- a/src/vs/editor/contrib/suggest/media/Class_inverse_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/ColorPalette_16x.svg b/src/vs/editor/contrib/suggest/media/ColorPalette_16x.svg deleted file mode 100755 index 2af5cc6fa..000000000 --- a/src/vs/editor/contrib/suggest/media/ColorPalette_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/ColorPalette_inverse_16x.svg b/src/vs/editor/contrib/suggest/media/ColorPalette_inverse_16x.svg deleted file mode 100755 index 7afb32b89..000000000 --- a/src/vs/editor/contrib/suggest/media/ColorPalette_inverse_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/Constant_16x.svg b/src/vs/editor/contrib/suggest/media/Constant_16x.svg deleted file mode 100644 index ed2a17510..000000000 --- a/src/vs/editor/contrib/suggest/media/Constant_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/Constant_16x_inverse.svg b/src/vs/editor/contrib/suggest/media/Constant_16x_inverse.svg deleted file mode 100644 index 173e427f9..000000000 --- a/src/vs/editor/contrib/suggest/media/Constant_16x_inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/Document_16x.svg b/src/vs/editor/contrib/suggest/media/Document_16x.svg deleted file mode 100755 index 13ded2953..000000000 --- a/src/vs/editor/contrib/suggest/media/Document_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/Document_inverse_16x.svg b/src/vs/editor/contrib/suggest/media/Document_inverse_16x.svg deleted file mode 100755 index 949a37621..000000000 --- a/src/vs/editor/contrib/suggest/media/Document_inverse_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/EnumItem_16x.svg b/src/vs/editor/contrib/suggest/media/EnumItem_16x.svg deleted file mode 100755 index aa901ec19..000000000 --- a/src/vs/editor/contrib/suggest/media/EnumItem_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/EnumItem_inverse_16x.svg b/src/vs/editor/contrib/suggest/media/EnumItem_inverse_16x.svg deleted file mode 100755 index 791759092..000000000 --- a/src/vs/editor/contrib/suggest/media/EnumItem_inverse_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/Enumerator_16x.svg b/src/vs/editor/contrib/suggest/media/Enumerator_16x.svg deleted file mode 100755 index e4a9551fd..000000000 --- a/src/vs/editor/contrib/suggest/media/Enumerator_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/Enumerator_inverse_16x.svg b/src/vs/editor/contrib/suggest/media/Enumerator_inverse_16x.svg deleted file mode 100755 index d8e9f4f10..000000000 --- a/src/vs/editor/contrib/suggest/media/Enumerator_inverse_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/Event_16x_vscode.svg b/src/vs/editor/contrib/suggest/media/Event_16x_vscode.svg deleted file mode 100644 index 0e202ec10..000000000 --- a/src/vs/editor/contrib/suggest/media/Event_16x_vscode.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/Event_16x_vscode_inverse.svg b/src/vs/editor/contrib/suggest/media/Event_16x_vscode_inverse.svg deleted file mode 100644 index a508edcd3..000000000 --- a/src/vs/editor/contrib/suggest/media/Event_16x_vscode_inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/Field_16x.svg b/src/vs/editor/contrib/suggest/media/Field_16x.svg deleted file mode 100755 index c6cb5362b..000000000 --- a/src/vs/editor/contrib/suggest/media/Field_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/Field_inverse_16x.svg b/src/vs/editor/contrib/suggest/media/Field_inverse_16x.svg deleted file mode 100755 index 5fc48ceff..000000000 --- a/src/vs/editor/contrib/suggest/media/Field_inverse_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/Folder_16x.svg b/src/vs/editor/contrib/suggest/media/Folder_16x.svg deleted file mode 100644 index 3d64ae71d..000000000 --- a/src/vs/editor/contrib/suggest/media/Folder_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/Folder_inverse_16x.svg b/src/vs/editor/contrib/suggest/media/Folder_inverse_16x.svg deleted file mode 100755 index 13b18d180..000000000 --- a/src/vs/editor/contrib/suggest/media/Folder_inverse_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/ImportFile_16x_vscode.svg b/src/vs/editor/contrib/suggest/media/ImportFile_16x_vscode.svg deleted file mode 100644 index 5511fc9e2..000000000 --- a/src/vs/editor/contrib/suggest/media/ImportFile_16x_vscode.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/ImportFile_16x_vscode_inverse.svg b/src/vs/editor/contrib/suggest/media/ImportFile_16x_vscode_inverse.svg deleted file mode 100644 index 604d994cb..000000000 --- a/src/vs/editor/contrib/suggest/media/ImportFile_16x_vscode_inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/IntelliSenseKeyword_16x.svg b/src/vs/editor/contrib/suggest/media/IntelliSenseKeyword_16x.svg deleted file mode 100755 index 4a69c4a03..000000000 --- a/src/vs/editor/contrib/suggest/media/IntelliSenseKeyword_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/IntelliSenseKeyword_inverse_16x.svg b/src/vs/editor/contrib/suggest/media/IntelliSenseKeyword_inverse_16x.svg deleted file mode 100755 index decbf2c40..000000000 --- a/src/vs/editor/contrib/suggest/media/IntelliSenseKeyword_inverse_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/Interface_16x.svg b/src/vs/editor/contrib/suggest/media/Interface_16x.svg deleted file mode 100755 index 958a79274..000000000 --- a/src/vs/editor/contrib/suggest/media/Interface_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/Interface_inverse_16x.svg b/src/vs/editor/contrib/suggest/media/Interface_inverse_16x.svg deleted file mode 100755 index f7c2934a5..000000000 --- a/src/vs/editor/contrib/suggest/media/Interface_inverse_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/LocalVariable_16x_vscode.svg b/src/vs/editor/contrib/suggest/media/LocalVariable_16x_vscode.svg deleted file mode 100644 index e78894b6c..000000000 --- a/src/vs/editor/contrib/suggest/media/LocalVariable_16x_vscode.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/LocalVariable_16x_vscode_inverse.svg b/src/vs/editor/contrib/suggest/media/LocalVariable_16x_vscode_inverse.svg deleted file mode 100644 index 44a44b489..000000000 --- a/src/vs/editor/contrib/suggest/media/LocalVariable_16x_vscode_inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/Method_16x.svg b/src/vs/editor/contrib/suggest/media/Method_16x.svg deleted file mode 100755 index 2be9daa5f..000000000 --- a/src/vs/editor/contrib/suggest/media/Method_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/Method_inverse_16x.svg b/src/vs/editor/contrib/suggest/media/Method_inverse_16x.svg deleted file mode 100755 index d3c2c571d..000000000 --- a/src/vs/editor/contrib/suggest/media/Method_inverse_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/Misc_16x.svg b/src/vs/editor/contrib/suggest/media/Misc_16x.svg deleted file mode 100755 index 13ff00b23..000000000 --- a/src/vs/editor/contrib/suggest/media/Misc_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/Misc_inverse_16x.svg b/src/vs/editor/contrib/suggest/media/Misc_inverse_16x.svg deleted file mode 100755 index 50a038657..000000000 --- a/src/vs/editor/contrib/suggest/media/Misc_inverse_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/Namespace_16x.svg b/src/vs/editor/contrib/suggest/media/Namespace_16x.svg deleted file mode 100755 index dab07dd5a..000000000 --- a/src/vs/editor/contrib/suggest/media/Namespace_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/Namespace_inverse_16x.svg b/src/vs/editor/contrib/suggest/media/Namespace_inverse_16x.svg deleted file mode 100755 index 9b9a44c52..000000000 --- a/src/vs/editor/contrib/suggest/media/Namespace_inverse_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/Operator_16x_vscode.svg b/src/vs/editor/contrib/suggest/media/Operator_16x_vscode.svg deleted file mode 100644 index ba2f2d091..000000000 --- a/src/vs/editor/contrib/suggest/media/Operator_16x_vscode.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/Operator_16x_vscode_inverse.svg b/src/vs/editor/contrib/suggest/media/Operator_16x_vscode_inverse.svg deleted file mode 100644 index 21e1e814b..000000000 --- a/src/vs/editor/contrib/suggest/media/Operator_16x_vscode_inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/Property_16x.svg b/src/vs/editor/contrib/suggest/media/Property_16x.svg deleted file mode 100755 index fb1c74cf7..000000000 --- a/src/vs/editor/contrib/suggest/media/Property_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/Property_inverse_16x.svg b/src/vs/editor/contrib/suggest/media/Property_inverse_16x.svg deleted file mode 100755 index f90781897..000000000 --- a/src/vs/editor/contrib/suggest/media/Property_inverse_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/Ruler_16x.svg b/src/vs/editor/contrib/suggest/media/Ruler_16x.svg deleted file mode 100755 index 2e8e88fef..000000000 --- a/src/vs/editor/contrib/suggest/media/Ruler_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/Ruler_inverse_16x.svg b/src/vs/editor/contrib/suggest/media/Ruler_inverse_16x.svg deleted file mode 100755 index 373ab812f..000000000 --- a/src/vs/editor/contrib/suggest/media/Ruler_inverse_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/Snippet_16x.svg b/src/vs/editor/contrib/suggest/media/Snippet_16x.svg deleted file mode 100644 index 8bf3b9f67..000000000 --- a/src/vs/editor/contrib/suggest/media/Snippet_16x.svg +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - - diff --git a/src/vs/editor/contrib/suggest/media/Snippet_inverse_16x.svg b/src/vs/editor/contrib/suggest/media/Snippet_inverse_16x.svg deleted file mode 100644 index 501ff9c61..000000000 --- a/src/vs/editor/contrib/suggest/media/Snippet_inverse_16x.svg +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - diff --git a/src/vs/editor/contrib/suggest/media/String_16x.svg b/src/vs/editor/contrib/suggest/media/String_16x.svg deleted file mode 100755 index 35e744ce9..000000000 --- a/src/vs/editor/contrib/suggest/media/String_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/String_inverse_16x.svg b/src/vs/editor/contrib/suggest/media/String_inverse_16x.svg deleted file mode 100755 index 1ac0cf99a..000000000 --- a/src/vs/editor/contrib/suggest/media/String_inverse_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/Structure_16x_vscode.svg b/src/vs/editor/contrib/suggest/media/Structure_16x_vscode.svg deleted file mode 100644 index e776cbc56..000000000 --- a/src/vs/editor/contrib/suggest/media/Structure_16x_vscode.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/Structure_16x_vscode_inverse.svg b/src/vs/editor/contrib/suggest/media/Structure_16x_vscode_inverse.svg deleted file mode 100644 index 1b76b62be..000000000 --- a/src/vs/editor/contrib/suggest/media/Structure_16x_vscode_inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/Template_16x_vscode.svg b/src/vs/editor/contrib/suggest/media/Template_16x_vscode.svg deleted file mode 100644 index 788cc8d64..000000000 --- a/src/vs/editor/contrib/suggest/media/Template_16x_vscode.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/Template_16x_vscode_inverse.svg b/src/vs/editor/contrib/suggest/media/Template_16x_vscode_inverse.svg deleted file mode 100644 index 6cec71cb0..000000000 --- a/src/vs/editor/contrib/suggest/media/Template_16x_vscode_inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/class-dark.svg b/src/vs/editor/contrib/suggest/media/class-dark.svg new file mode 100644 index 000000000..a71e221f6 --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/class-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/class-light.svg b/src/vs/editor/contrib/suggest/media/class-light.svg new file mode 100644 index 000000000..aa106f18f --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/class-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/close-dark.svg b/src/vs/editor/contrib/suggest/media/close-dark.svg index 751e89b3b..556e2e209 100644 --- a/src/vs/editor/contrib/suggest/media/close-dark.svg +++ b/src/vs/editor/contrib/suggest/media/close-dark.svg @@ -1 +1,3 @@ - \ No newline at end of file + + + diff --git a/src/vs/editor/contrib/suggest/media/close-light.svg b/src/vs/editor/contrib/suggest/media/close-light.svg new file mode 100644 index 000000000..c84816a03 --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/close-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/close.svg b/src/vs/editor/contrib/suggest/media/close.svg deleted file mode 100644 index fde34404d..000000000 --- a/src/vs/editor/contrib/suggest/media/close.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/contrib/suggest/media/color-dark.svg b/src/vs/editor/contrib/suggest/media/color-dark.svg new file mode 100644 index 000000000..0914abcdb --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/color-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/color-light.svg b/src/vs/editor/contrib/suggest/media/color-light.svg new file mode 100644 index 000000000..ca089a1bf --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/color-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/constant-dark.svg b/src/vs/editor/contrib/suggest/media/constant-dark.svg new file mode 100644 index 000000000..0e90ecafc --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/constant-dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/vs/editor/contrib/suggest/media/constant-light.svg b/src/vs/editor/contrib/suggest/media/constant-light.svg new file mode 100644 index 000000000..1a369c1d8 --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/constant-light.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/vs/editor/contrib/suggest/media/enumerator-dark.svg b/src/vs/editor/contrib/suggest/media/enumerator-dark.svg new file mode 100644 index 000000000..82d4ff29c --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/enumerator-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/enumerator-item-dark.svg b/src/vs/editor/contrib/suggest/media/enumerator-item-dark.svg new file mode 100644 index 000000000..23c697fdf --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/enumerator-item-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/enumerator-item-light.svg b/src/vs/editor/contrib/suggest/media/enumerator-item-light.svg new file mode 100644 index 000000000..a99045d33 --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/enumerator-item-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/enumerator-light.svg b/src/vs/editor/contrib/suggest/media/enumerator-light.svg new file mode 100644 index 000000000..e2441a0dc --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/enumerator-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/event-dark.svg b/src/vs/editor/contrib/suggest/media/event-dark.svg new file mode 100644 index 000000000..712344d1f --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/event-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/event-light.svg b/src/vs/editor/contrib/suggest/media/event-light.svg new file mode 100644 index 000000000..712344d1f --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/event-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/field-dark.svg b/src/vs/editor/contrib/suggest/media/field-dark.svg new file mode 100644 index 000000000..15623061c --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/field-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/field-light.svg b/src/vs/editor/contrib/suggest/media/field-light.svg new file mode 100644 index 000000000..72dd79504 --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/field-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/file-dark.svg b/src/vs/editor/contrib/suggest/media/file-dark.svg new file mode 100644 index 000000000..5ed5762a1 --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/file-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/file-light.svg b/src/vs/editor/contrib/suggest/media/file-light.svg new file mode 100644 index 000000000..ad54e13b1 --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/file-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/folder-dark.svg b/src/vs/editor/contrib/suggest/media/folder-dark.svg new file mode 100644 index 000000000..43d454e7e --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/folder-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/folder-light.svg b/src/vs/editor/contrib/suggest/media/folder-light.svg new file mode 100644 index 000000000..8daecdac6 --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/folder-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/info-dark.svg b/src/vs/editor/contrib/suggest/media/info-dark.svg new file mode 100644 index 000000000..3f2d84fa6 --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/info-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/info-light.svg b/src/vs/editor/contrib/suggest/media/info-light.svg new file mode 100644 index 000000000..f25ac7c78 --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/info-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/interface-dark.svg b/src/vs/editor/contrib/suggest/media/interface-dark.svg new file mode 100644 index 000000000..6d482b2ab --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/interface-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/interface-light.svg b/src/vs/editor/contrib/suggest/media/interface-light.svg new file mode 100644 index 000000000..a397dd00b --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/interface-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/keyword-dark.svg b/src/vs/editor/contrib/suggest/media/keyword-dark.svg new file mode 100644 index 000000000..70ba6ea93 --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/keyword-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/keyword-light.svg b/src/vs/editor/contrib/suggest/media/keyword-light.svg new file mode 100644 index 000000000..fc57528a3 --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/keyword-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/method-dark.svg b/src/vs/editor/contrib/suggest/media/method-dark.svg new file mode 100644 index 000000000..970d7b614 --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/method-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/method-light.svg b/src/vs/editor/contrib/suggest/media/method-light.svg new file mode 100644 index 000000000..403a9b90d --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/method-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/namespace-dark.svg b/src/vs/editor/contrib/suggest/media/namespace-dark.svg new file mode 100644 index 000000000..9a725bb41 --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/namespace-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/namespace-light.svg b/src/vs/editor/contrib/suggest/media/namespace-light.svg new file mode 100644 index 000000000..1339da7ce --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/namespace-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/operator-dark.svg b/src/vs/editor/contrib/suggest/media/operator-dark.svg new file mode 100644 index 000000000..957f5f44f --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/operator-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/operator-light.svg b/src/vs/editor/contrib/suggest/media/operator-light.svg new file mode 100644 index 000000000..bf6ed5799 --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/operator-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/property-dark.svg b/src/vs/editor/contrib/suggest/media/property-dark.svg new file mode 100644 index 000000000..23e07ffa1 --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/property-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/property-light.svg b/src/vs/editor/contrib/suggest/media/property-light.svg new file mode 100644 index 000000000..be642dd15 --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/property-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/reference-dark.svg b/src/vs/editor/contrib/suggest/media/reference-dark.svg new file mode 100644 index 000000000..ed302ae13 --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/reference-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/reference-light.svg b/src/vs/editor/contrib/suggest/media/reference-light.svg new file mode 100644 index 000000000..392a840c5 --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/reference-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/ruler-dark.svg b/src/vs/editor/contrib/suggest/media/ruler-dark.svg new file mode 100644 index 000000000..1957dbad3 --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/ruler-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/ruler-light.svg b/src/vs/editor/contrib/suggest/media/ruler-light.svg new file mode 100644 index 000000000..bc321cdff --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/ruler-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/snippet-dark.svg b/src/vs/editor/contrib/suggest/media/snippet-dark.svg new file mode 100644 index 000000000..79799f98c --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/snippet-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/snippet-light.svg b/src/vs/editor/contrib/suggest/media/snippet-light.svg new file mode 100644 index 000000000..45fa3a001 --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/snippet-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/string-dark.svg b/src/vs/editor/contrib/suggest/media/string-dark.svg new file mode 100644 index 000000000..80fb9d656 --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/string-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/string-light.svg b/src/vs/editor/contrib/suggest/media/string-light.svg new file mode 100644 index 000000000..02a0282e9 --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/string-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/structure-dark.svg b/src/vs/editor/contrib/suggest/media/structure-dark.svg new file mode 100644 index 000000000..13766a5dc --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/structure-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/structure-light.svg b/src/vs/editor/contrib/suggest/media/structure-light.svg new file mode 100644 index 000000000..c96bcfa61 --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/structure-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/suggest.css b/src/vs/editor/contrib/suggest/media/suggest.css index b5b3eb956..09594abb4 100644 --- a/src/vs/editor/contrib/suggest/media/suggest.css +++ b/src/vs/editor/contrib/suggest/media/suggest.css @@ -109,13 +109,13 @@ } .monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .header > .close { - background-image: url('./close.svg'); + background-image: url('./close-light.svg'); float: right; margin-right: 5px; } .monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .readMore { - background-image: url('./info.svg'); + background-image: url('./info-light.svg'); } .monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .header > .close:hover, @@ -179,7 +179,6 @@ .monaco-editor .suggest-widget .monaco-list .monaco-list-row .monaco-icon-label.suggest-icon::before { content: ' '; - background-image: url('Misc_16x.svg'); background-repeat: no-repeat; background-position: center; background-size: 75%; @@ -187,30 +186,30 @@ .monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.method::before, .monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.function::before, -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.constructor::before { background-image: url('Method_16x.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.field::before { background-image: url('Field_16x.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.event::before { background-image: url('Event_16x_vscode.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.operator::before { background-image: url('Operator_16x_vscode.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.variable::before { background-image: url('LocalVariable_16x_vscode.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.class::before { background-image: url('Class_16x.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.interface::before { background-image: url('Interface_16x.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.struct::before { background-image: url('Structure_16x_vscode.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.type-parameter::before { background-image: url('Template_16x_vscode.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.module::before { background-image: url('Namespace_16x.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.property::before { background-image: url('Property_16x.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.unit::before { background-image: url('Ruler_16x.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.constant::before { background-image: url('Constant_16x.svg'); } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.constructor::before { background-image: url('method-light.svg'); } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.field::before { background-image: url('field-light.svg'); } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.event::before { background-image: url('event-light.svg'); } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.operator::before { background-image: url('operator-light.svg'); } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.variable::before { background-image: url('variable-light.svg'); } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.class::before { background-image: url('class-light.svg'); } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.interface::before { background-image: url('interface-light.svg'); } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.struct::before { background-image: url('structure-light.svg'); } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.type-parameter::before { background-image: url('template-light.svg'); } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.module::before { background-image: url('namespace-light.svg'); } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.property::before { background-image: url('property-light.svg'); } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.unit::before { background-image: url('ruler-light.svg'); } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.constant::before { background-image: url('constant-light.svg'); } .monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.value::before, -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.enum::before { background-image: url('Enumerator_16x.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.enum-member::before { background-image: url('EnumItem_16x.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.keyword::before { background-image: url('IntelliSenseKeyword_16x.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.text::before { background-image: url('String_16x.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.color::before { background-image: url('ColorPalette_16x.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.file::before { background-image: url('Document_16x.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.reference::before { background-image: url('ImportFile_16x_vscode.svg'); } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.snippet::before { background-image: url('Snippet_16x.svg'); } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.enum::before { background-image: url('enumerator-light.svg'); } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.enum-member::before { background-image: url('enumerator-item-light.svg'); } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.keyword::before { background-image: url('keyword-light.svg'); } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.text::before { background-image: url('string-light.svg'); } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.color::before { background-image: url('color-light.svg'); } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.file::before { background-image: url('file-light.svg'); } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.reference::before { background-image: url('reference-light.svg'); } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.snippet::before { background-image: url('snippet-light.svg'); } .monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.customcolor::before { background-image: none; } -.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.folder::before { background-image: url('Folder_16x.svg'); } +.monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.folder::before { background-image: url('folder-light.svg'); } .monaco-editor .suggest-widget .monaco-list .monaco-list-row .icon.customcolor .colorspan { margin: 0 0 0 0.3em; @@ -301,80 +300,82 @@ background-image: url('./close-dark.svg'); } -.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon::before { background-image: url('Misc_inverse_16x.svg'); } +.monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .readMore, +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .readMore { + background-image: url('./info-dark.svg'); +} .monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.method::before, .monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.method::before, .monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.function::before, .monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.function::before, .monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.constructor::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.constructor::before { background-image: url('Method_inverse_16x.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.constructor::before { background-image: url('method-dark.svg'); } .monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.field::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.field::before { background-image: url('Field_inverse_16x.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.field::before { background-image: url('field-dark.svg'); } .monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.event::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.event::before { background-image: url('Event_16x_vscode_inverse.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.event::before { background-image: url('event-dark.svg'); } .monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.operator::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.operator::before { background-image: url('Operator_16x_vscode_inverse.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.operator::before { background-image: url('operator-dark.svg'); } .monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.variable::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.variable::before { background-image: url('LocalVariable_16x_vscode_inverse.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.variable::before { background-image: url('variable-dark.svg'); } .monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.class::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.class::before { background-image: url('Class_inverse_16x.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.class::before { background-image: url('class-dark.svg'); } .monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.interface::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.interface::before { background-image: url('Interface_inverse_16x.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.interface::before { background-image: url('interface-dark.svg'); } .monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.struct::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.struct::before { background-image: url('Structure_16x_vscode_inverse.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.struct::before { background-image: url('structure-dark.svg'); } .monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.type-parameter::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.type-parameter::before { background-image: url('Template_16x_vscode_inverse.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.type-parameter::before { background-image: url('template-dark.svg'); } .monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.module::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.module::before { background-image: url('Namespace_inverse_16x.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.module::before { background-image: url('namespace-dark.svg'); } .monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.property::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.property::before { background-image: url('Property_inverse_16x.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.property::before { background-image: url('property-dark.svg'); } .monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.unit::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.unit::before { background-image: url('Ruler_inverse_16x.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.unit::before { background-image: url('ruler-dark.svg'); } .monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.constant::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.constant::before { background-image: url('Constant_16x_inverse.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.constant::before { background-image: url('constant-dark.svg'); } .monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.value::before, .monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.value::before, .monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.enum::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.enum::before { background-image: url('Enumerator_inverse_16x.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.enum::before { background-image: url('enumerator-dark.svg'); } .monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.enum-member::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.enum-member::before { background-image: url('EnumItem_inverse_16x.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.enum-member::before { background-image: url('enumerator-item-dark.svg'); } .monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.keyword::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.keyword::before { background-image: url('IntelliSenseKeyword_inverse_16x.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.keyword::before { background-image: url('keyword-dark.svg'); } .monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.text::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.text::before { background-image: url('String_inverse_16x.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.text::before { background-image: url('string-dark.svg'); } .monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.color::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.color::before { background-image: url('ColorPalette_inverse_16x.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.color::before { background-image: url('color-dark.svg'); } .monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.file::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.file::before { background-image: url('Document_inverse_16x.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.file::before { background-image: url('file-dark.svg'); } .monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.reference::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.reference::before { background-image: url('ImportFile_16x_vscode_inverse.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.reference::before { background-image: url('reference-dark.svg'); } .monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.snippet::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.snippet::before { background-image: url('Snippet_inverse_16x.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.snippet::before { background-image: url('snippet-dark.svg'); } .monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.customcolor::before, .monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.customcolor::before { background-image: none; } .monaco-editor.vs-dark .suggest-widget .monaco-list .monaco-list-row .suggest-icon.folder::before, -.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.folder::before { background-image: url('Folder_inverse_16x.svg'); } +.monaco-editor.hc-black .suggest-widget .monaco-list .monaco-list-row .suggest-icon.folder::before { background-image: url('folder-dark.svg'); } diff --git a/src/vs/editor/contrib/suggest/media/template-dark.svg b/src/vs/editor/contrib/suggest/media/template-dark.svg new file mode 100644 index 000000000..425ced36f --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/template-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/template-light.svg b/src/vs/editor/contrib/suggest/media/template-light.svg new file mode 100644 index 000000000..496d8f7c8 --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/template-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/variable-dark.svg b/src/vs/editor/contrib/suggest/media/variable-dark.svg new file mode 100644 index 000000000..687fcabff --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/variable-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/media/variable-light.svg b/src/vs/editor/contrib/suggest/media/variable-light.svg new file mode 100644 index 000000000..ede7e9434 --- /dev/null +++ b/src/vs/editor/contrib/suggest/media/variable-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/editor/contrib/suggest/suggest.ts b/src/vs/editor/contrib/suggest/suggest.ts index 045aadd0b..241a826a5 100644 --- a/src/vs/editor/contrib/suggest/suggest.ts +++ b/src/vs/editor/contrib/suggest/suggest.ts @@ -16,6 +16,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { CancellationToken } from 'vs/base/common/cancellation'; import { Range } from 'vs/editor/common/core/range'; import { FuzzyScore } from 'vs/base/common/filters'; +import { isDisposable, DisposableStore } from 'vs/base/common/lifecycle'; export const Context = { Visible: new RawContextKey('suggestWidgetVisible', false), @@ -121,7 +122,6 @@ export function provideSuggestionItems( token: CancellationToken = CancellationToken.None ): Promise { - const allSuggestions: CompletionItem[] = []; const wordUntil = model.getWordUntilPosition(position); const defaultRange = new Range(position.lineNumber, wordUntil.startColumn, position.lineNumber, wordUntil.endColumn); @@ -135,9 +135,12 @@ export function provideSuggestionItems( supports.unshift([_snippetSuggestSupport]); } + const allSuggestions: CompletionItem[] = []; + const disposables = new DisposableStore(); + let hasResult = false; + // 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; const factory = supports.map(supports => () => { // for each support in the group ask for suggestions return Promise.all(supports.map(provider => { @@ -162,6 +165,9 @@ export function provideSuggestionItems( allSuggestions.push(new CompletionItem(position, suggestion, container, provider, model)); } } + if (isDisposable(container)) { + disposables.add(container); + } } if (len !== allSuggestions.length && provider !== _snippetSuggestSupport) { @@ -177,6 +183,7 @@ export function provideSuggestionItems( return hasResult || token.isCancellationRequested; }).then(() => { if (token.isCancellationRequested) { + disposables.dispose(); return Promise.reject(canceled()); } return allSuggestions.sort(getSuggestionComparator(options.snippetSortOrder)); @@ -244,29 +251,35 @@ export function getSuggestionComparator(snippetConfig: SnippetSortOrder): (a: Co return _snippetComparators.get(snippetConfig)!; } -registerDefaultLanguageCommand('_executeCompletionItemProvider', (model, position, args) => { +registerDefaultLanguageCommand('_executeCompletionItemProvider', async (model, position, args) => { const result: modes.CompletionList = { incomplete: false, suggestions: [] }; - let resolving: Promise[] = []; - let maxItemsToResolve = args['maxItemsToResolve'] || 0; + const disposables = new DisposableStore(); + const resolving: Promise[] = []; + const maxItemsToResolve = args['maxItemsToResolve'] || 0; - return provideSuggestionItems(model, position).then(items => { - for (const item of items) { - if (resolving.length < maxItemsToResolve) { - resolving.push(item.resolve(CancellationToken.None)); - } - result.incomplete = result.incomplete || item.container.incomplete; - result.suggestions.push(item.completion); + const items = await provideSuggestionItems(model, position); + for (const item of items) { + if (resolving.length < maxItemsToResolve) { + resolving.push(item.resolve(CancellationToken.None)); } - }).then(() => { - return Promise.all(resolving); - }).then(() => { + result.incomplete = result.incomplete || item.container.incomplete; + result.suggestions.push(item.completion); + if (isDisposable(item.container)) { + disposables.add(item.container); + } + } + + try { + await Promise.all(resolving); return result; - }); + } finally { + setTimeout(() => disposables.dispose(), 0); + } }); interface SuggestController extends IEditorContribution { diff --git a/src/vs/editor/contrib/suggest/suggestCommitCharacters.ts b/src/vs/editor/contrib/suggest/suggestCommitCharacters.ts new file mode 100644 index 000000000..20a765653 --- /dev/null +++ b/src/vs/editor/contrib/suggest/suggestCommitCharacters.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. + *--------------------------------------------------------------------------------------------*/ + +import { isNonEmptyArray } from 'vs/base/common/arrays'; +import { DisposableStore } from 'vs/base/common/lifecycle'; +import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; +import { ISelectedSuggestion, SuggestWidget } from './suggestWidget'; +import { CharacterSet } from 'vs/editor/common/core/characterClassifier'; + +export class CommitCharacterController { + + private readonly _disposables = new DisposableStore(); + + private _active?: { + readonly acceptCharacters: CharacterSet; + readonly item: ISelectedSuggestion; + }; + + constructor(editor: ICodeEditor, widget: SuggestWidget, accept: (selected: ISelectedSuggestion) => any) { + + this._disposables.add(widget.onDidShow(() => this._onItem(widget.getFocusedItem()))); + this._disposables.add(widget.onDidFocus(this._onItem, this)); + this._disposables.add(widget.onDidHide(this.reset, this)); + + this._disposables.add(editor.onWillType(text => { + if (this._active) { + const ch = text.charCodeAt(text.length - 1); + if (this._active.acceptCharacters.has(ch) && editor.getConfiguration().contribInfo.acceptSuggestionOnCommitCharacter) { + accept(this._active.item); + } + } + })); + } + + private _onItem(selected: ISelectedSuggestion | undefined): void { + if (!selected || !isNonEmptyArray(selected.item.completion.commitCharacters)) { + // no item or no commit characters + this.reset(); + return; + } + + if (this._active && this._active.item.item === selected.item) { + // still the same item + return; + } + + // keep item and its commit characters + const acceptCharacters = new CharacterSet(); + for (const ch of selected.item.completion.commitCharacters) { + if (ch.length > 0) { + acceptCharacters.add(ch.charCodeAt(0)); + } + } + this._active = { acceptCharacters, item: selected }; + } + + reset(): void { + this._active = undefined; + } + + dispose() { + this._disposables.dispose(); + } +} diff --git a/src/vs/editor/contrib/suggest/suggestController.ts b/src/vs/editor/contrib/suggest/suggestController.ts index c824573c9..aac58cf80 100644 --- a/src/vs/editor/contrib/suggest/suggestController.ts +++ b/src/vs/editor/contrib/suggest/suggestController.ts @@ -7,7 +7,7 @@ import { alert } from 'vs/base/browser/ui/aria/aria'; import { isNonEmptyArray } from 'vs/base/common/arrays'; import { onUnexpectedError } from 'vs/base/common/errors'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import { dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { dispose, IDisposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorAction, EditorCommand, registerEditorAction, registerEditorCommand, registerEditorContribution, ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { EditOperation } from 'vs/editor/common/core/editOperation'; @@ -31,57 +31,8 @@ import { WordContextKey } from 'vs/editor/contrib/suggest/wordContextKey'; import { Event } from 'vs/base/common/event'; import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService'; import { IdleValue } from 'vs/base/common/async'; -import { CharacterSet } from 'vs/editor/common/core/characterClassifier'; import { isObject } from 'vs/base/common/types'; - -class AcceptOnCharacterOracle { - - private _disposables: IDisposable[] = []; - - private _active?: { - readonly acceptCharacters: CharacterSet; - readonly item: ISelectedSuggestion; - }; - - constructor(editor: ICodeEditor, widget: SuggestWidget, accept: (selected: ISelectedSuggestion) => any) { - - this._disposables.push(widget.onDidShow(() => this._onItem(widget.getFocusedItem()))); - this._disposables.push(widget.onDidFocus(this._onItem, this)); - this._disposables.push(widget.onDidHide(this.reset, this)); - - this._disposables.push(editor.onWillType(text => { - if (this._active) { - const ch = text.charCodeAt(text.length - 1); - if (this._active.acceptCharacters.has(ch) && editor.getConfiguration().contribInfo.acceptSuggestionOnCommitCharacter) { - accept(this._active.item); - } - } - })); - } - - private _onItem(selected: ISelectedSuggestion | undefined): void { - if (!selected || !isNonEmptyArray(selected.item.completion.commitCharacters)) { - this.reset(); - return; - } - - const acceptCharacters = new CharacterSet(); - for (const ch of selected.item.completion.commitCharacters) { - if (ch.length > 0) { - acceptCharacters.add(ch.charCodeAt(0)); - } - } - this._active = { acceptCharacters, item: selected }; - } - - reset(): void { - this._active = undefined; - } - - dispose() { - dispose(this._disposables); - } -} +import { CommitCharacterController } from './suggestCommitCharacters'; export class SuggestController implements IEditorContribution { @@ -94,7 +45,7 @@ export class SuggestController implements IEditorContribution { private readonly _model: SuggestModel; private readonly _widget: IdleValue; private readonly _alternatives: IdleValue; - private _toDispose: IDisposable[] = []; + private readonly _toDispose = new DisposableStore(); private readonly _sticky = false; // for development purposes only @@ -112,23 +63,21 @@ export class SuggestController implements IEditorContribution { const widget = this._instantiationService.createInstance(SuggestWidget, this._editor); - this._toDispose.push(widget); - this._toDispose.push(widget.onDidSelect(item => this._onDidSelectItem(item, false, true), this)); + this._toDispose.add(widget); + this._toDispose.add(widget.onDidSelect(item => this._insertSuggestion(item, false, true), this)); // Wire up logic to accept a suggestion on certain characters - const autoAcceptOracle = new AcceptOnCharacterOracle(this._editor, widget, item => this._onDidSelectItem(item, false, true)); - this._toDispose.push( - autoAcceptOracle, - this._model.onDidSuggest(e => { - if (e.completionModel.items.length === 0) { - autoAcceptOracle.reset(); - } - }) - ); + const commitCharacterController = new CommitCharacterController(this._editor, widget, item => this._insertSuggestion(item, false, true)); + this._toDispose.add(commitCharacterController); + this._toDispose.add(this._model.onDidSuggest(e => { + if (e.completionModel.items.length === 0) { + commitCharacterController.reset(); + } + })); // Wire up makes text edit context key let makesTextEdit = SuggestContext.MakesTextEdit.bindTo(this._contextKeyService); - this._toDispose.push(widget.onDidFocus(({ item }) => { + this._toDispose.add(widget.onDidFocus(({ item }) => { const position = this._editor.getPosition()!; const startColumn = item.completion.range.startColumn; @@ -152,38 +101,35 @@ export class SuggestController implements IEditorContribution { } makesTextEdit.set(value); })); - this._toDispose.push({ - dispose() { makesTextEdit.reset(); } - }); + this._toDispose.add(toDisposable(() => makesTextEdit.reset())); return widget; }); this._alternatives = new IdleValue(() => { - let res = new SuggestAlternatives(this._editor, this._contextKeyService); - this._toDispose.push(res); - return res; + return this._toDispose.add(new SuggestAlternatives(this._editor, this._contextKeyService)); }); - this._toDispose.push(_instantiationService.createInstance(WordContextKey, _editor)); + this._toDispose.add(_instantiationService.createInstance(WordContextKey, _editor)); - this._toDispose.push(this._model.onDidTrigger(e => { + this._toDispose.add(this._model.onDidTrigger(e => { this._widget.getValue().showTriggered(e.auto, e.shy ? 250 : 50); })); - this._toDispose.push(this._model.onDidSuggest(e => { + this._toDispose.add(this._model.onDidSuggest(e => { if (!e.shy) { let index = this._memoryService.select(this._editor.getModel()!, this._editor.getPosition()!, e.completionModel.items); this._widget.getValue().showSuggestions(e.completionModel, index, e.isFrozen, e.auto); } })); - this._toDispose.push(this._model.onDidCancel(e => { + this._toDispose.add(this._model.onDidCancel(e => { if (this._widget && !e.retrigger) { this._widget.getValue().hideWidget(); } })); - this._toDispose.push(this._editor.onDidBlurEditorWidget(() => { + this._toDispose.add(this._editor.onDidBlurEditorWidget(() => { if (!this._sticky) { this._model.cancel(); + this._model.clear(); } })); @@ -193,7 +139,7 @@ export class SuggestController implements IEditorContribution { const { acceptSuggestionOnEnter } = this._editor.getConfiguration().contribInfo; acceptSuggestionsOnEnter.set(acceptSuggestionOnEnter === 'on' || acceptSuggestionOnEnter === 'smart'); }; - this._toDispose.push(this._editor.onDidChangeConfiguration((e) => updateFromConfig())); + this._toDispose.add(this._editor.onDidChangeConfiguration(() => updateFromConfig())); updateFromConfig(); } @@ -203,17 +149,17 @@ export class SuggestController implements IEditorContribution { } dispose(): void { - this._toDispose = dispose(this._toDispose); + this._alternatives.dispose(); + this._toDispose.dispose(); this._widget.dispose(); - if (this._model) { - this._model.dispose(); - } + this._model.dispose(); } - protected _onDidSelectItem(event: ISelectedSuggestion | undefined, keepAlternativeSuggestions: boolean, undoStops: boolean): void { + protected _insertSuggestion(event: ISelectedSuggestion | undefined, keepAlternativeSuggestions: boolean, undoStops: boolean): void { if (!event || !event.item) { this._alternatives.getValue().reset(); this._model.cancel(); + this._model.clear(); return; } if (!this._editor.hasModel()) { @@ -247,13 +193,13 @@ export class SuggestController implements IEditorContribution { const overwriteBefore = position.column - suggestion.range.startColumn; const overwriteAfter = suggestion.range.endColumn - position.column; - SnippetController2.get(this._editor).insert( - insertText, - overwriteBefore + columnDelta, + SnippetController2.get(this._editor).insert(insertText, { + overwriteBefore: overwriteBefore + columnDelta, overwriteAfter, - false, false, - !(suggestion.insertTextRules! & CompletionItemInsertTextRule.KeepWhitespace) - ); + undoStopBefore: false, + undoStopAfter: false, + adjustWhitespace: !(suggestion.insertTextRules! & CompletionItemInsertTextRule.KeepWhitespace) + }); if (undoStops) { this._editor.pushUndoStop(); @@ -262,6 +208,7 @@ export class SuggestController implements IEditorContribution { if (!suggestion.command) { // done this._model.cancel(); + this._model.clear(); } else if (suggestion.command.id === TriggerSuggestAction.id) { // retigger @@ -269,7 +216,9 @@ export class SuggestController implements IEditorContribution { } else { // exec command, done - this._commandService.executeCommand(suggestion.command.id, ...(suggestion.command.arguments ? [...suggestion.command.arguments] : [])).catch(onUnexpectedError); + this._commandService.executeCommand(suggestion.command.id, ...(suggestion.command.arguments ? [...suggestion.command.arguments] : [])) + .catch(onUnexpectedError) + .finally(() => this._model.clear()); // <- clear only now, keep commands alive this._model.cancel(); } @@ -282,7 +231,7 @@ export class SuggestController implements IEditorContribution { if (modelVersionNow !== model.getAlternativeVersionId()) { model.undo(); } - this._onDidSelectItem(next, false, false); + this._insertSuggestion(next, false, false); break; } }); @@ -364,7 +313,7 @@ export class SuggestController implements IEditorContribution { return; } this._editor.pushUndoStop(); - this._onDidSelectItem({ index, item, model: completionModel }, true, false); + this._insertSuggestion({ index, item, model: completionModel }, true, false); }, undefined, listener); }); @@ -375,10 +324,8 @@ export class SuggestController implements IEditorContribution { } acceptSelectedSuggestion(keepAlternativeSuggestions?: boolean): void { - if (this._widget) { - const item = this._widget.getValue().getFocusedItem(); - this._onDidSelectItem(item, !!keepAlternativeSuggestions, true); - } + const item = this._widget.getValue().getFocusedItem(); + this._insertSuggestion(item, !!keepAlternativeSuggestions, true); } acceptNextSuggestion() { @@ -390,58 +337,41 @@ export class SuggestController implements IEditorContribution { } cancelSuggestWidget(): void { - if (this._widget) { - this._model.cancel(); - this._widget.getValue().hideWidget(); - } + this._model.cancel(); + this._model.clear(); + this._widget.getValue().hideWidget(); } selectNextSuggestion(): void { - if (this._widget) { - this._widget.getValue().selectNext(); - } + this._widget.getValue().selectNext(); } selectNextPageSuggestion(): void { - if (this._widget) { - this._widget.getValue().selectNextPage(); - } + this._widget.getValue().selectNextPage(); } selectLastSuggestion(): void { - if (this._widget) { - this._widget.getValue().selectLast(); - } + this._widget.getValue().selectLast(); } selectPrevSuggestion(): void { - if (this._widget) { - this._widget.getValue().selectPrevious(); - } + this._widget.getValue().selectPrevious(); } selectPrevPageSuggestion(): void { - if (this._widget) { - this._widget.getValue().selectPreviousPage(); - } + this._widget.getValue().selectPreviousPage(); } selectFirstSuggestion(): void { - if (this._widget) { - this._widget.getValue().selectFirst(); - } + this._widget.getValue().selectFirst(); } toggleSuggestionDetails(): void { - if (this._widget) { - this._widget.getValue().toggleDetails(); - } + this._widget.getValue().toggleDetails(); } toggleSuggestionFocus(): void { - if (this._widget) { - this._widget.getValue().toggleDetailsFocus(); - } + this._widget.getValue().toggleDetailsFocus(); } } diff --git a/src/vs/editor/contrib/suggest/suggestMemory.ts b/src/vs/editor/contrib/suggest/suggestMemory.ts index e99c55af5..7e19017b7 100644 --- a/src/vs/editor/contrib/suggest/suggestMemory.ts +++ b/src/vs/editor/contrib/suggest/suggestMemory.ts @@ -5,7 +5,7 @@ import { LRUCache, TernarySearchTree } from 'vs/base/common/map'; -import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; +import { IStorageService, StorageScope, WillSaveStateReason } from 'vs/platform/storage/common/storage'; import { ITextModel } from 'vs/editor/common/model'; import { IPosition } from 'vs/editor/common/core/position'; import { CompletionItemKind, completionKindFromString } from 'vs/editor/common/modes'; @@ -221,7 +221,11 @@ export class SuggestMemoryService extends Disposable implements ISuggestMemorySe }; this._persistSoon = this._register(new RunOnceScheduler(() => this._saveState(), 500)); - this._register(_storageService.onWillSaveState(() => this._saveState())); + this._register(_storageService.onWillSaveState(e => { + if (e.reason === WillSaveStateReason.SHUTDOWN) { + this._saveState(); + } + })); this._register(this._configService.onDidChangeConfiguration(e => { if (e.affectsConfiguration('editor.suggestSelection') || e.affectsConfiguration('editor.suggest.shareSuggestSelections')) { diff --git a/src/vs/editor/contrib/suggest/suggestModel.ts b/src/vs/editor/contrib/suggest/suggestModel.ts index ef6857032..63de4055d 100644 --- a/src/vs/editor/contrib/suggest/suggestModel.ts +++ b/src/vs/editor/contrib/suggest/suggestModel.ts @@ -7,7 +7,7 @@ import { isNonEmptyArray } from 'vs/base/common/arrays'; import { TimeoutTimer } from 'vs/base/common/async'; import { onUnexpectedError } from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, DisposableStore, isDisposable } from 'vs/base/common/lifecycle'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { CursorChangeReason, ICursorSelectionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; import { Position } from 'vs/editor/common/core/position'; @@ -91,18 +91,18 @@ export const enum State { export class SuggestModel implements IDisposable { - private _toDispose: IDisposable[] = []; + private readonly _toDispose = new DisposableStore(); private _quickSuggestDelay: number; private _triggerCharacterListener: IDisposable; private readonly _triggerQuickSuggest = new TimeoutTimer(); - private readonly _triggerRefilter = new TimeoutTimer(); private _state: State = State.Idle; private _requestToken?: CancellationTokenSource; private _context?: LineContext; private _currentSelection: Selection; - private _completionModel?: CompletionModel; + private _completionModel: CompletionModel | undefined; + private readonly _completionDisposables = new DisposableStore(); private readonly _onDidCancel = new Emitter(); private readonly _onDidTrigger = new Emitter(); private readonly _onDidSuggest = new Emitter(); @@ -118,36 +118,36 @@ export class SuggestModel implements IDisposable { this._currentSelection = this._editor.getSelection() || new Selection(1, 1, 1, 1); // wire up various listeners - this._toDispose.push(this._editor.onDidChangeModel(() => { + this._toDispose.add(this._editor.onDidChangeModel(() => { this._updateTriggerCharacters(); this.cancel(); })); - this._toDispose.push(this._editor.onDidChangeModelLanguage(() => { + this._toDispose.add(this._editor.onDidChangeModelLanguage(() => { this._updateTriggerCharacters(); this.cancel(); })); - this._toDispose.push(this._editor.onDidChangeConfiguration(() => { + this._toDispose.add(this._editor.onDidChangeConfiguration(() => { this._updateTriggerCharacters(); this._updateQuickSuggest(); })); - this._toDispose.push(CompletionProviderRegistry.onDidChange(() => { + this._toDispose.add(CompletionProviderRegistry.onDidChange(() => { this._updateTriggerCharacters(); this._updateActiveSuggestSession(); })); - this._toDispose.push(this._editor.onDidChangeCursorSelection(e => { + this._toDispose.add(this._editor.onDidChangeCursorSelection(e => { this._onCursorChange(e); })); let editorIsComposing = false; - this._toDispose.push(this._editor.onCompositionStart(() => { + this._toDispose.add(this._editor.onCompositionStart(() => { editorIsComposing = true; })); - this._toDispose.push(this._editor.onCompositionEnd(() => { + this._toDispose.add(this._editor.onCompositionEnd(() => { // refilter when composition ends editorIsComposing = false; this._refilterCompletionItems(); })); - this._toDispose.push(this._editor.onDidChangeModelContent(() => { + this._toDispose.add(this._editor.onDidChangeModelContent(() => { // only filter completions when the editor isn't // composing a character, e.g. ¨ + u makes ü but just // ¨ cannot be used for filtering @@ -161,9 +161,9 @@ export class SuggestModel implements IDisposable { } dispose(): void { - dispose([this._onDidCancel, this._onDidSuggest, this._onDidTrigger, this._triggerCharacterListener, this._triggerQuickSuggest, this._triggerRefilter]); - this._toDispose = dispose(this._toDispose); - dispose(this._completionModel); + dispose([this._onDidCancel, this._onDidSuggest, this._onDidTrigger, this._triggerCharacterListener, this._triggerQuickSuggest]); + this._toDispose.dispose(); + this._completionDisposables.dispose(); this.cancel(); } @@ -221,20 +221,22 @@ export class SuggestModel implements IDisposable { cancel(retrigger: boolean = false): void { if (this._state !== State.Idle) { - this._triggerRefilter.cancel(); this._triggerQuickSuggest.cancel(); if (this._requestToken) { this._requestToken.cancel(); this._requestToken = undefined; } this._state = State.Idle; - dispose(this._completionModel); this._completionModel = undefined; this._context = undefined; this._onDidCancel.fire({ retrigger }); } } + clear() { + this._completionDisposables.clear(); + } + private _updateActiveSuggestSession(): void { if (this._state !== State.Idle) { if (!this._editor.hasModel() || !CompletionProviderRegistry.has(this._editor.getModel())) { @@ -291,6 +293,9 @@ export class SuggestModel implements IDisposable { this.cancel(); this._triggerQuickSuggest.cancelAndSet(() => { + if (this._state !== State.Idle) { + return; + } if (!LineContext.shouldAutoTrigger(this._editor)) { return; } @@ -328,14 +333,15 @@ export class SuggestModel implements IDisposable { } private _refilterCompletionItems(): void { - if (this._state === State.Idle) { - return; - } - if (!this._editor.hasModel()) { - return; - } - // refine active suggestion - this._triggerRefilter.cancelAndSet(() => { + // Re-filter suggestions. This MUST run async because filtering/scoring + // uses the model content AND the cursor position. The latter is NOT + // updated when the document has changed (the event which drives this method) + // and therefore a little pause (next mirco task) is needed. See: + // https://stackoverflow.com/questions/25915634/difference-between-microtask-and-macrotask-within-an-event-loop-context#25933985 + Promise.resolve().then(() => { + if (this._state === State.Idle) { + return; + } if (!this._editor.hasModel()) { return; } @@ -343,7 +349,7 @@ export class SuggestModel implements IDisposable { const position = this._editor.getPosition(); const ctx = new LineContext(model, position, this._state === State.Auto, false); this._onNewContext(ctx); - }, 0); + }); } trigger(context: SuggestTriggerContext, retrigger: boolean = false, onlyFrom?: Set, existingItems?: CompletionItem[]): void { @@ -436,7 +442,6 @@ export class SuggestModel implements IDisposable { } const ctx = new LineContext(model, this._editor.getPosition(), auto, context.shy); - dispose(this._completionModel); this._completionModel = new CompletionModel(items, this._context!.column, { leadingLineContent: ctx.leadingLineContent, characterCountDelta: ctx.column - this._context!.column @@ -444,6 +449,14 @@ export class SuggestModel implements IDisposable { wordDistance, this._editor.getConfiguration().contribInfo.suggest ); + + // store containers so that they can be disposed later + for (const item of items) { + if (isDisposable(item.container)) { + this._completionDisposables.add(item.container); + } + } + this._onNewContext(ctx); }).catch(onUnexpectedError); diff --git a/src/vs/editor/contrib/suggest/suggestWidget.ts b/src/vs/editor/contrib/suggest/suggestWidget.ts index 054feaf90..e6ac05dab 100644 --- a/src/vs/editor/contrib/suggest/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/suggestWidget.ts @@ -9,8 +9,8 @@ import { createMatches } from 'vs/base/common/filters'; import * as strings from 'vs/base/common/strings'; import { Event, Emitter } from 'vs/base/common/event'; import { onUnexpectedError } from 'vs/base/common/errors'; -import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; -import { addClass, append, $, hide, removeClass, show, toggleClass, getDomNodePagePosition, hasClass } from 'vs/base/browser/dom'; +import { IDisposable, dispose, toDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle'; +import { addClass, append, $, hide, removeClass, show, toggleClass, getDomNodePagePosition, hasClass, addDisposableListener } from 'vs/base/browser/dom'; import { IListVirtualDelegate, IListEvent, IListRenderer, IListMouseEvent } from 'vs/base/browser/ui/list/list'; import { List } from 'vs/base/browser/ui/list/listWidget'; import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; @@ -29,8 +29,7 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag import { MarkdownRenderer } from 'vs/editor/contrib/markdown/markdownRenderer'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IOpenerService } from 'vs/platform/opener/common/opener'; -import { TimeoutTimer, CancelablePromise, createCancelablePromise } from 'vs/base/common/async'; -import { CancellationToken } from 'vs/base/common/cancellation'; +import { TimeoutTimer, CancelablePromise, createCancelablePromise, disposableTimeout } from 'vs/base/common/async'; import { CompletionItemKind, completionKindToCssClass } from 'vs/editor/common/modes'; import { IconLabel, IIconLabelValueOptions } from 'vs/base/browser/ui/iconLabel/iconLabel'; import { getIconClasses } from 'vs/editor/common/services/getIconClasses'; @@ -38,6 +37,9 @@ import { IModelService } from 'vs/editor/common/services/modelService'; import { URI } from 'vs/base/common/uri'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { FileKind } from 'vs/platform/files/common/files'; +import { MarkdownString } from 'vs/base/common/htmlContent'; +import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; const expandSuggestionDocsByDefault = false; @@ -48,7 +50,7 @@ interface ISuggestionTemplateData { iconLabel: IconLabel; typeLabel: HTMLElement; readMore: HTMLElement; - disposables: IDisposable[]; + disposables: DisposableStore; } /** @@ -104,7 +106,8 @@ class Renderer implements IListRenderer renderTemplate(container: HTMLElement): ISuggestionTemplateData { const data = Object.create(null); - data.disposables = []; + data.disposables = new DisposableStore(); + data.root = container; addClass(data.root, 'show-file-icons'); @@ -115,7 +118,7 @@ class Renderer implements IListRenderer const main = append(text, $('.main')); data.iconLabel = new IconLabel(main, { supportHighlights: true }); - data.disposables.push(data.iconLabel); + data.disposables.add(data.iconLabel); data.typeLabel = append(main, $('span.type-label')); @@ -143,9 +146,9 @@ class Renderer implements IListRenderer configureFont(); - Event.chain(this.editor.onDidChangeConfiguration.bind(this.editor)) + data.disposables.add(Event.chain(this.editor.onDidChangeConfiguration.bind(this.editor)) .filter(e => e.fontInfo || e.contribInfo) - .on(configureFont, null, data.disposables); + .on(configureFont, null)); return data; } @@ -214,7 +217,7 @@ class Renderer implements IListRenderer } disposeTemplate(templateData: ISuggestionTemplateData): void { - templateData.disposables = dispose(templateData.disposables); + templateData.disposables.dispose(); } } @@ -227,6 +230,18 @@ const enum State { Details } + +let _explainMode = false; +KeybindingsRegistry.registerCommandAndKeybindingRule({ + id: 'suggest.toggleExplainMode', + handler() { + _explainMode = !_explainMode; + }, + when: SuggestContext.Visible, + weight: KeybindingWeight.EditorContrib, + primary: KeyMod.CtrlCmd | KeyCode.US_SLASH, +}); + class SuggestionDetails { private el: HTMLElement; @@ -237,7 +252,7 @@ class SuggestionDetails { private type: HTMLElement; private docs: HTMLElement; private ariaLabel: string | null; - private disposables: IDisposable[]; + private readonly disposables: DisposableStore; private renderDisposeable: IDisposable; private borderWidth: number = 1; @@ -246,18 +261,18 @@ class SuggestionDetails { private readonly widget: SuggestWidget, private readonly editor: ICodeEditor, private readonly markdownRenderer: MarkdownRenderer, - private readonly triggerKeybindingLabel: string + private readonly triggerKeybindingLabel: string, ) { - this.disposables = []; + this.disposables = new DisposableStore(); this.el = append(container, $('.details')); - this.disposables.push(toDisposable(() => container.removeChild(this.el))); + this.disposables.add(toDisposable(() => container.removeChild(this.el))); this.body = $('.body'); this.scrollbar = new DomScrollableElement(this.body, {}); append(this.el, this.scrollbar.getDomNode()); - this.disposables.push(this.scrollbar); + this.disposables.add(this.scrollbar); this.header = append(this.body, $('.header')); this.close = append(this.header, $('span.close')); @@ -280,10 +295,27 @@ class SuggestionDetails { return this.el; } - render(item: CompletionItem): void { + renderLoading(): void { + this.type.textContent = nls.localize('loading', "Loading..."); + this.docs.textContent = ''; + } + + renderItem(item: CompletionItem): void { this.renderDisposeable = dispose(this.renderDisposeable); - if (!item || !canExpandCompletionItem(item)) { + let { documentation, detail } = item.completion; + // --- documentation + + if (_explainMode) { + let md = ''; + md += `score: ${item.score[0]}${item.word ? `, compared '${item.completion.filterText && (item.completion.filterText + ' (filterText)') || item.completion.label}' with '${item.word}'` : ' (no prefix)'}\n`; + md += `distance: ${item.distance}, see localityBonus-setting\n`; + md += `index: ${item.idx}, based on ${item.completion.sortText && `sortText: "${item.completion.sortText}"` || 'label'}\n`; + documentation = new MarkdownString().appendCodeblock('empty', md); + detail = `Provider: ${item.provider._debugDisplayName}`; + } + + if (!_explainMode && !canExpandCompletionItem(item)) { this.type.textContent = ''; this.docs.textContent = ''; addClass(this.el, 'no-docs'); @@ -291,19 +323,20 @@ class SuggestionDetails { return; } removeClass(this.el, 'no-docs'); - if (typeof item.completion.documentation === 'string') { + if (typeof documentation === 'string') { removeClass(this.docs, 'markdown-docs'); - this.docs.textContent = item.completion.documentation; + this.docs.textContent = documentation; } else { addClass(this.docs, 'markdown-docs'); this.docs.innerHTML = ''; - const renderedContents = this.markdownRenderer.render(item.completion.documentation); + const renderedContents = this.markdownRenderer.render(documentation); this.renderDisposeable = renderedContents; this.docs.appendChild(renderedContents.element); } - if (item.completion.detail) { - this.type.innerText = item.completion.detail; + // --- details + if (detail) { + this.type.innerText = detail; show(this.type); } else { this.type.innerText = ''; @@ -327,8 +360,8 @@ class SuggestionDetails { this.ariaLabel = strings.format( '{0}{1}', - item.completion.detail || '', - item.completion.documentation ? (typeof item.completion.documentation === 'string' ? item.completion.documentation : item.completion.documentation.value) : ''); + detail || '', + documentation ? (typeof documentation === 'string' ? documentation : documentation.value) : ''); } getAriaLabel() { @@ -380,7 +413,7 @@ class SuggestionDetails { } dispose(): void { - this.disposables = dispose(this.disposables); + this.disposables.dispose(); this.renderDisposeable = dispose(this.renderDisposeable); } } @@ -400,10 +433,11 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate | null; private focusedItem: CompletionItem | null; private ignoreFocusEvents = false; @@ -421,14 +455,13 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate(); private onDidFocusEmitter = new Emitter(); private onDidHideEmitter = new Emitter(); private onDidShowEmitter = new Emitter(); - readonly onDidSelect: Event = this.onDidSelectEmitter.event; readonly onDidFocus: Event = this.onDidFocusEmitter.event; readonly onDidHide: Event = this.onDidHideEmitter.event; @@ -458,17 +491,22 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate { + if (e.target === this.element) { + this.hideWidget(); + } + })); this.messageElement = append(this.element, $('.message')); this.listElement = append(this.element, $('.tree')); - this.details = new SuggestionDetails(this.element, this, this.editor, markdownRenderer, triggerKeybindingLabel); + this.details = instantiationService.createInstance(SuggestionDetails, this.element, this, this.editor, markdownRenderer, triggerKeybindingLabel); const applyIconStyle = () => toggleClass(this.element, 'no-icons', !this.editor.getConfiguration().contribInfo.suggest.showIcons); applyIconStyle(); @@ -481,19 +519,18 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate this.onThemeChange(t)), - editor.onDidLayoutChange(() => this.onEditorLayoutChange()), - this.list.onMouseDown(e => this.onListMouseDown(e)), - this.list.onSelectionChange(e => this.onListSelection(e)), - this.list.onFocusChange(e => this.onListFocus(e)), - this.editor.onDidChangeCursorSelection(() => this.onCursorSelectionChanged()), - this.editor.onDidChangeConfiguration(e => e.contribInfo && applyIconStyle()) - ]; + this.toDispose.add(attachListStyler(this.list, themeService, { + listInactiveFocusBackground: editorSuggestWidgetSelectedBackground, + listInactiveFocusOutline: activeContrastBorder + })); + this.toDispose.add(themeService.onThemeChange(t => this.onThemeChange(t))); + this.toDispose.add(editor.onDidLayoutChange(() => this.onEditorLayoutChange())); + this.toDispose.add(this.list.onMouseDown(e => this.onListMouseDown(e))); + this.toDispose.add(this.list.onSelectionChange(e => this.onListSelection(e))); + this.toDispose.add(this.list.onFocusChange(e => this.onListFocus(e))); + this.toDispose.add(this.editor.onDidChangeCursorSelection(() => this.onCursorSelectionChanged())); + this.toDispose.add(this.editor.onDidChangeConfiguration(e => e.contribInfo && applyIconStyle())); + this.suggestWidgetVisible = SuggestContext.Visible.bindTo(contextKeyService); this.suggestWidgetMultipleSuggestions = SuggestContext.MultipleSuggestions.bindTo(contextKeyService); @@ -545,10 +582,8 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate { - this.onDidSelectEmitter.fire({ item, index, model: completionModel }); - this.editor.focus(); - }); + this.onDidSelectEmitter.fire({ item, index, model: completionModel }); + this.editor.focus(); } private _getSuggestionAriaAlertLabel(item: CompletionItem): string { @@ -627,10 +662,16 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate item.resolve(token)); + this.currentSuggestionDetails = createCancelablePromise(async token => { + const loading = disposableTimeout(() => this.showDetails(true), 250); + token.onCancellationRequested(() => loading.dispose()); + const result = await item.resolve(token); + loading.dispose(); + return result; + }); this.currentSuggestionDetails.then(() => { - if (this.list.length < index) { + if (index >= this.list.length || item !== this.list.element(index)) { return; } @@ -641,17 +682,13 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate { - if (this.focusedItem === item) { - this.currentSuggestionDetails = null; - } - }); + }).catch(onUnexpectedError); } // emit an event @@ -721,10 +758,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate { - this.loadingTimeout = null; - this.setState(State.Loading); - }, delay); + this.loadingTimeout = disposableTimeout(() => this.setState(State.Loading), delay); } } @@ -732,10 +766,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate { class TestCtrl extends SuggestController { - _onDidSelectItem(item: ISelectedSuggestion) { - super._onDidSelectItem(item, false, true); + _insertSuggestion(item: ISelectedSuggestion) { + super._insertSuggestion(item, false, true); } } const ctrl = editor.registerAndInstantiateContribution(TestCtrl); @@ -687,7 +688,7 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { const [first] = event.completionModel.items; assert.equal(first.completion.label, 'bar'); - ctrl._onDidSelectItem({ item: first, index: 0, model: event.completionModel }); + ctrl._insertSuggestion({ item: first, index: 0, model: event.completionModel }); }); assert.equal( @@ -776,9 +777,13 @@ suite('SuggestModel - TriggerAndCancelOracle', function () { }, event => { assert.equal(event.auto, true); assert.equal(event.completionModel.items.length, 2); - assert.equal(disposeA, 1); - assert.equal(disposeB, 0); + + // clean up + model.clear(); + assert.equal(disposeA, 2); // provide got called two times! + assert.equal(disposeB, 1); }); + }); }); }); diff --git a/src/vs/editor/contrib/suggest/wordContextKey.ts b/src/vs/editor/contrib/suggest/wordContextKey.ts index de2a026e5..9461b86d3 100644 --- a/src/vs/editor/contrib/suggest/wordContextKey.ts +++ b/src/vs/editor/contrib/suggest/wordContextKey.ts @@ -4,15 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import { RawContextKey, IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; -export class WordContextKey { +export class WordContextKey extends Disposable { static readonly AtEnd = new RawContextKey('atEndOfWord', false); private readonly _ckAtEnd: IContextKey; - private readonly _confListener: IDisposable; private _enabled: boolean; private _selectionListener?: IDisposable; @@ -21,13 +20,15 @@ export class WordContextKey { private readonly _editor: ICodeEditor, @IContextKeyService contextKeyService: IContextKeyService, ) { + super(); this._ckAtEnd = WordContextKey.AtEnd.bindTo(contextKeyService); - this._confListener = this._editor.onDidChangeConfiguration(e => e.contribInfo && this._update()); + this._register(this._editor.onDidChangeConfiguration(e => e.contribInfo && this._update())); this._update(); } dispose(): void { - dispose(this._confListener, this._selectionListener); + super.dispose(); + dispose(this._selectionListener); this._ckAtEnd.reset(); } diff --git a/src/vs/editor/contrib/toggleTabFocusMode/toggleTabFocusMode.ts b/src/vs/editor/contrib/toggleTabFocusMode/toggleTabFocusMode.ts index 22dabb97e..37e746577 100644 --- a/src/vs/editor/contrib/toggleTabFocusMode/toggleTabFocusMode.ts +++ b/src/vs/editor/contrib/toggleTabFocusMode/toggleTabFocusMode.ts @@ -20,7 +20,7 @@ export class ToggleTabFocusModeAction extends EditorAction { id: ToggleTabFocusModeAction.ID, label: nls.localize({ key: 'toggle.tabMovesFocus', comment: ['Turn on/off use of tab key for moving focus around VS Code'] }, "Toggle Tab Key Moves Focus"), alias: 'Toggle Tab Key Moves Focus', - precondition: null, + precondition: undefined, kbOpts: { kbExpr: null, primary: KeyMod.CtrlCmd | KeyCode.KEY_M, diff --git a/src/vs/editor/contrib/tokenization/tokenization.ts b/src/vs/editor/contrib/tokenization/tokenization.ts index aeb5b996e..87e8ab760 100644 --- a/src/vs/editor/contrib/tokenization/tokenization.ts +++ b/src/vs/editor/contrib/tokenization/tokenization.ts @@ -14,7 +14,7 @@ class ForceRetokenizeAction extends EditorAction { id: 'editor.action.forceRetokenize', label: nls.localize('forceRetokenize', "Developer: Force Retokenize"), alias: 'Developer: Force Retokenize', - precondition: null + precondition: undefined }); } @@ -23,11 +23,12 @@ class ForceRetokenizeAction extends EditorAction { return; } const model = editor.getModel(); - model.flushTokens(); + model.resetTokenization(); const sw = new StopWatch(true); model.forceTokenization(model.getLineCount()); sw.stop(); console.log(`tokenization took ${sw.elapsed()}`); + } } diff --git a/src/vs/editor/contrib/wordHighlighter/wordHighlighter.ts b/src/vs/editor/contrib/wordHighlighter/wordHighlighter.ts index 6b9180968..0820b22ce 100644 --- a/src/vs/editor/contrib/wordHighlighter/wordHighlighter.ts +++ b/src/vs/editor/contrib/wordHighlighter/wordHighlighter.ts @@ -9,7 +9,7 @@ import { CancelablePromise, createCancelablePromise, first, timeout } from 'vs/b import { CancellationToken } from 'vs/base/common/cancellation'; import { onUnexpectedError, onUnexpectedExternalError } from 'vs/base/common/errors'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IActiveCodeEditor, ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorAction, IActionOptions, registerDefaultLanguageCommand, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import { CursorChangeReason, ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; @@ -164,7 +164,7 @@ class WordHighlighter { private occurrencesHighlight: boolean; private readonly model: ITextModel; private _decorationIds: string[]; - private toUnhook: IDisposable[]; + private readonly toUnhook = new DisposableStore(); private workerRequestTokenId: number = 0; private workerRequest: IOccurenceAtPositionRequest | null; @@ -183,8 +183,7 @@ class WordHighlighter { this._ignorePositionChangeEvent = false; this.occurrencesHighlight = this.editor.getConfiguration().contribInfo.occurrencesHighlight; this.model = this.editor.getModel(); - this.toUnhook = []; - this.toUnhook.push(editor.onDidChangeCursorPosition((e: ICursorPositionChangedEvent) => { + this.toUnhook.add(editor.onDidChangeCursorPosition((e: ICursorPositionChangedEvent) => { if (this._ignorePositionChangeEvent) { // We are changing the position => ignore this event @@ -199,10 +198,10 @@ class WordHighlighter { this._onPositionChanged(e); })); - this.toUnhook.push(editor.onDidChangeModelContent((e) => { + this.toUnhook.add(editor.onDidChangeModelContent((e) => { this._stopAll(); })); - this.toUnhook.push(editor.onDidChangeConfiguration((e) => { + this.toUnhook.add(editor.onDidChangeConfiguration((e) => { let newValue = this.editor.getConfiguration().contribInfo.occurrencesHighlight; if (this.occurrencesHighlight !== newValue) { this.occurrencesHighlight = newValue; @@ -454,7 +453,7 @@ class WordHighlighter { public dispose(): void { this._stopAll(); - this.toUnhook = dispose(this.toUnhook); + this.toUnhook.dispose(); } } diff --git a/src/vs/editor/contrib/wordOperations/test/wordOperations.test.ts b/src/vs/editor/contrib/wordOperations/test/wordOperations.test.ts index 1cae3b38f..98c22c721 100644 --- a/src/vs/editor/contrib/wordOperations/test/wordOperations.test.ts +++ b/src/vs/editor/contrib/wordOperations/test/wordOperations.test.ts @@ -137,6 +137,22 @@ suite('WordOperations', () => { assert.deepEqual(actual, EXPECTED); }); + test('cursorWordLeftSelect - issue #74369: cursorWordLeft and cursorWordLeftSelect do not behave consistently', () => { + const EXPECTED = [ + '|this.|is.|a.|test', + ].join('\n'); + const [text,] = deserializePipePositions(EXPECTED); + const actualStops = testRepeatedActionAndExtractPositions( + text, + new Position(1, 15), + ed => cursorWordLeft(ed, true), + ed => ed.getPosition()!, + ed => ed.getPosition()!.equals(new Position(1, 1)) + ); + const actual = serializePipePositions(text, actualStops); + assert.deepEqual(actual, EXPECTED); + }); + test('cursorWordStartLeft', () => { // This is the behaviour observed in Visual Studio, please do not touch test const EXPECTED = ['| |/* |Just |some |more |text |a|+= |3 |+|5|-|3 |+ |7 |*/| '].join('\n'); diff --git a/src/vs/editor/contrib/wordOperations/wordOperations.ts b/src/vs/editor/contrib/wordOperations/wordOperations.ts index b39269c30..dc4e111f9 100644 --- a/src/vs/editor/contrib/wordOperations/wordOperations.ts +++ b/src/vs/editor/contrib/wordOperations/wordOperations.ts @@ -98,7 +98,7 @@ export class CursorWordStartLeft extends WordLeftCommand { inSelectionMode: false, wordNavigationType: WordNavigationType.WordStart, id: 'cursorWordStartLeft', - precondition: null, + precondition: undefined, kbOpts: { kbExpr: EditorContextKeys.textInputFocus, primary: KeyMod.CtrlCmd | KeyCode.LeftArrow, @@ -115,7 +115,7 @@ export class CursorWordEndLeft extends WordLeftCommand { inSelectionMode: false, wordNavigationType: WordNavigationType.WordEnd, id: 'cursorWordEndLeft', - precondition: null + precondition: undefined }); } } @@ -126,7 +126,7 @@ export class CursorWordLeft extends WordLeftCommand { inSelectionMode: false, wordNavigationType: WordNavigationType.WordStartFast, id: 'cursorWordLeft', - precondition: null + precondition: undefined }); } } @@ -137,7 +137,7 @@ export class CursorWordStartLeftSelect extends WordLeftCommand { inSelectionMode: true, wordNavigationType: WordNavigationType.WordStart, id: 'cursorWordStartLeftSelect', - precondition: null, + precondition: undefined, kbOpts: { kbExpr: EditorContextKeys.textInputFocus, primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.LeftArrow, @@ -154,7 +154,7 @@ export class CursorWordEndLeftSelect extends WordLeftCommand { inSelectionMode: true, wordNavigationType: WordNavigationType.WordEnd, id: 'cursorWordEndLeftSelect', - precondition: null + precondition: undefined }); } } @@ -163,9 +163,9 @@ export class CursorWordLeftSelect extends WordLeftCommand { constructor() { super({ inSelectionMode: true, - wordNavigationType: WordNavigationType.WordStart, + wordNavigationType: WordNavigationType.WordStartFast, id: 'cursorWordLeftSelect', - precondition: null + precondition: undefined }); } } @@ -176,7 +176,7 @@ export class CursorWordStartRight extends WordRightCommand { inSelectionMode: false, wordNavigationType: WordNavigationType.WordStart, id: 'cursorWordStartRight', - precondition: null + precondition: undefined }); } } @@ -187,7 +187,7 @@ export class CursorWordEndRight extends WordRightCommand { inSelectionMode: false, wordNavigationType: WordNavigationType.WordEnd, id: 'cursorWordEndRight', - precondition: null, + precondition: undefined, kbOpts: { kbExpr: EditorContextKeys.textInputFocus, primary: KeyMod.CtrlCmd | KeyCode.RightArrow, @@ -204,7 +204,7 @@ export class CursorWordRight extends WordRightCommand { inSelectionMode: false, wordNavigationType: WordNavigationType.WordEnd, id: 'cursorWordRight', - precondition: null + precondition: undefined }); } } @@ -215,7 +215,7 @@ export class CursorWordStartRightSelect extends WordRightCommand { inSelectionMode: true, wordNavigationType: WordNavigationType.WordStart, id: 'cursorWordStartRightSelect', - precondition: null + precondition: undefined }); } } @@ -226,7 +226,7 @@ export class CursorWordEndRightSelect extends WordRightCommand { inSelectionMode: true, wordNavigationType: WordNavigationType.WordEnd, id: 'cursorWordEndRightSelect', - precondition: null, + precondition: undefined, kbOpts: { kbExpr: EditorContextKeys.textInputFocus, primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.RightArrow, @@ -243,7 +243,7 @@ export class CursorWordRightSelect extends WordRightCommand { inSelectionMode: true, wordNavigationType: WordNavigationType.WordEnd, id: 'cursorWordRightSelect', - precondition: null + precondition: undefined }); } } diff --git a/src/vs/editor/contrib/wordPartOperations/wordPartOperations.ts b/src/vs/editor/contrib/wordPartOperations/wordPartOperations.ts index 0c20a58b7..5887bd84a 100644 --- a/src/vs/editor/contrib/wordPartOperations/wordPartOperations.ts +++ b/src/vs/editor/contrib/wordPartOperations/wordPartOperations.ts @@ -79,7 +79,7 @@ export class CursorWordPartLeft extends WordPartLeftCommand { inSelectionMode: false, wordNavigationType: WordNavigationType.WordStart, id: 'cursorWordPartLeft', - precondition: null, + precondition: undefined, kbOpts: { kbExpr: EditorContextKeys.textInputFocus, primary: 0, @@ -98,7 +98,7 @@ export class CursorWordPartLeftSelect extends WordPartLeftCommand { inSelectionMode: true, wordNavigationType: WordNavigationType.WordStart, id: 'cursorWordPartLeftSelect', - precondition: null, + precondition: undefined, kbOpts: { kbExpr: EditorContextKeys.textInputFocus, primary: 0, @@ -122,7 +122,7 @@ export class CursorWordPartRight extends WordPartRightCommand { inSelectionMode: false, wordNavigationType: WordNavigationType.WordEnd, id: 'cursorWordPartRight', - precondition: null, + precondition: undefined, kbOpts: { kbExpr: EditorContextKeys.textInputFocus, primary: 0, @@ -138,7 +138,7 @@ export class CursorWordPartRightSelect extends WordPartRightCommand { inSelectionMode: true, wordNavigationType: WordNavigationType.WordEnd, id: 'cursorWordPartRightSelect', - precondition: null, + precondition: undefined, kbOpts: { kbExpr: EditorContextKeys.textInputFocus, primary: 0, diff --git a/src/vs/editor/contrib/zoneWidget/zoneWidget.ts b/src/vs/editor/contrib/zoneWidget/zoneWidget.ts index 8afb01b96..34ed306c9 100644 --- a/src/vs/editor/contrib/zoneWidget/zoneWidget.ts +++ b/src/vs/editor/contrib/zoneWidget/zoneWidget.ts @@ -8,7 +8,7 @@ import * as dom from 'vs/base/browser/dom'; import { IHorizontalSashLayoutProvider, ISashEvent, Orientation, Sash, SashState } from 'vs/base/browser/ui/sash/sash'; import { Color, RGBA } from 'vs/base/common/color'; import { IdGenerator } from 'vs/base/common/idGenerator'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { DisposableStore } from 'vs/base/common/lifecycle'; import * as objects from 'vs/base/common/objects'; import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, IViewZone, IViewZoneChangeAccessor } from 'vs/editor/browser/editorBrowser'; import { EditorLayoutInfo } from 'vs/editor/common/config/editorOptions'; @@ -165,7 +165,7 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { private _positionMarkerId: string[] = []; protected _viewZone: ViewZoneDelegate | null; - protected _disposables: IDisposable[] = []; + protected readonly _disposables = new DisposableStore(); public container: HTMLElement; public domNode: HTMLElement; @@ -183,7 +183,7 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { this.domNode.setAttribute('role', 'presentation'); } - this._disposables.push(this.editor.onDidLayoutChange((info: EditorLayoutInfo) => { + this._disposables.add(this.editor.onDidLayoutChange((info: EditorLayoutInfo) => { const width = this._getWidth(info); this.domNode.style.width = width + 'px'; this.domNode.style.left = this._getLeft(info) + 'px'; @@ -193,7 +193,7 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { public dispose(): void { - dispose(this._disposables); + this._disposables.dispose(); if (this._overlayWidget) { this.editor.removeOverlayWidget(this._overlayWidget); @@ -225,7 +225,7 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { this.domNode.appendChild(this.container); if (this.options.showArrow) { this._arrow = new Arrow(this.editor); - this._disposables.push(this._arrow); + this._disposables.add(this._arrow); } this._fillContainer(this.container); this._initSash(); @@ -470,7 +470,10 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { // --- sash private _initSash(): void { - this._resizeSash = new Sash(this.domNode, this, { orientation: Orientation.HORIZONTAL }); + if (this._resizeSash) { + return; + } + this._resizeSash = this._disposables.add(new Sash(this.domNode, this, { orientation: Orientation.HORIZONTAL })); if (!this.options.isResizeable) { this._resizeSash.hide(); @@ -478,7 +481,7 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { } let data: { startY: number; heightInLines: number; } | undefined; - this._disposables.push(this._resizeSash.onDidStart((e: ISashEvent) => { + this._disposables.add(this._resizeSash.onDidStart((e: ISashEvent) => { if (this._viewZone) { data = { startY: e.startY, @@ -487,11 +490,11 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { } })); - this._disposables.push(this._resizeSash.onDidEnd(() => { + this._disposables.add(this._resizeSash.onDidEnd(() => { data = undefined; })); - this._disposables.push(this._resizeSash.onDidChange((evt: ISashEvent) => { + this._disposables.add(this._resizeSash.onDidChange((evt: ISashEvent) => { if (data) { let lineDelta = (evt.currentY - data.startY) / this.editor.getConfiguration().lineHeight; let roundedLineDelta = lineDelta < 0 ? Math.ceil(lineDelta) : Math.floor(lineDelta); diff --git a/src/vs/editor/editor.worker.ts b/src/vs/editor/editor.worker.ts index 41140026a..4586cafab 100644 --- a/src/vs/editor/editor.worker.ts +++ b/src/vs/editor/editor.worker.ts @@ -4,7 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { SimpleWorkerServer } from 'vs/base/common/worker/simpleWorker'; -import { EditorSimpleWorkerImpl } from 'vs/editor/common/services/editorSimpleWorker'; +import { EditorSimpleWorker } from 'vs/editor/common/services/editorSimpleWorker'; +import { EditorWorkerHost } from 'vs/editor/common/services/editorWorkerServiceImpl'; let initialized = false; @@ -14,10 +15,9 @@ export function initialize(foreignModule: any) { } initialized = true; - const editorWorker = new EditorSimpleWorkerImpl(foreignModule); const simpleWorker = new SimpleWorkerServer((msg) => { (self).postMessage(msg); - }, editorWorker); + }, (host: EditorWorkerHost) => new EditorSimpleWorker(host, foreignModule)); self.onmessage = (e) => { simpleWorker.onmessage(e.data); diff --git a/src/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts b/src/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts index 4bde524d5..22e860f8e 100644 --- a/src/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts +++ b/src/vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp.ts @@ -27,7 +27,7 @@ import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiati import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IOpenerService } from 'vs/platform/opener/common/opener'; -import { contrastBorder, editorWidgetBackground, widgetShadow } from 'vs/platform/theme/common/colorRegistry'; +import { contrastBorder, editorWidgetBackground, widgetShadow, editorWidgetForeground } from 'vs/platform/theme/common/colorRegistry'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; import { AccessibilityHelpNLS } from 'vs/editor/common/standaloneStrings'; @@ -330,7 +330,7 @@ class ShowAccessibilityHelpAction extends EditorAction { id: 'editor.action.showAccessibilityHelp', label: AccessibilityHelpNLS.showAccessibilityHelpAction, alias: 'Show Accessibility Help', - precondition: null, + precondition: undefined, kbOpts: { kbExpr: EditorContextKeys.focus, primary: (browser.isIE ? KeyMod.CtrlCmd | KeyCode.F1 : KeyMod.Alt | KeyCode.F1), @@ -371,6 +371,11 @@ registerThemingParticipant((theme, collector) => { if (widgetBackground) { collector.addRule(`.monaco-editor .accessibilityHelpWidget { background-color: ${widgetBackground}; }`); } + const widgetForeground = theme.getColor(editorWidgetForeground); + if (widgetForeground) { + collector.addRule(`.monaco-editor .accessibilityHelpWidget { color: ${widgetForeground}; }`); + } + const widgetShadowColor = theme.getColor(widgetShadow); if (widgetShadowColor) { diff --git a/src/vs/editor/standalone/browser/colorizer.ts b/src/vs/editor/standalone/browser/colorizer.ts index ff47bd408..d72d14104 100644 --- a/src/vs/editor/standalone/browser/colorizer.ts +++ b/src/vs/editor/standalone/browser/colorizer.ts @@ -128,7 +128,8 @@ export class Colorizer { -1, 'none', false, - false + false, + null )); return renderResult.html; } @@ -195,7 +196,8 @@ function _fakeColorize(lines: string[], tabSize: number): string { -1, 'none', false, - false + false, + null )); html = html.concat(renderResult.html); @@ -231,7 +233,8 @@ function _actualColorize(lines: string[], tabSize: number, tokenizationSupport: -1, 'none', false, - false + false, + null )); html = html.concat(renderResult.html); diff --git a/src/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.css b/src/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.css index 34cb14546..7579f7890 100644 --- a/src/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.css +++ b/src/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.css @@ -13,12 +13,12 @@ position: absolute; resize: none; overflow: hidden; - background: url('keyboard.svg') center center no-repeat; + background: url('keyboard-light.svg') center center no-repeat; border: 4px solid #F6F6F6; border-radius: 4px; } .monaco-editor.vs-dark .iPadShowKeyboard { - background: url('keyboard-inverse.svg') center center no-repeat; + background: url('keyboard-dark.svg') center center no-repeat; border: 4px solid #252526; } \ No newline at end of file diff --git a/src/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.ts b/src/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.ts index e48dcba65..1fc21b5fc 100644 --- a/src/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.ts +++ b/src/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.ts @@ -6,24 +6,23 @@ import 'vs/css!./iPadShowKeyboard'; import * as browser from 'vs/base/browser/browser'; import * as dom from 'vs/base/browser/dom'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { Disposable } from 'vs/base/common/lifecycle'; import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, OverlayWidgetPositionPreference } from 'vs/editor/browser/editorBrowser'; import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import { IEditorContribution } from 'vs/editor/common/editorCommon'; -export class IPadShowKeyboard implements IEditorContribution { +export class IPadShowKeyboard extends Disposable implements IEditorContribution { private static readonly ID = 'editor.contrib.iPadShowKeyboard'; private readonly editor: ICodeEditor; private widget: ShowKeyboardWidget | null; - private toDispose: IDisposable[]; constructor(editor: ICodeEditor) { + super(); this.editor = editor; - this.toDispose = []; if (browser.isIPad) { - this.toDispose.push(editor.onDidChangeConfiguration(() => this.update())); + this._register(editor.onDidChangeConfiguration(() => this.update())); this.update(); } } @@ -48,7 +47,7 @@ export class IPadShowKeyboard implements IEditorContribution { } public dispose(): void { - this.toDispose = dispose(this.toDispose); + super.dispose(); if (this.widget) { this.widget.dispose(); this.widget = null; @@ -56,25 +55,24 @@ export class IPadShowKeyboard implements IEditorContribution { } } -class ShowKeyboardWidget implements IOverlayWidget { +class ShowKeyboardWidget extends Disposable implements IOverlayWidget { private static readonly ID = 'editor.contrib.ShowKeyboardWidget'; private readonly editor: ICodeEditor; private readonly _domNode: HTMLElement; - private _toDispose: IDisposable[]; constructor(editor: ICodeEditor) { + super(); this.editor = editor; this._domNode = document.createElement('textarea'); this._domNode.className = 'iPadShowKeyboard'; - this._toDispose = []; - this._toDispose.push(dom.addDisposableListener(this._domNode, 'touchstart', (e) => { + this._register(dom.addDisposableListener(this._domNode, 'touchstart', (e) => { this.editor.focus(); })); - this._toDispose.push(dom.addDisposableListener(this._domNode, 'focus', (e) => { + this._register(dom.addDisposableListener(this._domNode, 'focus', (e) => { this.editor.focus(); })); @@ -83,7 +81,7 @@ class ShowKeyboardWidget implements IOverlayWidget { public dispose(): void { this.editor.removeOverlayWidget(this); - this._toDispose = dispose(this._toDispose); + super.dispose(); } // ----- IOverlayWidget API diff --git a/src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard-dark.svg b/src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard-dark.svg new file mode 100644 index 000000000..308c53316 --- /dev/null +++ b/src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard-dark.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard-inverse.svg b/src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard-inverse.svg deleted file mode 100644 index 40bfc4742..000000000 --- a/src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard-inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard-light.svg b/src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard-light.svg new file mode 100644 index 000000000..152bf777f --- /dev/null +++ b/src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard-light.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard.svg b/src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard.svg deleted file mode 100644 index bd1322427..000000000 --- a/src/vs/editor/standalone/browser/iPadShowKeyboard/keyboard.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.ts b/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.ts index e60dd1925..47a2da412 100644 --- a/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.ts +++ b/src/vs/editor/standalone/browser/inspectTokens/inspectTokens.ts @@ -84,7 +84,7 @@ class InspectTokens extends EditorAction { id: 'editor.action.inspectTokens', label: InspectTokensNLS.inspectTokensAction, alias: 'Developer: Inspect Tokens', - precondition: null + precondition: undefined }); } diff --git a/src/vs/editor/standalone/browser/quickOpen/gotoLine.ts b/src/vs/editor/standalone/browser/quickOpen/gotoLine.ts index 2b89cf276..5d2960a54 100644 --- a/src/vs/editor/standalone/browser/quickOpen/gotoLine.ts +++ b/src/vs/editor/standalone/browser/quickOpen/gotoLine.ts @@ -149,7 +149,7 @@ export class GotoLineAction extends BaseEditorQuickOpenAction { id: 'editor.action.gotoLine', label: GoToLineNLS.gotoLineActionLabel, alias: 'Go to Line...', - precondition: null, + precondition: undefined, kbOpts: { kbExpr: EditorContextKeys.focus, primary: KeyMod.CtrlCmd | KeyCode.KEY_G, diff --git a/src/vs/editor/standalone/browser/quickOpen/quickCommand.ts b/src/vs/editor/standalone/browser/quickOpen/quickCommand.ts index e50716e3c..b5d2715c8 100644 --- a/src/vs/editor/standalone/browser/quickOpen/quickCommand.ts +++ b/src/vs/editor/standalone/browser/quickOpen/quickCommand.ts @@ -82,7 +82,7 @@ export class QuickCommandAction extends BaseEditorQuickOpenAction { id: 'editor.action.quickCommand', label: QuickCommandNLS.quickCommandActionLabel, alias: 'Command Palette', - precondition: null, + precondition: undefined, kbOpts: { kbExpr: EditorContextKeys.focus, primary: (browser.isIE ? KeyMod.Alt | KeyCode.F1 : KeyCode.F1), diff --git a/src/vs/editor/standalone/browser/quickOpen/quickOutline.css b/src/vs/editor/standalone/browser/quickOpen/quickOutline.css index 3278328cd..c87261992 100644 --- a/src/vs/editor/standalone/browser/quickOpen/quickOutline.css +++ b/src/vs/editor/standalone/browser/quickOpen/quickOutline.css @@ -11,33 +11,37 @@ .vs-dark .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon { background-image: url('symbol-sprite.svg'); background-repeat: no-repeat; + background-position: -2px -22px; } +.monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon, .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.method, .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.function, -.monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.constructor { background-position: 0 -4px; } +.monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.constructor { background-position: -2px -2px; } .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.field, -.monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.variable { background-position: -22px -4px; } -.monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.class { background-position: -43px -3px; } -.monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.interface { background-position: -63px -4px; } -.monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.module { background-position: -82px -4px; } -.monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.property { background-position: -102px -3px; } -.monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.enum { background-position: -122px -3px; } -.monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.rule { background-position: -242px -4px; } -.monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.file { background-position: -262px -4px; } +.monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.variable { background-position: -22px -2px; } +.monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.class { background-position: -42px -2px; } +.monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.interface { background-position: -62px -2px; } +.monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.module { background-position: -82px -2px; } +.monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.property { background-position: -102px -2px; } +.monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.enum { background-position: -122px -2px; } +.monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.string { background-position: -202px -2px; } +.monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.rule { background-position: -242px -2px; } +.monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.file { background-position: -262px -2px; } .vs-dark .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.method, .vs-dark .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.function, -.vs-dark .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.constructor { background-position: 0 -24px; } +.vs-dark .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.constructor { background-position: -2px -22px; } .vs-dark .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.field, -.vs-dark .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.variable { background-position: -22px -24px; } -.vs-dark .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.class { background-position: -43px -23px; } -.vs-dark .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.interface { background-position: -63px -24px; } -.vs-dark .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.module { background-position: -82px -24px; } -.vs-dark .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.property { background-position: -102px -23px; } -.vs-dark .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.enum { background-position: -122px -23px; } -.vs-dark .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.rule { background-position: -242px -24px; } -.vs-dark .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.file { background-position: -262px -24px; } +.vs-dark .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.variable { background-position: -22px -22px; } +.vs-dark .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.class { background-position: -43px -22px; } +.vs-dark .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.interface { background-position: -63px -22px; } +.vs-dark .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.module { background-position: -82px -22px; } +.vs-dark .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.property { background-position: -102px -22px; } +.vs-dark .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.enum { background-position: -122px -22px; } +.vs-dark .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.string { background-position: -202px -22px; } +.vs-dark .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.rule { background-position: -242px -22px; } +.vs-dark .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.file { background-position: -262px -22px; } .hc-black .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon { background: none; @@ -50,46 +54,47 @@ display: inline-block; } +.hc-black .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon:before, .hc-black .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.method:before, .hc-black .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.function:before, .hc-black .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.constructor:before { - content: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBhdGggZmlsbD0iI0IxODBENyIgZD0iTTUuNSAzbC00LjUgMi44NTd2NC4yODVsNC41IDIuODU4IDQuNS0yLjg1N3YtNC4yODZsLTQuNS0yLjg1N3ptLS41IDguNDk4bC0zLTEuOTA1di0yLjgxNmwzIDEuOTA1djIuODE2em0tMi4zNTgtNS40OThsMi44NTgtMS44MTUgMi44NTggMS44MTUtMi44NTggMS44MTUtMi44NTgtMS44MTV6bTYuMzU4IDMuNTkzbC0zIDEuOTA1di0yLjgxNWwzLTEuOTA1djIuODE1eiIvPjwvc3ZnPg=="); - margin-left: 2px; + content: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yIDQuODU3NDlMMi40ODU1IDRMNy40ODU1IDFIOC41MTQ1TDEzLjUxNDUgNEwxNCA0Ljg1NzQ5VjEwLjg1NzVMMTMuNTE0NSAxMS43MTVMOC41MTQ1IDE0LjcxNUg3LjQ4NTVMMi40ODU1IDExLjcxNUwyIDEwLjg1NzVWNC44NTc0OVpNNy41IDEzLjU1NzVMMyAxMC44NTc1VjUuNjk5NzVMNy41IDguMTU0M1YxMy41NTc1Wk04LjUgMTMuNTU3NUwxMyAxMC44NTc1VjUuNjk5NzVMOC41IDguMTU0M1YxMy41NTc1Wk04IDEuODU3NDlMMy4yNTkxMyA0LjcwMjAxTDggNy4yODc5NEwxMi43NDA5IDQuNzAyMDFMOCAxLjg1NzQ5WiIgZmlsbD0iI0IxODBENyIvPgo8L3N2Zz4K"); } .hc-black .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.field:before, .hc-black .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.variable:before { - content: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBhdGggZmlsbD0iIzc1QkVGRiIgZD0iTTEgNnY0bDQgMiA2LTN2LTRsLTQtMi02IDN6bTQgMWwtMi0xIDQtMiAyIDEtNCAyeiIvPjwvc3ZnPg=="); - margin-left: 2px; + content: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xIDYuMzk0NDNMMS41NTI3OSA1LjVMOC41NTI3OSAySDkuNDQ3MjFMMTQuNDQ3MiA0LjVMMTUgNS4zOTQ0M1Y5Ljg5NDQzTDE0LjQ0NzIgMTAuNzg4OUw3LjQ0NzIxIDE0LjI4ODlINi41NTI3OUwxLjU1Mjc5IDExLjc4ODlMMSAxMC44OTQ0VjYuMzk0NDNaTTYuNSAxMy4xNDQ0TDIgMTAuODk0NFY3LjE3MDk0TDYuNSA5LjIxNjM5VjEzLjE0NDRaTTcuNSAxMy4xNDQ0TDE0IDkuODk0NDNWNi4xNzk1NEw3LjUgOS4yMTI4N1YxMy4xNDQ0Wk05IDIuODk0NDNMMi4zMzcyOCA2LjIyNTc5TDYuOTk3MjUgOC4zNDM5NkwxMy42NzA2IDUuMjI5NzNMOSAyLjg5NDQzWiIgZmlsbD0iIzc1QkVGRiIvPgo8L3N2Zz4K"); } .hc-black .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.class:before { - content: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBvbHlnb24gZmlsbD0iI0U4QUI1MyIgcG9pbnRzPSIxMS45OTgsMTEuMDAyIDksMTEgOSw3IDExLDcgMTAsOCAxMiwxMCAxNSw3IDEzLDUgMTIsNiA3LDYgOSw0IDYsMSAxLDYgNCw5IDYsNyA4LDcgOCwxMiAxMSwxMiAxMCwxMyAxMiwxNSAxNSwxMiAxMywxMCIvPjwvc3ZnPg=="); + content: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0zLjM1MzU2IDYuNjQ2NDJMMi4wNjA2NiA1LjM1MzUzTDUuMzUzNTYgMi4wNjA2NUw2LjY0NjQ1IDMuMzUzNTRMMy4zNTM1NiA2LjY0NjQyWk01IDFMMSA0Ljk5OTk4VjUuNzA3MDhMMyA3LjcwNzA3SDMuNzA3MTFMNC44NTM1NSA2LjU2MDYzVjEyLjM1MzVMNS4zNTM1NSAxMi44NTM1SDEwLjAwOTdWMTMuMzc0MUwxMS4zNDMgMTQuNzA3NEgxMi4wNTAxTDE0LjcxNjggMTIuMDQwN1YxMS4zMzM2TDEzLjM4MzUgMTAuMDAwM0gxMi42NzYzTDEwLjgyMzEgMTEuODUzNUg1Ljg1MzU1VjcuODkzNTVIMTAuMDA5N1Y4LjM3NDAxTDExLjM0MyA5LjcwNzM0SDEyLjA1MDFMMTQuNzE2OCA3LjA0MDY4VjYuMzMzNTdMMTMuMzgzNSA1LjAwMDI0SDEyLjY3NjNMMTAuODYzIDYuODEzNTZINS44NTM1NVY1LjU2MDY0TDcuNzA3MTEgMy43MDcwOVYyLjk5OTk5TDUuNzA3MTEgMUg1Wk0xMS4wNzAzIDguMDIwNDZMMTEuNjk2NiA4LjY0NjY4TDEzLjY1NjEgNi42ODcxM0wxMy4wMjk5IDYuMDYwOUwxMS4wNzAzIDguMDIwNDZaTTExLjA3MDMgMTMuMDIwNUwxMS42OTY2IDEzLjY0NjdMMTMuNjU2MSAxMS42ODcyTDEzLjAyOTkgMTEuMDYxTDExLjA3MDMgMTMuMDIwNVoiIGZpbGw9IiNFRTlEMjgiLz4KPC9zdmc+Cg=="); } .hc-black .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.interface:before { - content: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBhdGggZmlsbD0iIzc1QkVGRiIgZD0iTTExLjUgNGMtMS43NTkgMC0zLjIwNCAxLjMwOC0zLjQ0OSAzaC0zLjEyMmMtLjIyMy0uODYxLS45OTgtMS41LTEuOTI5LTEuNS0xLjEwNCAwLTIgLjg5NS0yIDIgMCAxLjEwNC44OTYgMiAyIDIgLjkzMSAwIDEuNzA2LS42MzkgMS45MjktMS41aDMuMTIyYy4yNDUgMS42OTEgMS42OSAzIDMuNDQ5IDMgMS45MyAwIDMuNS0xLjU3IDMuNS0zLjUgMC0xLjkzMS0xLjU3LTMuNS0zLjUtMy41em0wIDVjLS44MjcgMC0xLjUtLjY3NC0xLjUtMS41IDAtLjgyOC42NzMtMS41IDEuNS0xLjVzMS41LjY3MiAxLjUgMS41YzAgLjgyNi0uNjczIDEuNS0xLjUgMS41eiIvPjwvc3ZnPg=="); + content: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xMS41IDVDMTAuMTE5MyA1IDkgNi4xMTkyOSA5IDcuNUM5IDguODgwNzEgMTAuMTE5MyAxMCAxMS41IDEwQzEyLjg4MDcgMTAgMTQgOC44ODA3MSAxNCA3LjVDMTQgNi4xMTkyOSAxMi44ODA3IDUgMTEuNSA1Wk04LjAzNTQ0IDhDOC4yNzgwNiA5LjY5NjE1IDkuNzM2NzYgMTEgMTEuNSAxMUMxMy40MzMgMTEgMTUgOS40MzMgMTUgNy41QzE1IDUuNTY3IDEzLjQzMyA0IDExLjUgNEM5LjczNjc2IDQgOC4yNzgwNiA1LjMwMzg1IDguMDM1NDQgN0g0LjkzNjk5QzQuNzE0OTcgNi4xMzczOSAzLjkzMTkyIDUuNSAzIDUuNUMxLjg5NTQzIDUuNSAxIDYuMzk1NDMgMSA3LjVDMSA4LjYwNDU3IDEuODk1NDMgOS41IDMgOS41QzMuOTMxOTIgOS41IDQuNzE0OTcgOC44NjI2MSA0LjkzNjk5IDhIOC4wMzU0NFoiIGZpbGw9IiM3NUJFRkYiLz4KPC9zdmc+Cg=="); } .hc-black .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.module:before { - content: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBhdGggZmlsbD0iI0M1QzVDNSIgZD0iTTkgMTF2LTFjMC0uODM0LjQ5Ni0xLjczOCAxLTItLjUwNC0uMjctMS0xLjE2OC0xLTJ2LTFjMC0uODQtLjU4NC0xLTEtMXYtMWMyLjA4MyAwIDIgMS4xNjYgMiAydjFjMCAuOTY5LjcwMy45OCAxIDF2MmMtLjMyMi4wMi0xIC4wNTMtMSAxdjFjMCAuODM0LjA4MyAyLTIgMnYtMWMuODMzIDAgMS0xIDEtMXptLTYgMHYtMWMwLS44MzQtLjQ5Ni0xLjczOC0xLTIgLjUwNC0uMjcgMS0xLjE2OCAxLTJ2LTFjMC0uODQuNTg0LTEgMS0xdi0xYy0yLjA4MyAwLTIgMS4xNjYtMiAydjFjMCAuOTY5LS43MDMuOTgtMSAxdjJjLjMyMi4wMiAxIC4wNTMgMSAxdjFjMCAuODM0LS4wODMgMiAyIDJ2LTFjLS44MzMgMC0xLTEtMS0xeiIvPjwvc3ZnPg=="); - margin-left: 2px; + content: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik02IDIuOTgzNjFWMi45NzE4NFYySDUuOTEwODNDNS41OTc0MyAyIDUuMjk0MDcgMi4wNjE2MSA1LjAwMTI4IDIuMTg0NzNDNC43MDgxOCAyLjMwNzk4IDQuNDQ5NDIgMi40ODQ3NCA0LjIyNTc4IDIuNzE0OThDNC4wMDMxMSAyLjk0NDIyIDMuODM3OTIgMy4xOTQ5OCAzLjczMjgyIDMuNDY3NjZMMy43MzIzMyAzLjQ2ODk4QzMuNjMzODIgMy43MzUyIDMuNTY4MTQgNC4wMTIwMSAzLjUzNTMzIDQuMjk5MTdMMy41MzUxOSA0LjMwMDUzQzMuNTA2NzggNC41ODA1IDMuNDk4NyA0Ljg2ODQ0IDMuNTEwODQgNS4xNjQyOEMzLjUyMjcyIDUuNDUzNzkgMy41Mjg2NiA1Ljc0MzI5IDMuNTI4NjYgNi4wMzI3OUMzLjUyODY2IDYuMjM1NTYgMy40ODk3NCA2LjQyNTk0IDMuNDEyIDYuNjA1MDdMMy40MTE2IDYuNjA2MDFDMy4zMzY4NyA2Ljc4Mjk2IDMuMjM0MjMgNi45Mzg2NiAzLjEwMzE3IDcuMDczNTlDMi45NzY0NCA3LjIwNDA1IDIuODI0NjYgNy4zMTA1NSAyLjY0NjcyIDcuMzkyNUMyLjQ3MDYgNy40Njk1NCAyLjI4NDk3IDcuNTA4MiAyLjA4OTE3IDcuNTA4MkgyVjcuNlY4LjRWOC40OTE4SDIuMDg5MTdDMi4yODQ2NSA4LjQ5MTggMi40NzAwMSA4LjUzMjM4IDIuNjQ2MDEgOC42MTMzNEwyLjY0NzQyIDguNjEzOTZDMi44MjQ1NyA4LjY5MTU3IDIuOTc1NzcgOC43OTc2MiAzLjEwMjIxIDguOTMxNjFMMy4xMDQxMiA4LjkzMzUyQzMuMjM0MjggOS4wNjM3IDMuMzM2NTkgOS4yMTg3MSAzLjQxMTI5IDkuMzk5NDJMMy40MTIwMSA5LjQwMTA4QzMuNDg5ODYgOS41ODA0NyAzLjUyODY2IDkuNzY4ODMgMy41Mjg2NiA5Ljk2NzIxQzMuNTI4NjYgMTAuMjU2NyAzLjUyMjcyIDEwLjU0NjIgMy41MTA4NCAxMC44MzU3QzMuNDk4NyAxMS4xMzE2IDMuNTA2NzcgMTEuNDIxNSAzLjUzNTE2IDExLjcwNTVMMy41MzUzNSAxMS43MDcyQzMuNTY4MTkgMTEuOTkwMyAzLjYzMzg3IDEyLjI2NSAzLjczMjMyIDEyLjUzMUwzLjczMjgzIDEyLjUzMjNDMy44Mzc5MyAxMi44MDUgNC4wMDMxMSAxMy4wNTU4IDQuMjI1NzggMTMuMjg1QzQuNDQ5NDIgMTMuNTE1MyA0LjcwODE4IDEzLjY5MiA1LjAwMTI4IDEzLjgxNTNDNS4yOTQwNyAxMy45Mzg0IDUuNTk3NDMgMTQgNS45MTA4MyAxNEg2VjEzLjJWMTMuMDE2NEg1LjkxMDgzQzUuNzEwOTUgMTMuMDE2NCA1LjUyMzQ2IDEyLjk3NzcgNS4zNDc2MyAxMi45MDA4QzUuMTczOTYgMTIuODE5MSA1LjAyMTk0IDEyLjcxMjYgNC44OTA4NiAxMi41ODE4QzQuNzYzODYgMTIuNDQ2OSA0LjY2MTA0IDEyLjI5MTEgNC41ODIyMyAxMi4xMTM3QzQuNTA4MzggMTEuOTM0NiA0LjQ3MTM0IDExLjc0NCA0LjQ3MTM0IDExLjU0MUM0LjQ3MTM0IDExLjMxMjcgNC40NzUzIDExLjA4ODUgNC40ODMyMSAxMC44Njg2QzQuNDkxMjUgMTAuNjQxMSA0LjQ5MTI3IDEwLjQxOTUgNC40ODMyNCAxMC4yMDM5QzQuNDc5MTQgOS45ODI0NiA0LjQ2MDg0IDkuNzY4ODMgNC40MjgyMyA5LjU2MzEyQzQuMzk1MTMgOS4zNTAyNCA0LjMzOTIxIDkuMTQ3NTcgNC4yNjAzOSA4Ljk1NTM2QzQuMTgwOTEgOC43NjE1NyA0LjA3MjU4IDguNTc3NDYgMy45MzYxNiA4LjQwMjk4QzMuODIzNDUgOC4yNTg4MSAzLjY4NTM4IDguMTI0NjIgMy41MjI4MyA4QzMuNjg1MzggNy44NzUzOCAzLjgyMzQ1IDcuNzQxMTkgMy45MzYxNiA3LjU5NzAyQzQuMDcyNTggNy40MjI1NCA0LjE4MDkxIDcuMjM4NDMgNC4yNjAzOSA3LjA0NDY0QzQuMzM5MTMgNi44NTI2MyA0LjM5NTEzIDYuNjUxNzUgNC40MjgyNiA2LjQ0Mjg1QzQuNDYwODIgNi4yMzMzIDQuNDc5MTQgNi4wMTk3MyA0LjQ4MzI0IDUuODAyMTlDNC40OTEyNyA1LjU4MjYyIDQuNDkxMjUgNS4zNjEwNSA0LjQ4MzIxIDUuMTM3NDlDNC40NzUzIDQuOTEzNCA0LjQ3MTM0IDQuNjg3MjUgNC40NzEzNCA0LjQ1OTAyQzQuNDcxMzQgNC4yNjAxOSA0LjUwODMzIDQuMDcxNTIgNC41ODIzOCAzLjg5MjA1QzQuNjYxMzUgMy43MTAzNCA0Ljc2NDIxIDMuNTU0NzUgNC44OTA4NiAzLjQyNDM3QzUuMDIxOTMgMy4yODk0MiA1LjE3NDYxIDMuMTgyNzUgNS4zNDgwMiAzLjEwNTEzQzUuNTIzOCAzLjAyNDI3IDUuNzExMTMgMi45ODM2MSA1LjkxMDgzIDIuOTgzNjFINlpNMTAgMTMuMDE2NFYxMy4wMjgyVjE0SDEwLjA4OTJDMTAuNDAyNiAxNCAxMC43MDU5IDEzLjkzODQgMTAuOTk4NyAxMy44MTUzQzExLjI5MTggMTMuNjkyIDExLjU1MDYgMTMuNTE1MyAxMS43NzQyIDEzLjI4NUMxMS45OTY5IDEzLjA1NTggMTIuMTYyMSAxMi44MDUgMTIuMjY3MiAxMi41MzIzTDEyLjI2NzcgMTIuNTMxQzEyLjM2NjIgMTIuMjY0OCAxMi40MzE5IDExLjk4OCAxMi40NjQ3IDExLjcwMDhMMTIuNDY0OCAxMS42OTk1QzEyLjQ5MzIgMTEuNDE5NSAxMi41MDEzIDExLjEzMTYgMTIuNDg5MiAxMC44MzU3QzEyLjQ3NzMgMTAuNTQ2MiAxMi40NzEzIDEwLjI1NjcgMTIuNDcxMyA5Ljk2NzIxQzEyLjQ3MTMgOS43NjQ0NCAxMi41MTAzIDkuNTc0MDYgMTIuNTg4IDkuMzk0OTNMMTIuNTg4NCA5LjM5Mzk5QzEyLjY2MzEgOS4yMTcwNCAxMi43NjU4IDkuMDYxMzQgMTIuODk2OCA4LjkyNjQyQzEzLjAyMzYgOC43OTU5NSAxMy4xNzUzIDguNjg5NDUgMTMuMzUzMyA4LjYwNzVDMTMuNTI5NCA4LjUzMDQ2IDEzLjcxNSA4LjQ5MTggMTMuOTEwOCA4LjQ5MThIMTRWOC40VjcuNlY3LjUwODJIMTMuOTEwOEMxMy43MTUzIDcuNTA4MiAxMy41MyA3LjQ2NzYyIDEzLjM1NCA3LjM4NjY2TDEzLjM1MjYgNy4zODYwNEMxMy4xNzU0IDcuMzA4NDQgMTMuMDI0MiA3LjIwMjM4IDEyLjg5NzggNy4wNjgzOUwxMi44OTU5IDcuMDY2NDhDMTIuNzY1NyA2LjkzNjMgMTIuNjYzNCA2Ljc4MTI5IDEyLjU4ODcgNi42MDA1OEwxMi41ODggNi41OTg5MkMxMi41MTAxIDYuNDE5NTMgMTIuNDcxMyA2LjIzMTE3IDEyLjQ3MTMgNi4wMzI3OUMxMi40NzEzIDUuNzQzMjkgMTIuNDc3MyA1LjQ1Mzc5IDEyLjQ4OTIgNS4xNjQyOEMxMi41MDEzIDQuODY4NDIgMTIuNDkzMiA0LjU3ODQ4IDEyLjQ2NDggNC4yOTQ1NEwxMi40NjQ2IDQuMjkyODVDMTIuNDMxOCA0LjAwOTcxIDEyLjM2NjEgMy43MzUwMiAxMi4yNjc3IDMuNDY4OTdMMTIuMjY3MiAzLjQ2NzY2QzEyLjE2MjEgMy4xOTQ5OSAxMS45OTY5IDIuOTQ0MjIgMTEuNzc0MiAyLjcxNDk4QzExLjU1MDYgMi40ODQ3NCAxMS4yOTE4IDIuMzA3OTggMTAuOTk4NyAyLjE4NDczQzEwLjcwNTkgMi4wNjE2MSAxMC40MDI2IDIgMTAuMDg5MiAySDEwVjIuOFYyLjk4MzYxSDEwLjA4OTJDMTAuMjg5MSAyLjk4MzYxIDEwLjQ3NjUgMy4wMjIzIDEwLjY1MjQgMy4wOTkxN0MxMC44MjYgMy4xODA5MiAxMC45NzgxIDMuMjg3MzYgMTEuMTA5MSAzLjQxODIzQzExLjIzNjEgMy41NTMwNSAxMS4zMzkgMy43MDg4OSAxMS40MTc4IDMuODg2MjhDMTEuNDkxNiA0LjA2NTQgMTEuNTI4NyA0LjI1NTk2IDExLjUyODcgNC40NTkwMkMxMS41Mjg3IDQuNjg3MjcgMTEuNTI0NyA0LjkxMTQ1IDExLjUxNjggNS4xMzE0MkMxMS41MDg4IDUuMzU4OTQgMTEuNTA4NyA1LjU4MDQ5IDExLjUxNjggNS43OTYwNUMxMS41MjA5IDYuMDE3NTQgMTEuNTM5MiA2LjIzMTE3IDExLjU3MTggNi40MzY4OEMxMS42MDQ5IDYuNjQ5NzYgMTEuNjYwOCA2Ljg1MjQzIDExLjczOTYgNy4wNDQ2NEMxMS44MTkxIDcuMjM4NDMgMTEuOTI3NCA3LjQyMjU0IDEyLjA2MzggNy41OTcwMkMxMi4xNzY1IDcuNzQxMTkgMTIuMzE0NiA3Ljg3NTM4IDEyLjQ3NzIgOEMxMi4zMTQ2IDguMTI0NjIgMTIuMTc2NSA4LjI1ODgxIDEyLjA2MzggOC40MDI5OEMxMS45Mjc0IDguNTc3NDYgMTEuODE5MSA4Ljc2MTU3IDExLjczOTYgOC45NTUzNkMxMS42NjA5IDkuMTQ3MzcgMTEuNjA0OSA5LjM0ODI1IDExLjU3MTcgOS41NTcxNUMxMS41MzkyIDkuNzY2NyAxMS41MjA5IDkuOTgwMjcgMTEuNTE2OCAxMC4xOTc4QzExLjUwODcgMTAuNDE3NCAxMS41MDg3IDEwLjYzODkgMTEuNTE2OCAxMC44NjI1QzExLjUyNDcgMTEuMDg2NiAxMS41Mjg3IDExLjMxMjggMTEuNTI4NyAxMS41NDFDMTEuNTI4NyAxMS43Mzk4IDExLjQ5MTcgMTEuOTI4NSAxMS40MTc2IDEyLjEwNzlDMTEuMzM4NiAxMi4yODk3IDExLjIzNTggMTIuNDQ1MiAxMS4xMDkxIDEyLjU3NTZDMTAuOTc4MSAxMi43MTA2IDEwLjgyNTQgMTIuODE3MyAxMC42NTIgMTIuODk0OUMxMC40NzYyIDEyLjk3NTcgMTAuMjg4OSAxMy4wMTY0IDEwLjA4OTIgMTMuMDE2NEgxMFoiIGZpbGw9IiNDNUM1QzUiLz4KPC9zdmc+Cg=="); } .hc-black .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.property:before { - content: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBhdGggZmlsbD0iI0M1QzVDNSIgZD0iTTEyLjA5IDQuMzU5bC0yLjY0MSAyLjY0MS0yLTIgMi42NDEtMi42NDFjLS41MDItLjIyNi0xLjA1NS0uMzU5LTEuNjQxLS4zNTktMi4yMDkgMC00IDEuNzkxLTQgNCAwIC41ODYuMTMzIDEuMTM5LjM1OSAxLjY0bC0zLjM1OSAzLjM2cy0xIDEgMCAyaDJsMy4zNTktMy4zNmMuNTAzLjIyNiAxLjA1NS4zNiAxLjY0MS4zNiAyLjIwOSAwIDQtMS43OTEgNC00IDAtLjU4Ni0uMTMzLTEuMTM5LS4zNTktMS42NDF6Ii8+PC9zdmc+"); - margin-left: 1px; + content: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTIuODA3MjMgMTQuOTc1NEMyLjU3MTE5IDE0Ljk3MjEgMi4zMzgyNiAxNC45MjExIDIuMTIyNDcgMTQuODI1NEMxLjkwNjY3IDE0LjcyOTcgMS43MTI0OCAxNC41OTEzIDEuNTUxNTggMTQuNDE4NkMxLjIzODUgMTQuMTMzNCAxLjA0NDMzIDEzLjc0MDggMS4wMDc3NSAxMy4zMTg5QzAuOTY2MjI1IDEyLjg4MjggMS4wOTI2OSAxMi40NDczIDEuMzYxMzMgMTIuMTAxM0MyLjU2Nzc5IDEwLjgyODkgNC45NDczIDguNDQ5NCA2LjY3ODExIDYuNzU0NzlDNi4zMDk4MyA1Ljc1ODg3IDYuMzI3MDQgNC42NjEyNyA2LjcyNjM3IDMuNjc3MzlDNy4wNTQ3NCAyLjg1ODc2IDcuNjM4NjkgMi4xNjgwNSA4LjM5MTI5IDEuNzA4MDdDOC45ODE3IDEuMzE3MDYgOS42NjAzMSAxLjA3OTQ0IDEwLjM2NTcgMS4wMTY3M0MxMS4wNzExIDAuOTU0MDIyIDExLjc4MDkgMS4wNjgxOSAxMi40MzExIDEuMzQ4OTJMMTMuMDQ4MiAxLjYxNjJMMTAuMTgyNCA0LjU2NzM4TDExLjQzNzEgNS44MjU4MkwxNC4zODA5IDIuOTQ4ODdMMTQuNjQ4MiAzLjU2Nzg4QzE0Ljg3MzUgNC4wODk3NiAxNC45OTMgNC42NTExOSAxNC45OTk3IDUuMjE5NjFDMTUuMDA2NCA1Ljc4ODAyIDE0LjkwMDIgNi4zNTIxMSAxNC42ODcyIDYuODc5MTVDMTQuNDc2IDcuNDAwMjkgMTQuMTYyMyA3Ljg3MzY4IDEzLjc2NDcgOC4yNzEyMkMxMy41Mzk0IDguNDkxNjkgMTMuMjkwNCA4LjY4NjUzIDEzLjAyMjIgOC44NTIxOEMxMi40NjczIDkuMjIyNzUgMTEuODMyNCA5LjQ1NjM2IDExLjE2OTcgOS41MzM4QzEwLjUwNjkgOS42MTEyNCA5LjgzNTIxIDkuNTMwMyA5LjIwOTgyIDkuMjk3NjRDOC4xMTE5NCAxMC40MTEzIDUuMzcxNDIgMTMuMTcwNCAzLjg5MTE5IDE0LjU1MjJDMy41OTQyNiAxNC44MjE5IDMuMjA4MzIgMTQuOTcyNiAyLjgwNzIzIDE0Ljk3NTRaTTEwLjc0NDggMS45MjgwMkMxMC4wODcgMS45MjYzNyA5LjQ0MzU5IDIuMTIwMTggOC44OTYxNCAyLjQ4NDg1QzguNjgyNjUgMi42MTUyIDguNDg0MzcgMi43Njg5NyA4LjMwNDk4IDIuOTQzM0M3LjgyNzg5IDMuNDI0MjMgNy41MDkyNiA0LjAzOTUzIDcuMzkxODIgNC43MDY2OUM3LjI3NDM4IDUuMzczODUgNy4zNjM3NCA2LjA2MDk4IDcuNjQ3OTIgNi42NzU5MUw3Ljc4MzQyIDYuOTcyODhMNy41NTA0OCA3LjIwMDI1QzUuODEyMjQgOC44OTY3MiAzLjI4MTQ2IDExLjQyMDEgMi4wNjQ3OSAxMi43MDQ1QzEuOTU2NDYgMTIuODY1OCAxLjkxMDEyIDEzLjA2MDggMS45MzQzNSAxMy4yNTM1QzEuOTU4NTcgMTMuNDQ2MyAyLjA1MTcxIDEzLjYyMzggMi4xOTY1NyAxMy43NTMyQzIuMjgwMDUgMTMuODQ2MiAyLjM4MTc3IDEzLjkyMTEgMi40OTU0MSAxMy45NzMxQzIuNTk1NTcgMTQuMDE4NCAyLjcwMzgzIDE0LjA0MyAyLjgxMzczIDE0LjA0NTVDMi45ODA2NCAxNC4wNDEzIDMuMTQwNDQgMTMuOTc3IDMuMjYzODMgMTMuODY0NkM0LjgzNjg3IDEyLjM5NjQgNy44NzYyMiA5LjMyNjQxIDguNzY4MDcgOC40MjQzNUw4Ljk5NzMgOC4xOTMyNkw5LjI5MjQyIDguMzI3ODNDOS44MDYxNyA4LjU2NzMyIDEwLjM3MzEgOC42Njk4NSAxMC45MzgyIDguNjI1NDVDMTEuNTAzMyA4LjU4MTA2IDEyLjA0NzMgOC4zOTEyNSAxMi41MTc0IDguMDc0NDdDMTIuNzMxMyA3Ljk0MjYgMTIuOTI5NiA3Ljc4Njk0IDEzLjEwODUgNy42MTA0NUMxMy40MTgzIDcuMzAxNTMgMTMuNjYzMSA2LjkzMzc0IDEzLjgyODYgNi41Mjg3NEMxMy45OTQgNi4xMjM3NSAxNC4wNzY3IDUuNjg5NzQgMTQuMDcxOSA1LjI1MjI4QzE0LjA3MTkgNS4wMzY2MiAxNC4wNTA1IDQuODIxNDggMTQuMDA3OCA0LjYxMDA3TDExLjQzMDYgNy4xMjUwOEw4Ljg3OTQ0IDQuNTc3NTlMMTEuMzk0NCAxLjk4ODM0QzExLjE4MDQgMS45NDY3NCAxMC45NjI4IDEuOTI2NTMgMTAuNzQ0OCAxLjkyODAyWiIgZmlsbD0iI0M1QzVDNSIvPgo8L3N2Zz4K"); } .hc-black .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.value:before, .hc-black .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.enum:before { - content: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PGcgZmlsbD0iIzc1QkVGRiI+PHBhdGggZD0iTTEyIDNoLTRsLTEgMXYyaDV2MWgtMnYxaDJsMS0xdi0zbC0xLTF6bTAgMmgtNHYtMWg0djF6TTMgMTJoNnYtNWgtNnY1em0xLTNoNHYxaC00di0xeiIvPjwvZz48L3N2Zz4="); + content: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik04IDJMNyAzVjZIOFYzSDE0VjhIMTBWOUgxNEwxNSA4VjNMMTQgMkg4Wk05IDhMOCA3SDdIMkwxIDhWMTNMMiAxNEg4TDkgMTNWOVY4Wk04IDlWOEg3SDJWMTNIOFY5Wk05IDYuNTg1NzlMOS40MTQyMSA3SDEzVjZIOVY2LjU4NTc5Wk0xMyA0SDlWNUgxM1Y0Wk03IDlIM1YxMEg3VjlaTTMgMTFIN1YxMkgzVjExWiIgZmlsbD0iI0VFOUQyOCIvPgo8L3N2Zz4K"); } .hc-black .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.rule:before { - content: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxMiI+PHBhdGggZmlsbD0iI0M1QzVDNSIgZD0iTTEwIDVoLTh2LTJoOHYyem0wIDFoLTZ2MWg2di0xem0wIDJoLTZ2MWg2di0xeiIvPjwvc3ZnPg=="); + content: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik00IDFMMyAyVjE0TDQgMTVIMTJMMTMgMTRWMkwxMiAxSDRaTTQgM1YySDEyVjE0SDRWMTNINlYxMkg0VjEwSDhWOUg0VjdINlY2SDRWNEg4VjNINFoiIGZpbGw9IiNDNUM1QzUiLz4KPC9zdmc+Cg=="); } .hc-black .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.file:before { - content: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBhdGggZmlsbD0iI0M1QzVDNSIgZD0iTTkuNjc2IDJoLTYuNjc2djEyaDEwdi05bC0zLjMyNC0zem0yLjMyNCAxMWgtOHYtMTBoNXYzaDN2N3oiLz48L3N2Zz4="); -} \ No newline at end of file + content: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik00IDFMMyAyVjE0TDQgMTVIMTNMMTQgMTRWNUwxMy43MDcxIDQuMjkyODlMMTAuNzA3MSAxLjI5Mjg5TDEwIDFINFpNNCAxNFYyTDkgMlY2SDEzVjE0SDRaTTEzIDVMMTAgMlY1TDEzIDVaIiBmaWxsPSIjQzVDNUM1Ii8+Cjwvc3ZnPgo="); +} + +.hc-black .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.string:before { + content: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik03LjIyMjg5IDEwLjkzM0M3LjU0ODYzIDExLjEyNTQgNy45MjE2MyAxMS4yMjMxIDguMjk5ODkgMTEuMjE1QzguNjM3NzcgMTEuMjIxOCA4Ljk3MjU0IDExLjE0OTIgOS4yNzcyMSAxMS4wMDNDOS41ODE4OCAxMC44NTY3IDkuODQ3OTIgMTAuNjQwOSAxMC4wNTM5IDEwLjM3M0MxMC41MDkxIDkuNzY1MTkgMTAuNzQwMiA5LjAxODY3IDEwLjcwNzkgOC4yNTk5OEMxMC43NDEyIDcuNTg2MjIgMTAuNTM3NCA2LjkyMjEgMTAuMTMxOSA2LjM4Mjk4QzkuOTM1NzUgNi4xNDE2MSA5LjY4NTc3IDUuOTQ5NTcgOS40MDIgNS44MjIyOEM5LjExODI0IDUuNjk0OTggOC44MDg1OCA1LjYzNTk3IDguNDk3ODkgNS42NDk5N0M4LjA3NTIyIDUuNjQ2OTkgNy42NTk5NCA1Ljc2MDg1IDcuMjk3ODkgNS45Nzg5OEM3LjE4MzA0IDYuMDQ4MDcgNy4wNzQ5IDYuMTI3NzUgNi45NzQ4OSA2LjIxNjk4VjMuNDc0OThINS45ODM4OVYxMS4xSDYuOTc4ODlWMTAuNzU2QzcuMDU1MTYgMTAuODIxNyA3LjEzNjc3IDEwLjg4MDkgNy4yMjI4OSAxMC45MzNaTTcuODQ5ODEgNi43MDAwNkM4LjAzNTk4IDYuNjIxMDUgOC4yMzgwNyA2LjU4Njc3IDguNDM5ODkgNi41OTk5OEM4LjYxMjU3IDYuNTk0NTIgOC43ODQwNCA2LjYzMDU0IDguOTM5OTQgNi43MDUwMUM5LjA5NTgzIDYuNzc5NDggOS4yMzE2MSA2Ljg5MDIzIDkuMzM1ODkgNy4wMjc5OEM5LjU5MjUzIDcuMzkwNTMgOS43MTg0IDcuODI5NTEgOS42OTI4OSA4LjI3Mjk3QzkuNzE5NzIgOC43OTc0OCA5LjU3OTY5IDkuMzE3MDEgOS4yOTI4OSA5Ljc1Njk4QzkuMTg4MjIgOS45MTUyNyA5LjA0NTQ2IDEwLjA0NDcgOC44Nzc3MyAxMC4xMzM1QzguNzA5OTkgMTAuMjIyMyA4LjUyMjY0IDEwLjI2NzUgOC4zMzI4OSAxMC4yNjVDOC4xNDkzNCAxMC4yNzMyIDcuOTY2MyAxMC4yNCA3Ljc5NzM0IDEwLjE2NzhDNy42MjgzOCAxMC4wOTU2IDcuNDc3ODQgOS45ODYyOCA3LjM1Njg5IDkuODQ3OTdDNy4xMDE1MiA5LjU1OTU3IDYuOTY1MDEgOS4xODUwNiA2Ljk3NDg5IDguNzk5OThWOC4xOTk5OEM2Ljk2Mjk5IDcuNzgzMzIgNy4xMDI2MyA3LjM3NjUgNy4zNjc4OSA3LjA1NDk4QzcuNDk4NTggNi45MDA2NCA3LjY2MzY0IDYuNzc5MDggNy44NDk4MSA2LjcwMDA2Wk0zLjI4OTAyIDUuNjc0OTlDMi45NzAxMSA1LjY3OTMzIDIuNjUzODggNS43MzQgMi4zNTIwMiA1LjgzNjk5QzIuMDY0MTcgNS45MjI5MyAxLjc5MzQ3IDYuMDU4MjggMS41NTIwMiA2LjIzNjk5TDEuNDUyMDIgNi4zMTM5OVY3LjUxMzk5TDEuODc1MDIgNy4xNTQ5OUMyLjI0NTc5IDYuODA0NzggMi43MzEzMyA2LjYwMTQ2IDMuMjQxMDIgNi41ODI5OUMzLjM2NTkzIDYuNTcxNjQgMy40OTE3IDYuNTkxNDcgMy42MDcwNiA2LjY0MDY4QzMuNzIyNDMgNi42ODk5IDMuODIzNzcgNi43NjY5NyAzLjkwMjAyIDYuODY0OTlDNC4wNTIyIDcuMDk3MSA0LjEzMjM5IDcuMzY3NTQgNC4xMzMwMiA3LjY0Mzk5TDIuOTAwMDIgNy44MjQ5OUMyLjM5NDM1IDcuODc3ODEgMS45MTUyNSA4LjA3NzcyIDEuNTIyMDIgOC4zOTk5OUMxLjM2Njk3IDguNTUxODEgMS4yNDMzOSA4LjczMjcxIDEuMTU4MzUgOC45MzIzNUMxLjA3MzMxIDkuMTMxOTkgMS4wMjg0OCA5LjM0NjQ0IDEuMDI2NDQgOS41NjM0M0MxLjAyNDQgOS43ODA0MiAxLjA2NTE3IDkuOTk1NjggMS4xNDY0NCAxMC4xOTY5QzEuMjI3NyAxMC4zOTgxIDEuMzQ3ODYgMTAuNTgxMyAxLjUwMDAyIDEwLjczNkMxLjY2ODcgMTAuODkwNCAxLjg2NjIyIDExLjAxIDIuMDgxMjUgMTEuMDg3OUMyLjI5NjI3IDExLjE2NTkgMi41MjQ1NiAxMS4yMDA1IDIuNzUzMDIgMTEuMTlDMy4xNDcgMTEuMTkzMSAzLjUzMjc4IDExLjA3NzQgMy44NjAwMiAxMC44NThDMy45NjE1MyAxMC43ODk3IDQuMDU3MiAxMC43MTMxIDQuMTQ2MDIgMTAuNjI5VjExLjA3M0g1LjA4NzAyVjcuNzE0OTlDNS4xMjEzNyA3LjE3NDIyIDQuOTU0MyA2LjYzOTg4IDQuNjE4MDIgNi4yMTQ5OUM0LjQ0OTc5IDYuMDMyODUgNC4yNDM0OCA1Ljg5MDAzIDQuMDEzNzggNS43OTY3QzMuNzg0MDcgNS43MDMzNiAzLjUzNjYxIDUuNjYxODEgMy4yODkwMiA1LjY3NDk5Wk00LjE0NjAyIDguNzE1OTlDNC4xNjU2NCA5LjEzNDM1IDQuMDI1OTIgOS41NDQ1OSAzLjc1NTAyIDkuODY0QzMuNjM2ODkgMTAuMDAwNSAzLjQ4OTk4IDEwLjEwOTIgMy4zMjQ4NiAxMC4xODIxQzMuMTU5NzMgMTAuMjU1MSAyLjk4MDQ5IDEwLjI5MDYgMi44MDAwMiAxMC4yODZDMi42OTA0OSAxMC4yOTQ1IDIuNTgwMzUgMTAuMjgxMiAyLjQ3NTk5IDEwLjI0NjlDMi4zNzE2MyAxMC4yMTI1IDIuMjc1MTEgMTAuMTU3OSAyLjE5MjAyIDEwLjA4NkMyLjA2MDc5IDkuOTM0NTUgMS45ODg1NiA5Ljc0MDg4IDEuOTg4NTYgOS41NDA0OUMxLjk4ODU2IDkuMzQwMTEgMi4wNjA3OSA5LjE0NjQ0IDIuMTkyMDIgOC45OTQ5OUMyLjQ3MzIyIDguODIxMzEgMi43OTIzMyA4LjcxODM3IDMuMTIyMDIgOC42OTQ5OUw0LjE0MjAyIDguNTQ2OTlMNC4xNDYwMiA4LjcxNTk5Wk0xMi40NTg4IDExLjAzMjVDMTIuNzY2IDExLjE2MzggMTMuMDk4MyAxMS4yMjYxIDEzLjQzMjIgMTEuMjE1QzEzLjkyNyAxMS4yMjcgMTQuNDE1MyAxMS4xMDA2IDE0Ljg0MjIgMTAuODVMMTQuOTY1MiAxMC43NzVMMTQuOTc4MiAxMC43NjhWOS42MTUwNEwxNC41MzIyIDkuOTM1MDRDMTQuMjE2IDEwLjE1OTIgMTMuODM1NiAxMC4yNzQ3IDEzLjQ0ODIgMTAuMjY0QzEzLjI0OTcgMTAuMjcxOSAxMy4wNTIgMTAuMjM0MiAxMi44NzAzIDEwLjE1MzhDMTIuNjg4NiAxMC4wNzMzIDEyLjUyNzggOS45NTIzMiAxMi40MDAyIDkuODAwMDRDMTIuMTE0NCA5LjQyNDUzIDExLjk3MjUgOC45NTkxMSAxMi4wMDAyIDguNDg4MDRDMTEuOTczNyA3Ljk4NzMyIDEyLjEzNTIgNy40OTQ3NSAxMi40NTMyIDcuMTA3MDRDMTIuNTkzNCA2Ljk0MTA1IDEyLjc2OTUgNi44MDkxNCAxMi45NjgyIDYuNzIxM0MxMy4xNjcgNi42MzM0NiAxMy4zODMxIDYuNTkyIDEzLjYwMDIgNi42MDAwNEMxMy45NDM5IDYuNTk4NDQgMTQuMjgwOCA2LjY5NTI1IDE0LjU3MTIgNi44NzkwNEwxNS4wMDAyIDcuMTQ0MDRWNS45NzAwNEwxNC44MzEyIDUuODk3MDRDMTQuNDYyNiA1LjczNDMyIDE0LjA2NDEgNS42NTAyIDEzLjY2MTIgNS42NTAwNEMxMy4yOTk5IDUuNjM5OTEgMTIuOTQwNiA1LjcwNzYyIDEyLjYwNzggNS44NDg1OUMxMi4yNzQ5IDUuOTg5NTYgMTEuOTc2MyA2LjIwMDQ4IDExLjczMjIgNi40NjcwNEMxMS4yMjYxIDcuMDI2ODMgMTAuOTU4MSA3Ljc2MTg2IDEwLjk4NTIgOC41MTYwNEMxMC45NTY3IDkuMjIzNDYgMTEuMTk1NSA5LjkxNTY5IDExLjY1NDIgMTAuNDU1QzExLjg3NjkgMTAuNzA0IDEyLjE1MTYgMTAuOTAxMiAxMi40NTg4IDExLjAzMjVaIiBmaWxsPSIjQzVDNUM1Ii8+Cjwvc3ZnPgo="); +} diff --git a/src/vs/editor/standalone/browser/quickOpen/quickOutline.ts b/src/vs/editor/standalone/browser/quickOpen/quickOutline.ts index 92cc30a7b..eeeaf6f32 100644 --- a/src/vs/editor/standalone/browser/quickOpen/quickOutline.ts +++ b/src/vs/editor/standalone/browser/quickOpen/quickOutline.ts @@ -26,12 +26,12 @@ let SCOPE_PREFIX = ':'; export class SymbolEntry extends QuickOpenEntryGroup { private readonly name: string; private readonly type: string; - private readonly description: string | null; + private readonly description: string | undefined; private readonly range: Range; private readonly editor: ICodeEditor; private readonly decorator: IDecorator; - constructor(name: string, type: string, description: string | null, range: Range, highlights: IHighlight[], editor: ICodeEditor, decorator: IDecorator) { + constructor(name: string, type: string, description: string | undefined, range: Range, highlights: IHighlight[], editor: ICodeEditor, decorator: IDecorator) { super(); this.name = name; @@ -55,7 +55,7 @@ export class SymbolEntry extends QuickOpenEntryGroup { return this.type; } - public getDescription(): string | null { + public getDescription(): string | undefined { return this.description; } @@ -169,7 +169,7 @@ export class QuickOutlineAction extends BaseEditorQuickOpenAction { }); } - private symbolEntry(name: string, type: string, description: string | null, range: IRange, highlights: IHighlight[], editor: ICodeEditor, decorator: IDecorator): SymbolEntry { + private symbolEntry(name: string, type: string, description: string | undefined, range: IRange, highlights: IHighlight[], editor: ICodeEditor, decorator: IDecorator): SymbolEntry { return new SymbolEntry(name, type, description, Range.lift(range), highlights, editor, decorator); } @@ -192,7 +192,7 @@ export class QuickOutlineAction extends BaseEditorQuickOpenAction { if (highlights) { // Show parent scope as description - let description: string | null = null; + let description: string | undefined = undefined; if (element.containerName) { description = element.containerName; } diff --git a/src/vs/editor/standalone/browser/quickOpen/symbol-sprite.svg b/src/vs/editor/standalone/browser/quickOpen/symbol-sprite.svg index d2b2038b1..62449987c 100644 --- a/src/vs/editor/standalone/browser/quickOpen/symbol-sprite.svg +++ b/src/vs/editor/standalone/browser/quickOpen/symbol-sprite.svg @@ -1 +1,26 @@ - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/vs/editor/standalone/browser/simpleServices.ts b/src/vs/editor/standalone/browser/simpleServices.ts index b6468cddf..d333ce037 100644 --- a/src/vs/editor/standalone/browser/simpleServices.ts +++ b/src/vs/editor/standalone/browser/simpleServices.ts @@ -8,7 +8,7 @@ import * as dom from 'vs/base/browser/dom'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { Emitter, Event } from 'vs/base/common/event'; import { Keybinding, ResolvedKeybinding, SimpleKeybinding, createKeybinding } from 'vs/base/common/keyCodes'; -import { IDisposable, IReference, ImmortalReference, combinedDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, IReference, ImmortalReference, toDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle'; import { OS, isLinux, isMacintosh } from 'vs/base/common/platform'; import Severity from 'vs/base/common/severity'; import { URI } from 'vs/base/common/uri'; @@ -19,13 +19,13 @@ import { EditOperation } from 'vs/editor/common/core/editOperation'; import { IPosition, Position as Pos } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import * as editorCommon from 'vs/editor/common/editorCommon'; -import { ITextModel } from 'vs/editor/common/model'; +import { ITextModel, ITextSnapshot } from 'vs/editor/common/model'; import { TextEdit, WorkspaceEdit, isResourceTextEdit } from 'vs/editor/common/modes'; import { IModelService } from 'vs/editor/common/services/modelService'; import { IResolvedTextEditorModel, ITextModelContentProvider, ITextModelService } from 'vs/editor/common/services/resolverService'; import { ITextResourceConfigurationService, ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration'; import { CommandsRegistry, ICommand, ICommandEvent, ICommandHandler, ICommandService } from 'vs/platform/commands/common/commands'; -import { IConfigurationChangeEvent, IConfigurationData, IConfigurationOverrides, IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationChangeEvent, IConfigurationData, IConfigurationOverrides, IConfigurationService, IConfigurationModel } from 'vs/platform/configuration/common/configuration'; import { Configuration, ConfigurationModel, DefaultConfigurationModel } from 'vs/platform/configuration/common/configurationModels'; import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IConfirmation, IConfirmationResult, IDialogOptions, IDialogService } from 'vs/platform/dialogs/common/dialogs'; @@ -37,13 +37,14 @@ import { IKeybindingItem, KeybindingsRegistry } from 'vs/platform/keybinding/com import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; import { USLayoutResolvedKeybinding } from 'vs/platform/keybinding/common/usLayoutResolvedKeybinding'; import { ILabelService, ResourceLabelFormatter } from 'vs/platform/label/common/label'; -import { INotification, INotificationHandle, INotificationService, IPromptChoice, IPromptOptions, NoOpNotification } from 'vs/platform/notification/common/notification'; -import { IProgressRunner, IProgressService } from 'vs/platform/progress/common/progress'; +import { INotification, INotificationHandle, INotificationService, IPromptChoice, IPromptOptions, NoOpNotification, IStatusMessageOptions } from 'vs/platform/notification/common/notification'; +import { IProgressRunner, IEditorProgressService } from 'vs/platform/progress/common/progress'; import { ITelemetryInfo, ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IWorkspace, IWorkspaceContextService, IWorkspaceFolder, IWorkspaceFoldersChangeEvent, WorkbenchState, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { ILayoutService, IDimension } from 'vs/platform/layout/browser/layoutService'; import { SimpleServicesNLS } from 'vs/editor/common/standaloneStrings'; +import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings'; export class SimpleModel implements IResolvedTextEditorModel { @@ -67,6 +68,10 @@ export class SimpleModel implements IResolvedTextEditorModel { return this.model; } + public createSnapshot(): ITextSnapshot { + return this.model.createSnapshot(); + } + public isReadonly(): boolean { return false; } @@ -132,7 +137,7 @@ export class SimpleEditorModelResolverService implements ITextModelService { } } -export class SimpleProgressService implements IProgressService { +export class SimpleEditorProgressService implements IEditorProgressService { _serviceBrand: any; private static NULL_PROGRESS_RUNNER: IProgressRunner = { @@ -144,7 +149,7 @@ export class SimpleProgressService implements IProgressService { show(infinite: true, delay?: number): IProgressRunner; show(total: number, delay?: number): IProgressRunner; show(): IProgressRunner { - return SimpleProgressService.NULL_PROGRESS_RUNNER; + return SimpleEditorProgressService.NULL_PROGRESS_RUNNER; } showWhile(promise: Promise, delay?: number): Promise { @@ -216,6 +221,10 @@ export class SimpleNotificationService implements INotificationService { public prompt(severity: Severity, message: string, choices: IPromptChoice[], options?: IPromptOptions): INotificationHandle { return SimpleNotificationService.NO_OP; } + + public status(message: string | Error, options?: IStatusMessageOptions): IDisposable { + return Disposable.None; + } } export class StandaloneCommandService implements ICommandService { @@ -225,7 +234,9 @@ export class StandaloneCommandService implements ICommandService { private readonly _dynamicCommands: { [id: string]: ICommand; }; private readonly _onWillExecuteCommand = new Emitter(); + private readonly _onDidExecuteCommand = new Emitter(); public readonly onWillExecuteCommand: Event = this._onWillExecuteCommand.event; + public readonly onDidExecuteCommand: Event = this._onDidExecuteCommand.event; constructor(instantiationService: IInstantiationService) { this._instantiationService = instantiationService; @@ -247,8 +258,10 @@ export class StandaloneCommandService implements ICommandService { } try { - this._onWillExecuteCommand.fire({ commandId: id }); + this._onWillExecuteCommand.fire({ commandId: id, args }); const result = this._instantiationService.invokeFunction.apply(this._instantiationService, [command.handler, ...args]) as T; + + this._onDidExecuteCommand.fire({ commandId: id, args }); return Promise.resolve(result); } catch (err) { return Promise.reject(err); @@ -287,7 +300,7 @@ export class StandaloneKeybindingService extends AbstractKeybindingService { throw new Error(`Invalid keybinding`); } - let toDispose: IDisposable[] = []; + const toDispose = new DisposableStore(); this._dynamicKeybindings.push({ keybinding: keybinding, @@ -297,7 +310,7 @@ export class StandaloneKeybindingService extends AbstractKeybindingService { weight2: 0 }); - toDispose.push(toDisposable(() => { + toDispose.add(toDisposable(() => { for (let i = 0; i < this._dynamicKeybindings.length; i++) { let kb = this._dynamicKeybindings[i]; if (kb.command === commandId) { @@ -310,7 +323,7 @@ export class StandaloneKeybindingService extends AbstractKeybindingService { let commandService = this._commandService; if (commandService instanceof StandaloneCommandService) { - toDispose.push(commandService.addCommand({ + toDispose.add(commandService.addCommand({ id: commandId, handler: handler })); @@ -319,7 +332,7 @@ export class StandaloneKeybindingService extends AbstractKeybindingService { } this.updateResolver({ source: KeybindingSource.Default }); - return combinedDisposable(toDispose); + return toDispose; } private updateResolver(event: IKeybindingEvent): void { @@ -343,12 +356,12 @@ export class StandaloneKeybindingService extends AbstractKeybindingService { private _toNormalizedKeybindingItems(items: IKeybindingItem[], isDefault: boolean): ResolvedKeybindingItem[] { let result: ResolvedKeybindingItem[] = [], resultLen = 0; for (const item of items) { - const when = (item.when ? item.when.normalize() : undefined); + const when = item.when || undefined; const keybinding = item.keybinding; if (!keybinding) { // This might be a removal keybinding item in user settings => accept it - result[resultLen++] = new ResolvedKeybindingItem(null, item.command, item.commandArgs, when, isDefault); + result[resultLen++] = new ResolvedKeybindingItem(undefined, item.command, item.commandArgs, when, isDefault); } else { const resolvedKeybindings = this.resolveKeybinding(keybinding); for (const resolvedKeybinding of resolvedKeybindings) { @@ -382,6 +395,10 @@ export class StandaloneKeybindingService extends AbstractKeybindingService { public _dumpDebugInfo(): string { return ''; } + + public _dumpDebugInfoJSON(): string { + return ''; + } } function isConfigurationOverrides(thing: any): thing is IConfigurationOverrides { @@ -442,7 +459,17 @@ export class SimpleConfigurationService implements IConfigurationService { } public getConfigurationData(): IConfigurationData | null { - return null; + const emptyModel: IConfigurationModel = { + contents: {}, + keys: [], + overrides: [] + }; + return { + defaults: emptyModel, + user: emptyModel, + workspace: emptyModel, + folders: {} + }; } } @@ -503,6 +530,10 @@ export class StandaloneTelemetryService implements ITelemetryService { return Promise.resolve(undefined); } + publicLog2 = never, T extends GDPRClassification = never>(eventName: string, data?: StrictPropertyCheck) { + return this.publicLog(eventName, data as any); + } + public getTelemetryInfo(): Promise { throw new Error(`Not available`); } diff --git a/src/vs/editor/standalone/browser/standaloneCodeEditor.ts b/src/vs/editor/standalone/browser/standaloneCodeEditor.ts index 75fae8936..85b3aaaf0 100644 --- a/src/vs/editor/standalone/browser/standaloneCodeEditor.ts +++ b/src/vs/editor/standalone/browser/standaloneCodeEditor.ts @@ -5,7 +5,7 @@ import * as browser from 'vs/base/browser/browser'; import * as aria from 'vs/base/browser/ui/aria/aria'; -import { Disposable, IDisposable, combinedDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; @@ -227,13 +227,13 @@ export class StandaloneCodeEditor extends CodeEditorWidget implements IStandalon }; - let toDispose: IDisposable[] = []; + const toDispose = new DisposableStore(); // Generate a unique id to allow the same descriptor.id across multiple editor instances const uniqueId = this.getId() + ':' + id; // Register the command - toDispose.push(CommandsRegistry.registerCommand(uniqueId, run)); + toDispose.add(CommandsRegistry.registerCommand(uniqueId, run)); // Register the context menu item if (contextMenuGroupId) { @@ -246,16 +246,14 @@ export class StandaloneCodeEditor extends CodeEditorWidget implements IStandalon group: contextMenuGroupId, order: contextMenuOrder }; - toDispose.push(MenuRegistry.appendMenuItem(MenuId.EditorContext, menuItem)); + toDispose.add(MenuRegistry.appendMenuItem(MenuId.EditorContext, menuItem)); } // Register the keybindings if (Array.isArray(keybindings)) { - toDispose = toDispose.concat( - keybindings.map((kb) => { - return this._standaloneKeybindingService.addDynamicKeybinding(uniqueId, kb, run, keybindingsWhen); - }) - ); + for (const kb of keybindings) { + toDispose.add(this._standaloneKeybindingService.addDynamicKeybinding(uniqueId, kb, run, keybindingsWhen)); + } } // Finally, register an internal editor action @@ -270,11 +268,11 @@ export class StandaloneCodeEditor extends CodeEditorWidget implements IStandalon // Store it under the original id, such that trigger with the original id will work this._actions[id] = internalAction; - toDispose.push(toDisposable(() => { + toDispose.add(toDisposable(() => { delete this._actions[id]; })); - return combinedDisposable(toDispose); + return toDispose; } } diff --git a/src/vs/editor/standalone/browser/standaloneEditor.ts b/src/vs/editor/standalone/browser/standaloneEditor.ts index 09d4b4bce..8750db8f9 100644 --- a/src/vs/editor/standalone/browser/standaloneEditor.ts +++ b/src/vs/editor/standalone/browser/standaloneEditor.ts @@ -152,15 +152,13 @@ export function createModel(value: string, language?: string, uri?: URI): ITextM value = value || ''; if (!language) { - let path = uri ? uri.path : null; - let firstLF = value.indexOf('\n'); let firstLine = value; if (firstLF !== -1) { firstLine = value.substring(0, firstLF); } - return doCreateModel(value, StaticServices.modeService.get().createByFilepathOrFirstLine(path, firstLine), uri); + return doCreateModel(value, StaticServices.modeService.get().createByFilepathOrFirstLine(uri || null, firstLine), uri); } return doCreateModel(value, StaticServices.modeService.get().create(language), uri); } @@ -354,6 +352,7 @@ export function createMonacoEditorAPI(): typeof monaco.editor { ScrollbarVisibility: standaloneEnums.ScrollbarVisibility, WrappingIndent: standaloneEnums.WrappingIndent, OverviewRulerLane: standaloneEnums.OverviewRulerLane, + MinimapPosition: standaloneEnums.MinimapPosition, EndOfLinePreference: standaloneEnums.EndOfLinePreference, DefaultEndOfLine: standaloneEnums.DefaultEndOfLine, EndOfLineSequence: standaloneEnums.EndOfLineSequence, diff --git a/src/vs/editor/standalone/browser/standaloneLanguages.ts b/src/vs/editor/standalone/browser/standaloneLanguages.ts index 8a1f4a9c1..cfe1ec119 100644 --- a/src/vs/editor/standalone/browser/standaloneLanguages.ts +++ b/src/vs/editor/standalone/browser/standaloneLanguages.ts @@ -250,7 +250,7 @@ export interface IEncodedLineTokens { * - f = foreground ColorId (9 bits) * - b = background ColorId (9 bits) * - The color value for each colorId is defined in IStandaloneThemeData.customTokenColors: - * e.g colorId = 1 is stored in IStandaloneThemeData.customTokenColors[1]. Color id = 0 means no color, + * e.g. colorId = 1 is stored in IStandaloneThemeData.customTokenColors[1]. Color id = 0 means no color, * id = 1 is for the default foreground color, id = 2 for the default background. */ tokens: Uint32Array; @@ -290,14 +290,11 @@ export interface EncodedTokensProvider { } function isEncodedTokensProvider(provider: TokensProvider | EncodedTokensProvider): provider is EncodedTokensProvider { - return provider['tokenizeEncoded']; + return 'tokenizeEncoded' in provider; } function isThenable(obj: any): obj is Thenable { - if (typeof obj.then === 'function') { - return true; - } - return false; + return obj && typeof obj.then === 'function'; } /** @@ -427,7 +424,7 @@ export function registerCodeLensProvider(languageId: string, provider: modes.Cod */ export function registerCodeActionProvider(languageId: string, provider: CodeActionProvider): IDisposable { return modes.CodeActionProviderRegistry.register(languageId, { - provideCodeActions: (model: model.ITextModel, range: Range, context: modes.CodeActionContext, token: CancellationToken): (modes.Command | modes.CodeAction)[] | Promise<(modes.Command | modes.CodeAction)[]> => { + provideCodeActions: (model: model.ITextModel, range: Range, context: modes.CodeActionContext, token: CancellationToken): modes.CodeActionList | Promise => { let markers = StaticServices.markerService.get().read({ resource: model.uri }).filter(m => { return Range.areIntersectingOrTouching(m, range); }); @@ -510,7 +507,7 @@ export interface CodeActionProvider { /** * Provide commands for the given document and range. */ - provideCodeActions(model: model.ITextModel, range: Range, context: CodeActionContext, token: CancellationToken): (modes.Command | modes.CodeAction)[] | Promise<(modes.Command | modes.CodeAction)[]>; + provideCodeActions(model: model.ITextModel, range: Range, context: CodeActionContext, token: CancellationToken): modes.CodeActionList | Promise; } /** diff --git a/src/vs/editor/standalone/browser/standaloneServices.ts b/src/vs/editor/standalone/browser/standaloneServices.ts index 97fbd6d11..1777683f5 100644 --- a/src/vs/editor/standalone/browser/standaloneServices.ts +++ b/src/vs/editor/standalone/browser/standaloneServices.ts @@ -13,7 +13,7 @@ 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 { ITextResourceConfigurationService, ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration'; -import { SimpleBulkEditService, SimpleConfigurationService, SimpleDialogService, SimpleNotificationService, SimpleProgressService, SimpleResourceConfigurationService, SimpleResourcePropertiesService, SimpleUriLabelService, SimpleWorkspaceContextService, StandaloneCommandService, StandaloneKeybindingService, StandaloneTelemetryService, SimpleLayoutService } from 'vs/editor/standalone/browser/simpleServices'; +import { SimpleBulkEditService, SimpleConfigurationService, SimpleDialogService, SimpleNotificationService, SimpleEditorProgressService, SimpleResourceConfigurationService, SimpleResourcePropertiesService, SimpleUriLabelService, SimpleWorkspaceContextService, StandaloneCommandService, StandaloneKeybindingService, StandaloneTelemetryService, SimpleLayoutService } from 'vs/editor/standalone/browser/simpleServices'; import { StandaloneCodeEditorServiceImpl } from 'vs/editor/standalone/browser/standaloneCodeServiceImpl'; import { StandaloneThemeServiceImpl } from 'vs/editor/standalone/browser/standaloneThemeServiceImpl'; import { IStandaloneThemeService } from 'vs/editor/standalone/common/standaloneThemeService'; @@ -36,7 +36,7 @@ import { ILogService, NullLogService } from 'vs/platform/log/common/log'; import { MarkerService } from 'vs/platform/markers/common/markerService'; import { IMarkerService } from 'vs/platform/markers/common/markers'; import { INotificationService } from 'vs/platform/notification/common/notification'; -import { IProgressService } from 'vs/platform/progress/common/progress'; +import { IEditorProgressService } from 'vs/platform/progress/common/progress'; import { IStorageService, InMemoryStorageService } from 'vs/platform/storage/common/storage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IThemeService } from 'vs/platform/theme/common/themeService'; @@ -44,10 +44,10 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace import { MenuService } from 'vs/platform/actions/common/menuService'; import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDecorationService'; import { MarkerDecorationsService } from 'vs/editor/common/services/markerDecorationsServiceImpl'; -import { ISuggestMemoryService, SuggestMemoryService } from 'vs/editor/contrib/suggest/suggestMemory'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; import { BrowserAccessibilityService } from 'vs/platform/accessibility/common/accessibilityService'; import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; +import { getSingletonServiceDescriptors } from 'vs/platform/instantiation/common/extensions'; export interface IEditorOverrideServices { [index: string]: any; @@ -99,6 +99,11 @@ export module StaticServices { // Create a fresh service collection let result = new ServiceCollection(); + // make sure to add all services that use `registerSingleton` + for (const [id, descriptor] of getSingletonServiceDescriptors()) { + result.set(id, descriptor); + } + // Initialize the service collection with the overrides for (let serviceId in overrides) { if (overrides.hasOwnProperty(serviceId)) { @@ -135,8 +140,6 @@ export module StaticServices { export const notificationService = define(INotificationService, () => new SimpleNotificationService()); - export const accessibilityService = define(IAccessibilityService, () => new BrowserAccessibilityService()); - export const markerService = define(IMarkerService, () => new MarkerService()); export const modeService = define(IModeService, (o) => new ModeServiceImpl()); @@ -149,16 +152,13 @@ export module StaticServices { export const codeEditorService = define(ICodeEditorService, (o) => new StandaloneCodeEditorServiceImpl(standaloneThemeService.get(o))); - export const progressService = define(IProgressService, () => new SimpleProgressService()); + export const editorProgressService = define(IEditorProgressService, () => new SimpleEditorProgressService()); export const storageService = define(IStorageService, () => new InMemoryStorageService()); export const logService = define(ILogService, () => new NullLogService()); export const editorWorkerService = define(IEditorWorkerService, (o) => new EditorWorkerServiceImpl(modelService.get(o), resourceConfigurationService.get(o), logService.get(o))); - - export const suggestMemoryService = define(ISuggestMemoryService, (o) => new SuggestMemoryService(storageService.get(o), configurationService.get(o))); - } export class DynamicStandaloneServices extends Disposable { @@ -192,6 +192,8 @@ export class DynamicStandaloneServices extends Disposable { let contextKeyService = ensure(IContextKeyService, () => this._register(new ContextKeyService(configurationService))); + ensure(IAccessibilityService, () => new BrowserAccessibilityService(contextKeyService, configurationService)); + ensure(IListService, () => new ListService(contextKeyService)); let commandService = ensure(ICommandService, () => new StandaloneCommandService(this._instantiationService)); diff --git a/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts b/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts index 5e9074577..3f04994e5 100644 --- a/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts +++ b/src/vs/editor/standalone/browser/standaloneThemeServiceImpl.ts @@ -27,7 +27,7 @@ class StandaloneTheme implements IStandaloneTheme { public readonly themeName: string; private readonly themeData: IStandaloneThemeData; - private colors: { [colorId: string]: Color } | null; + private colors: Map | null; private readonly defaultColors: { [colorId: string]: Color | undefined; }; private _tokenTheme: TokenTheme | null; @@ -57,19 +57,18 @@ class StandaloneTheme implements IStandaloneTheme { } } - private getColors(): { [colorId: string]: Color } { + private getColors(): Map { if (!this.colors) { - let colors: { [colorId: string]: Color } = Object.create(null); + const colors = new Map(); for (let id in this.themeData.colors) { - colors[id] = Color.fromHex(this.themeData.colors[id]); + colors.set(id, Color.fromHex(this.themeData.colors[id])); } if (this.themeData.inherit) { let baseData = getBuiltinRules(this.themeData.base); for (let id in baseData.colors) { - if (!colors[id]) { - colors[id] = Color.fromHex(baseData.colors[id]); + if (!colors.has(id)) { + colors.set(id, Color.fromHex(baseData.colors[id])); } - } } this.colors = colors; @@ -78,7 +77,7 @@ class StandaloneTheme implements IStandaloneTheme { } public getColor(colorId: ColorIdentifier, useDefault?: boolean): Color | undefined { - const color = this.getColors()[colorId]; + const color = this.getColors().get(colorId); if (color) { return color; } diff --git a/src/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.ts b/src/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.ts index 9f6261900..22cb5063a 100644 --- a/src/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.ts +++ b/src/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.ts @@ -17,7 +17,7 @@ class ToggleHighContrast extends EditorAction { id: 'editor.action.toggleHighContrast', label: ToggleHighContrastNLS.toggleHighContrast, alias: 'Toggle High Contrast Theme', - precondition: null + precondition: undefined }); this._originalThemeName = null; } diff --git a/src/vs/editor/standalone/common/monarch/monarchLexer.ts b/src/vs/editor/standalone/common/monarch/monarchLexer.ts index 2567c561f..a5c97ad6f 100644 --- a/src/vs/editor/standalone/common/monarch/monarchLexer.ts +++ b/src/vs/editor/standalone/common/monarch/monarchLexer.ts @@ -857,6 +857,11 @@ export class MonarchTokenizer implements modes.ITokenizationSupport { return null; } + if (mimetypeOrModeId === this._modeId) { + // embedding myself... + return mimetypeOrModeId; + } + let modeId = this._modeService.getModeId(mimetypeOrModeId); if (modeId) { diff --git a/src/vs/editor/test/browser/controller/cursor.test.ts b/src/vs/editor/test/browser/controller/cursor.test.ts index d34c9ff1b..c2a4e4a45 100644 --- a/src/vs/editor/test/browser/controller/cursor.test.ts +++ b/src/vs/editor/test/browser/controller/cursor.test.ts @@ -710,7 +710,8 @@ suite('Editor Controller - Cursor', () => { CoreNavigationCommands.ColumnSelect.runCoreEditorCommand(cursor, { position: new Position(4, 4), viewPosition: new Position(4, 4), - mouseColumn: 15 + mouseColumn: 15, + setAnchorIfNotSet: false }); let expectedSelections = [ @@ -745,7 +746,8 @@ suite('Editor Controller - Cursor', () => { CoreNavigationCommands.ColumnSelect.runCoreEditorCommand(cursor, { position: new Position(4, 1), viewPosition: new Position(4, 1), - mouseColumn: 1 + mouseColumn: 1, + setAnchorIfNotSet: false }); assertCursor(cursor, [ @@ -784,7 +786,8 @@ suite('Editor Controller - Cursor', () => { CoreNavigationCommands.ColumnSelect.runCoreEditorCommand(cursor, { position: new Position(1, 1), viewPosition: new Position(1, 1), - mouseColumn: 1 + mouseColumn: 1, + setAnchorIfNotSet: false }); assertCursor(cursor, [ new Selection(10, 10, 10, 1), @@ -802,7 +805,8 @@ suite('Editor Controller - Cursor', () => { CoreNavigationCommands.ColumnSelect.runCoreEditorCommand(cursor, { position: new Position(1, 1), viewPosition: new Position(1, 1), - mouseColumn: 1 + mouseColumn: 1, + setAnchorIfNotSet: false }); assertCursor(cursor, [ new Selection(10, 10, 10, 1), @@ -2052,7 +2056,7 @@ suite('Editor Controller - Regression tests', () => { getInitialState: () => NULL_STATE, tokenize: undefined!, tokenize2: (line: string, state: IState): TokenizationResult2 => { - return new TokenizationResult2(null!, state); + return new TokenizationResult2(new Uint32Array(0), state); } }; @@ -4340,12 +4344,12 @@ suite('autoClosingPairs', () => { let autoClosePositions = [ 'var a |=| [|]|;|', 'var b |=| |`asd`|;|', - 'var c |=| |\'asd!\'|;|', + 'var c |=| |\'asd\'|;|', 'var d |=| |"asd"|;|', 'var e |=| /*3*/| 3;|', 'var f |=| /**| 3 */3;|', 'var g |=| (3+5)|;|', - 'var h |=| {| a:| |\'value!\'| |}|;|', + 'var h |=| {| a:| |\'value\'| |}|;|', ]; for (let i = 0, len = autoClosePositions.length; i < len; i++) { const lineNumber = i + 1; @@ -4490,6 +4494,107 @@ suite('autoClosingPairs', () => { mode.dispose(); }); + test('issue #37315 - overtypes only those characters that it inserted', () => { + let mode = new AutoClosingMode(); + usingCursor({ + text: [ + '', + 'y=();' + ], + languageIdentifier: mode.getLanguageIdentifier() + }, (model, cursor) => { + assertCursor(cursor, new Position(1, 1)); + + cursorCommand(cursor, H.Type, { text: 'x=(' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=()'); + + cursorCommand(cursor, H.Type, { text: 'asd' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=(asd)'); + + // overtype! + cursorCommand(cursor, H.Type, { text: ')' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=(asd)'); + + // do not overtype! + cursor.setSelections('test', [new Selection(2, 4, 2, 4)]); + cursorCommand(cursor, H.Type, { text: ')' }, 'keyboard'); + assert.strictEqual(model.getLineContent(2), 'y=());'); + + }); + mode.dispose(); + }); + + test('issue #37315 - stops overtyping once cursor leaves area', () => { + let mode = new AutoClosingMode(); + usingCursor({ + text: [ + '', + 'y=();' + ], + languageIdentifier: mode.getLanguageIdentifier() + }, (model, cursor) => { + assertCursor(cursor, new Position(1, 1)); + + cursorCommand(cursor, H.Type, { text: 'x=(' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=()'); + + cursor.setSelections('test', [new Selection(1, 5, 1, 5)]); + cursorCommand(cursor, H.Type, { text: ')' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=())'); + }); + mode.dispose(); + }); + + test('issue #37315 - it overtypes only once', () => { + let mode = new AutoClosingMode(); + usingCursor({ + text: [ + '', + 'y=();' + ], + languageIdentifier: mode.getLanguageIdentifier() + }, (model, cursor) => { + assertCursor(cursor, new Position(1, 1)); + + cursorCommand(cursor, H.Type, { text: 'x=(' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=()'); + + cursorCommand(cursor, H.Type, { text: ')' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=()'); + + cursor.setSelections('test', [new Selection(1, 4, 1, 4)]); + cursorCommand(cursor, H.Type, { text: ')' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=())'); + }); + mode.dispose(); + }); + + test('issue #37315 - it can remember multiple auto-closed instances', () => { + let mode = new AutoClosingMode(); + usingCursor({ + text: [ + '', + 'y=();' + ], + languageIdentifier: mode.getLanguageIdentifier() + }, (model, cursor) => { + assertCursor(cursor, new Position(1, 1)); + + cursorCommand(cursor, H.Type, { text: 'x=(' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=()'); + + cursorCommand(cursor, H.Type, { text: '(' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=(())'); + + cursorCommand(cursor, H.Type, { text: ')' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=(())'); + + cursorCommand(cursor, H.Type, { text: ')' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=(())'); + }); + mode.dispose(); + }); + test('issue #15825: accents on mac US intl keyboard', () => { let mode = new AutoClosingMode(); usingCursor({ diff --git a/src/vs/editor/test/browser/controller/cursorMoveCommand.test.ts b/src/vs/editor/test/browser/controller/cursorMoveCommand.test.ts index 96bc4fc04..92aedce24 100644 --- a/src/vs/editor/test/browser/controller/cursorMoveCommand.test.ts +++ b/src/vs/editor/test/browser/controller/cursorMoveCommand.test.ts @@ -132,7 +132,7 @@ suite('Cursor move command test', () => { test('move to first non white space character of line from middle', () => { moveTo(thisCursor, 1, 8); - moveToLineFirstNonWhiteSpaceCharacter(thisCursor); + moveToLineFirstNonWhitespaceCharacter(thisCursor); cursorEqual(thisCursor, 1, 6); }); @@ -140,7 +140,7 @@ suite('Cursor move command test', () => { test('move to first non white space character of line from first non white space character', () => { moveTo(thisCursor, 1, 6); - moveToLineFirstNonWhiteSpaceCharacter(thisCursor); + moveToLineFirstNonWhitespaceCharacter(thisCursor); cursorEqual(thisCursor, 1, 6); }); @@ -148,7 +148,7 @@ suite('Cursor move command test', () => { test('move to first non white space character of line from first character', () => { moveTo(thisCursor, 1, 1); - moveToLineFirstNonWhiteSpaceCharacter(thisCursor); + moveToLineFirstNonWhitespaceCharacter(thisCursor); cursorEqual(thisCursor, 1, 6); }); @@ -180,7 +180,7 @@ suite('Cursor move command test', () => { test('move to last non white space character from middle', () => { moveTo(thisCursor, 1, 8); - moveToLineLastNonWhiteSpaceCharacter(thisCursor); + moveToLineLastNonWhitespaceCharacter(thisCursor); cursorEqual(thisCursor, 1, 19); }); @@ -188,7 +188,7 @@ suite('Cursor move command test', () => { test('move to last non white space character from last non white space character', () => { moveTo(thisCursor, 1, 19); - moveToLineLastNonWhiteSpaceCharacter(thisCursor); + moveToLineLastNonWhitespaceCharacter(thisCursor); cursorEqual(thisCursor, 1, 19); }); @@ -196,7 +196,7 @@ suite('Cursor move command test', () => { test('move to last non white space character from line end', () => { moveTo(thisCursor, 1, 21); - moveToLineLastNonWhiteSpaceCharacter(thisCursor); + moveToLineLastNonWhitespaceCharacter(thisCursor); cursorEqual(thisCursor, 1, 19); }); @@ -415,7 +415,7 @@ function moveToLineStart(cursor: Cursor) { move(cursor, { to: CursorMove.RawDirection.WrappedLineStart }); } -function moveToLineFirstNonWhiteSpaceCharacter(cursor: Cursor) { +function moveToLineFirstNonWhitespaceCharacter(cursor: Cursor) { move(cursor, { to: CursorMove.RawDirection.WrappedLineFirstNonWhitespaceCharacter }); } @@ -427,7 +427,7 @@ function moveToLineEnd(cursor: Cursor) { move(cursor, { to: CursorMove.RawDirection.WrappedLineEnd }); } -function moveToLineLastNonWhiteSpaceCharacter(cursor: Cursor) { +function moveToLineLastNonWhitespaceCharacter(cursor: Cursor) { move(cursor, { to: CursorMove.RawDirection.WrappedLineLastNonWhitespaceCharacter }); } diff --git a/src/vs/editor/test/browser/editorTestServices.ts b/src/vs/editor/test/browser/editorTestServices.ts index 25af3b0ef..f896360ac 100644 --- a/src/vs/editor/test/browser/editorTestServices.ts +++ b/src/vs/editor/test/browser/editorTestServices.ts @@ -32,6 +32,9 @@ export class TestCommandService implements ICommandService { private readonly _onWillExecuteCommand = new Emitter(); public readonly onWillExecuteCommand: Event = this._onWillExecuteCommand.event; + private readonly _onDidExecuteCommand = new Emitter(); + public readonly onDidExecuteCommand: Event = this._onDidExecuteCommand.event; + constructor(instantiationService: IInstantiationService) { this._instantiationService = instantiationService; } @@ -43,8 +46,9 @@ export class TestCommandService implements ICommandService { } try { - this._onWillExecuteCommand.fire({ commandId: id }); + this._onWillExecuteCommand.fire({ commandId: id, args }); const result = this._instantiationService.invokeFunction.apply(this._instantiationService, [command.handler, ...args]) as T; + this._onDidExecuteCommand.fire({ commandId: id, args }); return Promise.resolve(result); } catch (err) { return Promise.reject(err); diff --git a/src/vs/editor/test/browser/services/openerService.test.ts b/src/vs/editor/test/browser/services/openerService.test.ts index 3e6437424..eadf90235 100644 --- a/src/vs/editor/test/browser/services/openerService.test.ts +++ b/src/vs/editor/test/browser/services/openerService.test.ts @@ -17,6 +17,7 @@ suite('OpenerService', function () { const commandService = new class implements ICommandService { _serviceBrand: any; onWillExecuteCommand = () => ({ dispose: () => { } }); + onDidExecuteCommand = () => ({ dispose: () => { } }); executeCommand(id: string, ...args: any[]): Promise { lastCommand = { id, args }; return Promise.resolve(undefined); diff --git a/src/vs/editor/test/browser/testCommand.ts b/src/vs/editor/test/browser/testCommand.ts index f0e12dadc..5b96fde1e 100644 --- a/src/vs/editor/test/browser/testCommand.ts +++ b/src/vs/editor/test/browser/testCommand.ts @@ -18,7 +18,8 @@ export function testCommand( selection: Selection, commandFactory: (selection: Selection) => editorCommon.ICommand, expectedLines: string[], - expectedSelection: Selection + expectedSelection: Selection, + forceTokenization?: boolean ): void { let model = TextModel.createFromString(lines.join('\n'), undefined, languageIdentifier); withTestCodeEditor('', { model: model }, (_editor, cursor) => { @@ -26,6 +27,10 @@ export function testCommand( return; } + if (forceTokenization) { + model.forceTokenization(model.getLineCount()); + } + cursor.setSelections('tests', [selection]); cursor.trigger('tests', editorCommon.Handler.ExecuteCommand, commandFactory(cursor.getSelection())); 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 19379cd5c..be29d6a96 100644 --- a/src/vs/editor/test/common/model/model.line.test.ts +++ b/src/vs/editor/test/common/model/model.line.test.ts @@ -110,7 +110,9 @@ suite('ModelLinesTokens', () => { for (let lineIndex = 0; lineIndex < initial.length; lineIndex++) { const lineTokens = initial[lineIndex].tokens; const lineTextLength = model.getLineMaxColumn(lineIndex + 1) - 1; - model._tokens._setTokens(0, lineIndex, lineTextLength, TestToken.toTokens(lineTokens)); + const tokens = TestToken.toTokens(lineTokens); + LineTokens.convertToEndOffset(tokens, lineTextLength); + model.setLineTokens(lineIndex + 1, tokens); } model.applyEdits(edits.map((ed) => ({ @@ -441,14 +443,16 @@ suite('ModelLinesTokens', () => { test('insertion on empty line', () => { const model = new TextModel('some text', TextModel.DEFAULT_CREATION_OPTIONS, new LanguageIdentifier('test', 0)); - model._tokens._setTokens(0, 0, model.getLineMaxColumn(1) - 1, TestToken.toTokens([new TestToken(0, 1)])); + const tokens = TestToken.toTokens([new TestToken(0, 1)]); + LineTokens.convertToEndOffset(tokens, model.getLineMaxColumn(1) - 1); + model.setLineTokens(1, tokens); model.applyEdits([{ range: new Range(1, 1, 1, 10), text: '' }]); - model._tokens._setTokens(0, 0, model.getLineMaxColumn(1) - 1, new Uint32Array(0)); + model.setLineTokens(1, new Uint32Array(0)); model.applyEdits([{ range: new Range(1, 1, 1, 1), @@ -660,7 +664,7 @@ suite('ModelLinesTokens', () => { test('updates tokens on insertion 10', () => { testLineEditTokens( '', - null!, + [], [{ startColumn: 1, endColumn: 1, diff --git a/src/vs/editor/test/common/model/model.modes.test.ts b/src/vs/editor/test/common/model/model.modes.test.ts index 3f2a4044f..559a6f89f 100644 --- a/src/vs/editor/test/common/model/model.modes.test.ts +++ b/src/vs/editor/test/common/model/model.modes.test.ts @@ -29,7 +29,7 @@ suite('Editor Model - Model Modes 1', () => { tokenize: undefined!, tokenize2: (line: string, state: modes.IState): TokenizationResult2 => { calledFor.push(line.charAt(0)); - return new TokenizationResult2(null!, state); + return new TokenizationResult2(new Uint32Array(0), state); } }; @@ -170,37 +170,23 @@ suite('Editor Model - Model Modes 2', () => { } } + let calledFor: string[] = []; + + function checkAndClear(arr: string[]): void { + assert.deepEqual(calledFor, arr); + calledFor = []; + } + const tokenizationSupport: modes.ITokenizationSupport = { getInitialState: () => new ModelState2(''), tokenize: undefined!, tokenize2: (line: string, state: modes.IState): TokenizationResult2 => { + calledFor.push(line); (state).prevLineContent = line; - return new TokenizationResult2(null!, state); + return new TokenizationResult2(new Uint32Array(0), state); } }; - function invalidEqual(model: TextModel, expected: number[]): void { - let actual: number[] = []; - for (let i = 0, len = model.getLineCount(); i < len; i++) { - if (model._tokens._isInvalid(i)) { - actual.push(i); - } - } - assert.deepEqual(actual, expected); - } - - function stateEqual(state: modes.IState, content: string): void { - assert.equal((state).prevLineContent, content); - } - - function statesEqual(model: TextModel, states: string[]): void { - let i, len = states.length - 1; - for (i = 0; i < len; i++) { - stateEqual(model._tokens._getState(i)!, states[i]); - } - stateEqual((model)._tokens._lastState, states[len]); - } - let thisModel: TextModel; let languageRegistration: IDisposable; @@ -223,64 +209,54 @@ suite('Editor Model - Model Modes 2', () => { test('getTokensForInvalidLines one text insert', () => { thisModel.forceTokenization(5); - statesEqual(thisModel, ['', 'Line1', 'Line2', 'Line3', 'Line4', 'Line5']); + checkAndClear(['Line1', 'Line2', 'Line3', 'Line4', 'Line5']); thisModel.applyEdits([EditOperation.insert(new Position(1, 6), '-')]); - invalidEqual(thisModel, [0]); - statesEqual(thisModel, ['', 'Line1', 'Line2', 'Line3', 'Line4', 'Line5']); thisModel.forceTokenization(5); - statesEqual(thisModel, ['', 'Line1-', 'Line2', 'Line3', 'Line4', 'Line5']); + checkAndClear(['Line1-', 'Line2']); }); test('getTokensForInvalidLines two text insert', () => { thisModel.forceTokenization(5); - statesEqual(thisModel, ['', 'Line1', 'Line2', 'Line3', 'Line4', 'Line5']); + checkAndClear(['Line1', 'Line2', 'Line3', 'Line4', 'Line5']); thisModel.applyEdits([ EditOperation.insert(new Position(1, 6), '-'), EditOperation.insert(new Position(3, 6), '-') ]); - invalidEqual(thisModel, [0, 2]); thisModel.forceTokenization(5); - statesEqual(thisModel, ['', 'Line1-', 'Line2', 'Line3-', 'Line4', 'Line5']); + checkAndClear(['Line1-', 'Line2', 'Line3-', 'Line4']); }); test('getTokensForInvalidLines one multi-line text insert, one small text insert', () => { thisModel.forceTokenization(5); - statesEqual(thisModel, ['', 'Line1', 'Line2', 'Line3', 'Line4', 'Line5']); + checkAndClear(['Line1', 'Line2', 'Line3', 'Line4', 'Line5']); thisModel.applyEdits([EditOperation.insert(new Position(1, 6), '\nNew line\nAnother new line')]); - invalidEqual(thisModel, [0, 1, 2]); thisModel.applyEdits([EditOperation.insert(new Position(5, 6), '-')]); - invalidEqual(thisModel, [0, 1, 2, 4]); thisModel.forceTokenization(7); - statesEqual(thisModel, ['', 'Line1', 'New line', 'Another new line', 'Line2', 'Line3-', 'Line4', 'Line5']); + checkAndClear(['Line1', 'New line', 'Another new line', 'Line2', 'Line3-', 'Line4']); }); test('getTokensForInvalidLines one delete text', () => { thisModel.forceTokenization(5); - statesEqual(thisModel, ['', 'Line1', 'Line2', 'Line3', 'Line4', 'Line5']); + checkAndClear(['Line1', 'Line2', 'Line3', 'Line4', 'Line5']); thisModel.applyEdits([EditOperation.delete(new Range(1, 1, 1, 5))]); - invalidEqual(thisModel, [0]); thisModel.forceTokenization(5); - statesEqual(thisModel, ['', '1', 'Line2', 'Line3', 'Line4', 'Line5']); + checkAndClear(['1', 'Line2']); }); test('getTokensForInvalidLines one line delete text', () => { thisModel.forceTokenization(5); - statesEqual(thisModel, ['', 'Line1', 'Line2', 'Line3', 'Line4', 'Line5']); + checkAndClear(['Line1', 'Line2', 'Line3', 'Line4', 'Line5']); thisModel.applyEdits([EditOperation.delete(new Range(1, 1, 2, 1))]); - invalidEqual(thisModel, [0]); - statesEqual(thisModel, ['', 'Line2', 'Line3', 'Line4', 'Line5']); thisModel.forceTokenization(4); - statesEqual(thisModel, ['', 'Line2', 'Line3', 'Line4', 'Line5']); + checkAndClear(['Line2']); }); test('getTokensForInvalidLines multiple lines delete text', () => { thisModel.forceTokenization(5); - statesEqual(thisModel, ['', 'Line1', 'Line2', 'Line3', 'Line4', 'Line5']); + checkAndClear(['Line1', 'Line2', 'Line3', 'Line4', 'Line5']); thisModel.applyEdits([EditOperation.delete(new Range(1, 1, 3, 3))]); - invalidEqual(thisModel, [0]); - statesEqual(thisModel, ['', 'Line3', 'Line4', 'Line5']); thisModel.forceTokenization(3); - statesEqual(thisModel, ['', 'ne3', 'Line4', 'Line5']); + checkAndClear(['ne3', 'Line4']); }); }); diff --git a/src/vs/editor/test/common/model/textModel.test.ts b/src/vs/editor/test/common/model/textModel.test.ts index d2a8d3cd4..812edc454 100644 --- a/src/vs/editor/test/common/model/textModel.test.ts +++ b/src/vs/editor/test/common/model/textModel.test.ts @@ -26,17 +26,21 @@ function testGuessIndentation(defaultInsertSpaces: boolean, defaultTabSize: numb assert.equal(r.tabSize, expectedTabSize, msg); } -function assertGuess(expectedInsertSpaces: boolean | undefined, expectedTabSize: number | undefined, text: string[], msg?: string): void { +function assertGuess(expectedInsertSpaces: boolean | undefined, expectedTabSize: number | undefined | [number], text: string[], msg?: string): void { if (typeof expectedInsertSpaces === 'undefined') { // cannot guess insertSpaces if (typeof expectedTabSize === 'undefined') { // cannot guess tabSize testGuessIndentation(true, 13370, true, 13370, text, msg); testGuessIndentation(false, 13371, false, 13371, text, msg); - } else { + } else if (typeof expectedTabSize === 'number') { // can guess tabSize testGuessIndentation(true, 13370, true, expectedTabSize, text, msg); testGuessIndentation(false, 13371, false, expectedTabSize, text, msg); + } else { + // can only guess tabSize when insertSpaces is true + testGuessIndentation(true, 13370, true, expectedTabSize[0], text, msg); + testGuessIndentation(false, 13371, false, 13371, text, msg); } } else { // can guess insertSpaces @@ -44,10 +48,19 @@ function assertGuess(expectedInsertSpaces: boolean | undefined, expectedTabSize: // cannot guess tabSize testGuessIndentation(true, 13370, expectedInsertSpaces, 13370, text, msg); testGuessIndentation(false, 13371, expectedInsertSpaces, 13371, text, msg); - } else { + } else if (typeof expectedTabSize === 'number') { // can guess tabSize testGuessIndentation(true, 13370, expectedInsertSpaces, expectedTabSize, text, msg); testGuessIndentation(false, 13371, expectedInsertSpaces, expectedTabSize, text, msg); + } else { + // can only guess tabSize when insertSpaces is true + if (expectedInsertSpaces === true) { + testGuessIndentation(true, 13370, expectedInsertSpaces, expectedTabSize[0], text, msg); + testGuessIndentation(false, 13371, expectedInsertSpaces, expectedTabSize[0], text, msg); + } else { + testGuessIndentation(true, 13370, expectedInsertSpaces, 13370, text, msg); + testGuessIndentation(false, 13371, expectedInsertSpaces, 13371, text, msg); + } } } } @@ -219,7 +232,7 @@ suite('Editor Model - TextModel', () => { '\tx' ], '7xTAB'); - assertGuess(undefined, 2, [ + assertGuess(undefined, [2], [ '\tx', ' x', '\tx', @@ -239,7 +252,7 @@ suite('Editor Model - TextModel', () => { '\tx', ' x' ], '4x1, 4xTAB'); - assertGuess(false, 2, [ + assertGuess(false, undefined, [ '\tx', '\tx', ' x', @@ -250,7 +263,7 @@ suite('Editor Model - TextModel', () => { '\tx', ' x', ], '4x2, 5xTAB'); - assertGuess(false, 2, [ + assertGuess(false, undefined, [ '\tx', '\tx', 'x', @@ -261,7 +274,7 @@ suite('Editor Model - TextModel', () => { '\tx', ' x', ], '1x2, 5xTAB'); - assertGuess(false, 4, [ + assertGuess(false, undefined, [ '\tx', '\tx', 'x', @@ -272,7 +285,7 @@ suite('Editor Model - TextModel', () => { '\tx', ' x', ], '1x4, 5xTAB'); - assertGuess(false, 2, [ + assertGuess(false, undefined, [ '\tx', '\tx', 'x', @@ -524,7 +537,7 @@ suite('Editor Model - TextModel', () => { ' \t x', '\tx' ], 'mixed whitespace 1'); - assertGuess(false, 4, [ + assertGuess(false, undefined, [ '\tx', '\t x' ], 'mixed whitespace 2'); @@ -575,6 +588,26 @@ suite('Editor Model - TextModel', () => { ]); }); + test('issue #70832: Broken indentation detection', () => { + assertGuess(false, undefined, [ + 'x', + 'x', + 'x', + 'x', + ' x', + ' x', + ' x', + ' x', + ' x', + ' x', + ' x', + ' x', + ' x', + ' x', + 'x', + ]); + }); + test('validatePosition', () => { let m = TextModel.createFromString('line one\nline two'); diff --git a/src/vs/editor/test/common/model/textModelSearch.test.ts b/src/vs/editor/test/common/model/textModelSearch.test.ts index 1dc5e82b5..6476015cb 100644 --- a/src/vs/editor/test/common/model/textModelSearch.test.ts +++ b/src/vs/editor/test/common/model/textModelSearch.test.ts @@ -733,4 +733,23 @@ suite('TextModelSearch', () => { assert(isMultilineRegexSource('\\n')); assert(isMultilineRegexSource('foo\\W')); }); + + test('issue #74715. \\d* finds empty string and stops searching.', () => { + let model = TextModel.createFromString('10.243.30.10'); + + let searchParams = new SearchParams('\\d*', true, false, null); + + let actual = TextModelSearch.findMatches(model, searchParams, model.getFullModelRange(), true, 100); + assert.deepEqual(actual, [ + new FindMatch(new Range(1, 1, 1, 3), ['10']), + new FindMatch(new Range(1, 3, 1, 3), ['']), + new FindMatch(new Range(1, 4, 1, 7), ['243']), + new FindMatch(new Range(1, 7, 1, 7), ['']), + new FindMatch(new Range(1, 8, 1, 10), ['30']), + new FindMatch(new Range(1, 10, 1, 10), ['']), + new FindMatch(new Range(1, 11, 1, 13), ['10']) + ]); + + model.dispose(); + }); }); diff --git a/src/vs/editor/test/common/services/editorSimpleWorker.test.ts b/src/vs/editor/test/common/services/editorSimpleWorker.test.ts index 43726f59e..8ea09048b 100644 --- a/src/vs/editor/test/common/services/editorSimpleWorker.test.ts +++ b/src/vs/editor/test/common/services/editorSimpleWorker.test.ts @@ -5,11 +5,12 @@ import * as assert from 'assert'; import { Range } from 'vs/editor/common/core/range'; -import { EditorSimpleWorkerImpl, ICommonModel } from 'vs/editor/common/services/editorSimpleWorker'; +import { EditorSimpleWorker, ICommonModel } from 'vs/editor/common/services/editorSimpleWorker'; +import { EditorWorkerHost } from 'vs/editor/common/services/editorWorkerServiceImpl'; suite('EditorSimpleWorker', () => { - class WorkerWithModels extends EditorSimpleWorkerImpl { + class WorkerWithModels extends EditorSimpleWorker { getModel(uri: string) { return this._getModel(uri); @@ -31,7 +32,7 @@ suite('EditorSimpleWorker', () => { let model: ICommonModel; setup(() => { - worker = new WorkerWithModels(null); + worker = new WorkerWithModels(null!, null); model = worker.addModel([ 'This is line one', //16 'and this is line number two', //27 diff --git a/src/vs/editor/test/common/viewLayout/viewLineRenderer.test.ts b/src/vs/editor/test/common/viewLayout/viewLineRenderer.test.ts index 0112ef018..e3e6ad4c2 100644 --- a/src/vs/editor/test/common/viewLayout/viewLineRenderer.test.ts +++ b/src/vs/editor/test/common/viewLayout/viewLineRenderer.test.ts @@ -9,7 +9,7 @@ import * as strings from 'vs/base/common/strings'; import { IViewLineTokens } from 'vs/editor/common/core/lineTokens'; import { MetadataConsts } from 'vs/editor/common/modes'; import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations'; -import { CharacterMapping, RenderLineInput, renderViewLine2 as renderViewLine } from 'vs/editor/common/viewLayout/viewLineRenderer'; +import { CharacterMapping, RenderLineInput, renderViewLine2 as renderViewLine, LineRange } from 'vs/editor/common/viewLayout/viewLineRenderer'; import { InlineDecorationType } from 'vs/editor/common/viewModel/viewModel'; import { ViewLineToken, ViewLineTokens } from 'vs/editor/test/common/core/viewLineToken'; @@ -41,7 +41,8 @@ suite('viewLineRenderer.renderLine', () => { -1, 'none', false, - false + false, + null )); assert.equal(_actual.html, '' + expected + ''); @@ -90,7 +91,8 @@ suite('viewLineRenderer.renderLine', () => { -1, 'none', false, - false + false, + null )); assert.equal(_actual.html, '' + expected + ''); @@ -142,7 +144,8 @@ suite('viewLineRenderer.renderLine', () => { 6, 'boundary', false, - false + false, + null )); let expectedOutput = [ @@ -233,7 +236,8 @@ suite('viewLineRenderer.renderLine', () => { -1, 'boundary', false, - false + false, + null )); assert.equal(_actual.html, '' + expectedOutput + ''); @@ -295,7 +299,8 @@ suite('viewLineRenderer.renderLine', () => { -1, 'none', false, - false + false, + null )); assert.equal(_actual.html, '' + expectedOutput + ''); @@ -357,7 +362,8 @@ suite('viewLineRenderer.renderLine', () => { -1, 'none', false, - false + false, + null )); assert.equal(_actual.html, '' + expectedOutput + ''); @@ -396,7 +402,8 @@ suite('viewLineRenderer.renderLine', () => { -1, 'none', false, - false + false, + null )); assert.equal(_actual.html, '' + expectedOutput + ''); @@ -426,7 +433,8 @@ suite('viewLineRenderer.renderLine', () => { -1, 'none', false, - false + false, + null )); assert.equal(actual.html, '' + expectedOutput.join('') + '', message); } @@ -526,7 +534,8 @@ suite('viewLineRenderer.renderLine', () => { -1, 'none', false, - true + true, + null )); assert.equal(actual.html, '' + expectedOutput.join('') + '', message); } @@ -564,7 +573,8 @@ suite('viewLineRenderer.renderLine', () => { -1, 'none', false, - false + false, + null )); let expectedOutput = [ 'a𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷𠮷', @@ -593,7 +603,8 @@ suite('viewLineRenderer.renderLine', () => { -1, 'none', false, - false + false, + null )); assert.equal(actual.html, '' + expectedOutput.join('') + ''); assert.equal(actual.containsRTL, true); @@ -639,7 +650,8 @@ suite('viewLineRenderer.renderLine', () => { -1, 'none', false, - false + false, + null )); assert.equal(_actual.html, '' + expectedOutput + ''); @@ -704,7 +716,7 @@ suite('viewLineRenderer.renderLine', () => { suite('viewLineRenderer.renderLine 2', () => { - function testCreateLineParts(fontIsMonospace: boolean, lineContent: string, tokens: ViewLineToken[], fauxIndentLength: number, renderWhitespace: 'none' | 'boundary' | 'all', expected: string): void { + function testCreateLineParts(fontIsMonospace: boolean, lineContent: string, tokens: ViewLineToken[], fauxIndentLength: number, renderWhitespace: 'none' | 'boundary' | 'selection' | 'all', selections: LineRange[] | null, expected: string): void { let actual = renderViewLine(new RenderLineInput( fontIsMonospace, true, @@ -720,7 +732,8 @@ suite('viewLineRenderer.renderLine 2', () => { -1, renderWhitespace, false, - false + false, + selections )); assert.deepEqual(actual.html, expected); @@ -745,7 +758,8 @@ suite('viewLineRenderer.renderLine 2', () => { -1, 'none', false, - false + false, + null )); let expected = [ @@ -784,7 +798,8 @@ suite('viewLineRenderer.renderLine 2', () => { -1, 'none', false, - false + false, + null )); let expected = [ @@ -811,6 +826,7 @@ suite('viewLineRenderer.renderLine 2', () => { ], 0, 'none', + null, [ '', 'Hello\u00a0world!', @@ -828,6 +844,7 @@ suite('viewLineRenderer.renderLine 2', () => { ], 0, 'none', + null, [ '', 'Hello\u00a0', @@ -847,6 +864,7 @@ suite('viewLineRenderer.renderLine 2', () => { ], 0, 'boundary', + null, [ '', '\u00b7\u00b7\u00b7\u00b7', @@ -868,6 +886,7 @@ suite('viewLineRenderer.renderLine 2', () => { ], 0, 'boundary', + null, [ '', '\u00b7\u00b7\u00b7\u00b7', @@ -891,6 +910,7 @@ suite('viewLineRenderer.renderLine 2', () => { ], 0, 'boundary', + null, [ '', '\u2192\u00a0\u00a0\u00a0', @@ -913,6 +933,7 @@ suite('viewLineRenderer.renderLine 2', () => { ], 0, 'boundary', + null, [ '', '\u00b7\u00b7\u2192\u00a0', @@ -940,6 +961,7 @@ suite('viewLineRenderer.renderLine 2', () => { ], 2, 'boundary', + null, [ '', '\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0', @@ -966,6 +988,7 @@ suite('viewLineRenderer.renderLine 2', () => { ], 2, 'boundary', + null, [ '', '\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0', @@ -989,6 +1012,7 @@ suite('viewLineRenderer.renderLine 2', () => { ], 0, 'boundary', + null, [ '', 'it', @@ -1014,6 +1038,7 @@ suite('viewLineRenderer.renderLine 2', () => { ], 0, 'all', + null, [ '', '\u00b7', @@ -1027,6 +1052,147 @@ suite('viewLineRenderer.renderLine 2', () => { ); }); + test('createLineParts render whitespace for selection with no selections', () => { + testCreateLineParts( + false, + ' Hello world!\t', + [ + createPart(4, 0), + createPart(6, 1), + createPart(14, 2) + ], + 0, + 'selection', + null, + [ + '', + '\u00a0Hel', + 'lo', + '\u00a0world!\u00a0\u00a0\u00a0', + '', + ].join('') + ); + }); + + test('createLineParts render whitespace for selection with whole line selection', () => { + testCreateLineParts( + false, + ' Hello world!\t', + [ + createPart(4, 0), + createPart(6, 1), + createPart(14, 2) + ], + 0, + 'selection', + [new LineRange(0, 14)], + [ + '', + '\u00b7', + 'Hel', + 'lo', + '\u00b7', + 'world!', + '\u2192\u00a0\u00a0', + '', + ].join('') + ); + }); + + test('createLineParts render whitespace for selection with selection spanning part of whitespace', () => { + testCreateLineParts( + false, + ' Hello world!\t', + [ + createPart(4, 0), + createPart(6, 1), + createPart(14, 2) + ], + 0, + 'selection', + [new LineRange(0, 5)], + [ + '', + '\u00b7', + 'Hel', + 'lo', + '\u00a0world!\u00a0\u00a0\u00a0', + '', + ].join('') + ); + }); + + + test('createLineParts render whitespace for selection with multiple selections', () => { + testCreateLineParts( + false, + ' Hello world!\t', + [ + createPart(4, 0), + createPart(6, 1), + createPart(14, 2) + ], + 0, + 'selection', + [new LineRange(0, 5), new LineRange(9, 14)], + [ + '', + '\u00b7', + 'Hel', + 'lo', + '\u00a0world!', + '\u2192\u00a0\u00a0', + '', + ].join('') + ); + }); + + + test('createLineParts render whitespace for selection with multiple, initially unsorted selections', () => { + testCreateLineParts( + false, + ' Hello world!\t', + [ + createPart(4, 0), + createPart(6, 1), + createPart(14, 2) + ], + 0, + 'selection', + [new LineRange(9, 14), new LineRange(0, 5)], + [ + '', + '\u00b7', + 'Hel', + 'lo', + '\u00a0world!', + '\u2192\u00a0\u00a0', + '', + ].join('') + ); + }); + + test('createLineParts render whitespace for selection with selections next to each other', () => { + testCreateLineParts( + false, + ' * S', + [ + createPart(4, 0) + ], + 0, + 'selection', + [new LineRange(0, 1), new LineRange(1, 2), new LineRange(2, 3)], + [ + '', + '\u00b7', + '*', + '\u00b7', + 'S', + '', + ].join('') + ); + }); + test('createLineParts can handle unsorted inline decorations', () => { let actual = renderViewLine(new RenderLineInput( false, @@ -1047,7 +1213,8 @@ suite('viewLineRenderer.renderLine 2', () => { -1, 'none', false, - false + false, + null )); // 01234567890 @@ -1087,7 +1254,8 @@ suite('viewLineRenderer.renderLine 2', () => { -1, 'all', false, - true + true, + null )); let expected = [ @@ -1119,7 +1287,8 @@ suite('viewLineRenderer.renderLine 2', () => { -1, 'all', false, - true + true, + null )); let expected = [ @@ -1152,7 +1321,8 @@ suite('viewLineRenderer.renderLine 2', () => { -1, 'all', false, - true + true, + null )); let expected = [ @@ -1181,7 +1351,8 @@ suite('viewLineRenderer.renderLine 2', () => { 10000, 'none', false, - false + false, + null )); let expected = [ @@ -1214,7 +1385,8 @@ suite('viewLineRenderer.renderLine 2', () => { 10000, 'none', false, - false + false, + null )); let expected = [ @@ -1246,7 +1418,8 @@ suite('viewLineRenderer.renderLine 2', () => { 10000, 'none', false, - false + false, + null )); let expected = [ @@ -1276,7 +1449,8 @@ suite('viewLineRenderer.renderLine 2', () => { 10000, 'none', false, - false + false, + null )); let expected = [ @@ -1305,7 +1479,8 @@ suite('viewLineRenderer.renderLine 2', () => { 10000, 'all', false, - false + false, + null )); let expected = [ @@ -1340,7 +1515,8 @@ suite('viewLineRenderer.renderLine 2', () => { 10000, 'none', false, - false + false, + null )); let expected = [ @@ -1369,7 +1545,8 @@ suite('viewLineRenderer.renderLine 2', () => { 10000, 'none', false, - false + false, + null )); let expected = [ @@ -1400,7 +1577,8 @@ suite('viewLineRenderer.renderLine 2', () => { 10000, 'none', false, - false + false, + null )); let expected = [ @@ -1430,7 +1608,8 @@ suite('viewLineRenderer.renderLine 2', () => { 10000, 'boundary', false, - false + false, + null )); let expected = [ @@ -1458,7 +1637,8 @@ suite('viewLineRenderer.renderLine 2', () => { 10000, 'none', false, - true + true, + null )); let expected = [ @@ -1490,7 +1670,8 @@ suite('viewLineRenderer.renderLine 2', () => { 10000, 'none', false, - true + true, + null )); let expected = [ @@ -1518,7 +1699,8 @@ suite('viewLineRenderer.renderLine 2', () => { -1, 'none', false, - false + false, + null )); return (partIndex: number, partLength: number, offset: number, expected: number) => { diff --git a/src/vs/editor/test/node/classification/typescript-test.ts b/src/vs/editor/test/node/classification/typescript-test.ts new file mode 100644 index 000000000..f8c68e4ee --- /dev/null +++ b/src/vs/editor/test/node/classification/typescript-test.ts @@ -0,0 +1,71 @@ +/// +/* tslint:disable */ +const x01 = "string"; +/// ^^^^^^^^ string + +const x02 = '\''; +/// ^^^^ string + +const x03 = '\n\'\t'; +/// ^^^^^^^^ string + +const x04 = 'this is\ +/// ^^^^^^^^^ string\ +a multiline string'; +/// <------------------- string + +const x05 = x01;// just some text +/// ^^^^^^^^^^^^^^^^^ comment + +const x06 = x05;/* multi +/// ^^^^^^^^ comment +line *comment */ +/// <---------------- comment + +const x07 = 4 / 5; + +const x08 = `howdy`; +/// ^^^^^^^ string + +const x09 = `\'\"\``; +/// ^^^^^^^^ string + +const x10 = `$[]`; +/// ^^^^^ string + +const x11 = `${x07 +/**/3}px`; +/// ^^^ string +/// ^^^^ comment +/// ^^^^ string + +const x12 = `${x07 + (function () { return 5; })()/**/}px`; +/// ^^^ string +/// ^^^^ comment +/// ^^^^ string + +const x13 = /([\w\-]+)?(#([\w\-]+))?((.([\w\-]+))*)/; +/// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ regex + +const x14 = /\./g; +/// ^^^^^ regex + + +const x15 = Math.abs(x07) / x07; // speed +/// ^^^^^^^^ comment + +const x16 = / x07; /.test('3'); +/// ^^^^^^^^ regex +/// ^^^ string + +const x17 = `.dialog-modal-block${true ? '.dimmed' : ''}`; +/// ^^^^^^^^^^^^^^^^^^^^^^ string +/// ^^^^^^^^^ string +/// ^^^^ string + +const x18 = Math.min((14 <= 0.5 ? 123 / (2 * 1) : ''.length / (2 - (2 * 1))), 1); +/// ^^ string + +const x19 = `${3 / '5'.length} km/h)`; +/// ^^^ string +/// ^^^ string +/// ^^^^^^^ string diff --git a/src/vs/editor/test/node/classification/typescript.test.ts b/src/vs/editor/test/node/classification/typescript.test.ts new file mode 100644 index 000000000..b5290f225 --- /dev/null +++ b/src/vs/editor/test/node/classification/typescript.test.ts @@ -0,0 +1,140 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { StandardTokenType } from 'vs/editor/common/modes'; +import * as fs from 'fs'; +// import { getPathFromAmdModule } from 'vs/base/common/amd'; +// import { parse } from 'vs/editor/common/modes/tokenization/typescript'; +import { toStandardTokenType } from 'vs/editor/common/modes/supports/tokenization'; + +interface IParseFunc { + (text: string): number[]; +} + +interface IAssertion { + testLineNumber: number; + startOffset: number; + length: number; + tokenType: StandardTokenType; +} + +interface ITest { + content: string; + assertions: IAssertion[]; +} + +function parseTest(fileName: string): ITest { + interface ILineWithAssertions { + line: string; + assertions: ILineAssertion[]; + } + + interface ILineAssertion { + testLineNumber: number; + startOffset: number; + length: number; + expectedTokenType: StandardTokenType; + } + + const testContents = fs.readFileSync(fileName).toString(); + const lines = testContents.split(/\r\n|\n/); + const magicToken = lines[0]; + + let currentElement: ILineWithAssertions = { + line: lines[1], + assertions: [] + }; + + let parsedTest: ILineWithAssertions[] = []; + for (let i = 2; i < lines.length; i++) { + let line = lines[i]; + if (line.substr(0, magicToken.length) === magicToken) { + // this is an assertion line + let m1 = line.substr(magicToken.length).match(/^( +)([\^]+) (\w+)\\?$/); + if (m1) { + currentElement.assertions.push({ + testLineNumber: i + 1, + startOffset: magicToken.length + m1[1].length, + length: m1[2].length, + expectedTokenType: toStandardTokenType(m1[3]) + }); + } else { + let m2 = line.substr(magicToken.length).match(/^( +)<(-+) (\w+)\\?$/); + if (m2) { + currentElement.assertions.push({ + testLineNumber: i + 1, + startOffset: 0, + length: m2[2].length, + expectedTokenType: toStandardTokenType(m2[3]) + }); + } else { + throw new Error(`Invalid test line at line number ${i + 1}.`); + } + } + } else { + // this is a line to be parsed + parsedTest.push(currentElement); + currentElement = { + line: line, + assertions: [] + }; + } + } + parsedTest.push(currentElement); + + let assertions: IAssertion[] = []; + + let offset = 0; + for (let i = 0; i < parsedTest.length; i++) { + const parsedTestLine = parsedTest[i]; + for (let j = 0; j < parsedTestLine.assertions.length; j++) { + const assertion = parsedTestLine.assertions[j]; + assertions.push({ + testLineNumber: assertion.testLineNumber, + startOffset: offset + assertion.startOffset, + length: assertion.length, + tokenType: assertion.expectedTokenType + }); + } + offset += parsedTestLine.line.length + 1; + } + + let content: string = parsedTest.map(parsedTestLine => parsedTestLine.line).join('\n'); + + return { content, assertions }; +} + +// @ts-ignore +function executeTest(fileName: string, parseFunc: IParseFunc): void { + const { content, assertions } = parseTest(fileName); + const actual = parseFunc(content); + + let actualIndex = 0, actualCount = actual.length / 3; + for (let i = 0; i < assertions.length; i++) { + const assertion = assertions[i]; + while (actualIndex < actualCount && actual[3 * actualIndex] + actual[3 * actualIndex + 1] <= assertion.startOffset) { + actualIndex++; + } + assert.ok( + actual[3 * actualIndex] <= assertion.startOffset, + `Line ${assertion.testLineNumber} : startOffset : ${actual[3 * actualIndex]} <= ${assertion.startOffset}` + ); + assert.ok( + actual[3 * actualIndex] + actual[3 * actualIndex + 1] >= assertion.startOffset + assertion.length, + `Line ${assertion.testLineNumber} : length : ${actual[3 * actualIndex]} + ${actual[3 * actualIndex + 1]} >= ${assertion.startOffset} + ${assertion.length}.` + ); + assert.equal( + actual[3 * actualIndex + 2], + assertion.tokenType, + `Line ${assertion.testLineNumber} : tokenType`); + } +} + +suite('Classification', () => { + test('TypeScript', () => { + // executeTest(getPathFromAmdModule(require, 'vs/editor/test/node/classification/typescript-test.ts').replace(/\bout\b/, 'src'), parse); + }); +}); diff --git a/src/vs/loader.js b/src/vs/loader.js index 4eddcab3a..8445bbeff 100644 --- a/src/vs/loader.js +++ b/src/vs/loader.js @@ -23,7 +23,7 @@ var _commonjsGlobal = typeof global === 'object' ? global : {}; var AMDLoader; (function (AMDLoader) { AMDLoader.global = _amdLoaderGlobal; - var Environment = (function () { + var Environment = /** @class */ (function () { function Environment() { this._detected = false; this._isWindows = false; @@ -94,7 +94,7 @@ var AMDLoader; *--------------------------------------------------------------------------------------------*/ var AMDLoader; (function (AMDLoader) { - var LoaderEvent = (function () { + var LoaderEvent = /** @class */ (function () { function LoaderEvent(type, detail, timestamp) { this.type = type; this.detail = detail; @@ -103,7 +103,7 @@ var AMDLoader; return LoaderEvent; }()); AMDLoader.LoaderEvent = LoaderEvent; - var LoaderEventRecorder = (function () { + var LoaderEventRecorder = /** @class */ (function () { function LoaderEventRecorder(loaderAvailableTimestamp) { this._events = [new LoaderEvent(1 /* LoaderAvailable */, '', loaderAvailableTimestamp)]; } @@ -116,7 +116,7 @@ var AMDLoader; return LoaderEventRecorder; }()); AMDLoader.LoaderEventRecorder = LoaderEventRecorder; - var NullLoaderEventRecorder = (function () { + var NullLoaderEventRecorder = /** @class */ (function () { function NullLoaderEventRecorder() { } NullLoaderEventRecorder.prototype.record = function (type, detail) { @@ -125,9 +125,9 @@ var AMDLoader; NullLoaderEventRecorder.prototype.getEvents = function () { return []; }; + NullLoaderEventRecorder.INSTANCE = new NullLoaderEventRecorder(); return NullLoaderEventRecorder; }()); - NullLoaderEventRecorder.INSTANCE = new NullLoaderEventRecorder(); AMDLoader.NullLoaderEventRecorder = NullLoaderEventRecorder; })(AMDLoader || (AMDLoader = {})); /*--------------------------------------------------------------------------------------------- @@ -136,7 +136,7 @@ var AMDLoader; *--------------------------------------------------------------------------------------------*/ var AMDLoader; (function (AMDLoader) { - var Utilities = (function () { + var Utilities = /** @class */ (function () { function Utilities() { } /** @@ -222,11 +222,11 @@ var AMDLoader; } return (this.HAS_PERFORMANCE_NOW ? AMDLoader.global.performance.now() : Date.now()); }; + Utilities.NEXT_ANONYMOUS_ID = 1; + Utilities.PERFORMANCE_NOW_PROBED = false; + Utilities.HAS_PERFORMANCE_NOW = false; return Utilities; }()); - Utilities.NEXT_ANONYMOUS_ID = 1; - Utilities.PERFORMANCE_NOW_PROBED = false; - Utilities.HAS_PERFORMANCE_NOW = false; AMDLoader.Utilities = Utilities; })(AMDLoader || (AMDLoader = {})); /*--------------------------------------------------------------------------------------------- @@ -235,7 +235,19 @@ var AMDLoader; *--------------------------------------------------------------------------------------------*/ var AMDLoader; (function (AMDLoader) { - var ConfigurationOptionsUtil = (function () { + function ensureError(err) { + if (err instanceof Error) { + return err; + } + var result = new Error(err.message || String(err) || 'Unknown Error'); + if (err.stack) { + result.stack = err.stack; + } + return result; + } + AMDLoader.ensureError = ensureError; + ; + var ConfigurationOptionsUtil = /** @class */ (function () { function ConfigurationOptionsUtil() { } /** @@ -243,22 +255,16 @@ var AMDLoader; */ ConfigurationOptionsUtil.validateConfigurationOptions = function (options) { function defaultOnError(err) { - if (err.errorCode === 'load') { + if (err.phase === 'loading') { console.error('Loading "' + err.moduleId + '" failed'); - console.error('Detail: ', err.detail); - if (err.detail && err.detail.stack) { - console.error(err.detail.stack); - } + console.error(err); console.error('Here are the modules that depend on it:'); console.error(err.neededBy); return; } - if (err.errorCode === 'factory') { + if (err.phase === 'factory') { console.error('The factory method of "' + err.moduleId + '" has thrown an exception'); - console.error(err.detail); - if (err.detail && err.detail.stack) { - console.error(err.detail.stack); - } + console.error(err); return; } } @@ -278,13 +284,16 @@ var AMDLoader; if (typeof options.catchError === 'undefined') { options.catchError = false; } + if (typeof options.recordStats === 'undefined') { + options.recordStats = false; + } if (typeof options.urlArgs !== 'string') { options.urlArgs = ''; } if (typeof options.onError !== 'function') { options.onError = defaultOnError; } - if (typeof options.ignoreDuplicateModules !== 'object' || !Array.isArray(options.ignoreDuplicateModules)) { + if (!Array.isArray(options.ignoreDuplicateModules)) { options.ignoreDuplicateModules = []; } if (options.baseUrl.length > 0) { @@ -298,29 +307,17 @@ var AMDLoader; if (!Array.isArray(options.nodeModules)) { options.nodeModules = []; } - if (typeof options.nodeCachedData === 'object') { + if (options.nodeCachedData && typeof options.nodeCachedData === 'object') { if (typeof options.nodeCachedData.seed !== 'string') { options.nodeCachedData.seed = 'seed'; } if (typeof options.nodeCachedData.writeDelay !== 'number' || options.nodeCachedData.writeDelay < 0) { options.nodeCachedData.writeDelay = 1000 * 7; } - if (typeof options.nodeCachedData.onData !== 'function') { - options.nodeCachedData.onData = function (err) { - if (err && err.errorCode === 'cachedDataRejected') { - console.warn('Rejected cached data from file: ' + err.path); - } - else if (err && err.errorCode) { - console.error('Problems handling cached data file: ' + err.path); - console.error(err.detail); - } - else if (err) { - console.error(err); - } - }; - } if (!options.nodeCachedData.path || typeof options.nodeCachedData.path !== 'string') { - options.nodeCachedData.onData('INVALID cached data configuration, \'path\' MUST be set'); + var err = ensureError(new Error('INVALID cached data configuration, \'path\' MUST be set')); + err.phase = 'configuration'; + options.onError(err); options.nodeCachedData = undefined; } } @@ -350,7 +347,7 @@ var AMDLoader; return ConfigurationOptionsUtil; }()); AMDLoader.ConfigurationOptionsUtil = ConfigurationOptionsUtil; - var Configuration = (function () { + var Configuration = /** @class */ (function () { function Configuration(env, options) { this._env = env; this.options = ConfigurationOptionsUtil.mergeConfigurationOptions(options); @@ -561,7 +558,7 @@ var AMDLoader; /** * Load `scriptSrc` only once (avoid multiple + + + + \ No newline at end of file diff --git a/src/vs/workbench/contrib/webview/browser/pre/main.js b/src/vs/workbench/contrib/webview/browser/pre/main.js index 133b3d28e..63585fc25 100644 --- a/src/vs/workbench/contrib/webview/browser/pre/main.js +++ b/src/vs/workbench/contrib/webview/browser/pre/main.js @@ -3,41 +3,54 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // @ts-check -'use strict'; /** - * Use polling to track focus of main webview and iframes within the webview - * - * @param {Object} handlers - * @param {() => void} handlers.onFocus - * @param {() => void} handlers.onBlur + * @typedef {{ + * postMessage: (channel: string, data?: any) => void, + * onMessage: (channel: string, handler: any) => void, + * focusIframeOnCreate?: boolean, + * ready?: Promise, + * onIframeLoaded?: (iframe: HTMLIFrameElement) => void, + * fakeLoad: boolean + * }} WebviewHost */ -const trackFocus = ({ onFocus, onBlur }) => { - const interval = 50; - let isFocused = document.hasFocus(); - setInterval(() => { - const isCurrentlyFocused = document.hasFocus(); - if (isCurrentlyFocused === isFocused) { - return; - } - isFocused = isCurrentlyFocused; - if (isCurrentlyFocused) { - onFocus(); - } else { - onBlur(); - } - }, interval); -}; -const getActiveFrame = () => { - return /** @type {HTMLIFrameElement} */ (document.getElementById('active-frame')); -}; +(function () { + 'use strict'; -const getPendingFrame = () => { - return /** @type {HTMLIFrameElement} */ (document.getElementById('pending-frame')); -}; + /** + * Use polling to track focus of main webview and iframes within the webview + * + * @param {Object} handlers + * @param {() => void} handlers.onFocus + * @param {() => void} handlers.onBlur + */ + const trackFocus = ({ onFocus, onBlur }) => { + const interval = 50; + let isFocused = document.hasFocus(); + setInterval(() => { + const isCurrentlyFocused = document.hasFocus(); + if (isCurrentlyFocused === isFocused) { + return; + } + isFocused = isCurrentlyFocused; + if (isCurrentlyFocused) { + onFocus(); + } else { + onBlur(); + } + }, interval); + }; -const defaultCssRules = ` + const getActiveFrame = () => { + return /** @type {HTMLIFrameElement} */ (document.getElementById('active-frame')); + }; + + const getPendingFrame = () => { + return /** @type {HTMLIFrameElement} */ (document.getElementById('pending-frame')); + }; + + const defaultCssRules = ` body { background-color: var(--vscode-editor-background); color: var(--vscode-editor-foreground); @@ -93,151 +106,156 @@ const defaultCssRules = ` background-color: var(--vscode-scrollbarSlider-activeBackground); }`; -/** - * @typedef {{ postMessage: (channel: string, data?: any) => void, onMessage: (channel: string, handler: any) => void }} HostCommunications - */ - -/** - * @param {HostCommunications} host - */ -module.exports = function createWebviewManager(host) { - // state - let firstLoad = true; - let loadTimeout; - let pendingMessages = []; - let isInDevelopmentMode = false; - - const initData = { - initialScrollProgress: undefined - }; + /** + * @param {*} [state] + * @return {string} + */ + function getVsCodeApiScript(state) { + return ` + const acquireVsCodeApi = (function() { + const originalPostMessage = window.parent.postMessage.bind(window.parent); + const targetOrigin = '*'; + let acquired = false; + + let state = ${state ? `JSON.parse(${JSON.stringify(state)})` : undefined}; + + return () => { + if (acquired) { + throw new Error('An instance of the VS Code API has already been acquired'); + } + acquired = true; + return Object.freeze({ + postMessage: function(msg) { + return originalPostMessage({ command: 'onmessage', data: msg }, targetOrigin); + }, + setState: function(newState) { + state = newState; + originalPostMessage({ command: 'do-update-state', data: JSON.stringify(newState) }, targetOrigin); + return newState; + }, + getState: function() { + return state; + } + }); + }; + })(); + delete window.parent; + delete window.top; + delete window.frameElement; + `; + } /** - * @param {HTMLDocument?} document - * @param {HTMLElement?} body + * @param {WebviewHost} host */ - const applyStyles = (document, body) => { - if (!document) { - return; - } + function createWebviewManager(host) { + // state + let firstLoad = true; + let loadTimeout; + let pendingMessages = []; + + const initData = { + initialScrollProgress: undefined + }; + + + /** + * @param {HTMLDocument?} document + * @param {HTMLElement?} body + */ + const applyStyles = (document, body) => { + if (!document) { + return; + } - if (body) { - body.classList.remove('vscode-light', 'vscode-dark', 'vscode-high-contrast'); - body.classList.add(initData.activeTheme); - } + if (body) { + body.classList.remove('vscode-light', 'vscode-dark', 'vscode-high-contrast'); + body.classList.add(initData.activeTheme); + } - if (initData.styles) { - for (const variable of Object.keys(initData.styles)) { - document.documentElement.style.setProperty(`--${variable}`, initData.styles[variable]); + if (initData.styles) { + for (const variable of Object.keys(initData.styles)) { + document.documentElement.style.setProperty(`--${variable}`, initData.styles[variable]); + } } - } - }; + }; - /** - * @param {MouseEvent} event - */ - const handleInnerClick = (event) => { - if (!event || !event.view || !event.view.document) { - return; - } + /** + * @param {MouseEvent} event + */ + const handleInnerClick = (event) => { + if (!event || !event.view || !event.view.document) { + return; + } - let baseElement = event.view.document.getElementsByTagName('base')[0]; - /** @type {any} */ - let node = event.target; - while (node) { - if (node.tagName && node.tagName.toLowerCase() === 'a' && node.href) { - if (node.getAttribute('href') === '#') { - event.view.scrollTo(0, 0); - } else if (node.hash && (node.getAttribute('href') === node.hash || (baseElement && node.href.indexOf(baseElement.href) >= 0))) { - let scrollTarget = event.view.document.getElementById(node.hash.substr(1, node.hash.length - 1)); - if (scrollTarget) { - scrollTarget.scrollIntoView(); + let baseElement = event.view.document.getElementsByTagName('base')[0]; + /** @type {any} */ + let node = event.target; + while (node) { + if (node.tagName && node.tagName.toLowerCase() === 'a' && node.href) { + if (node.getAttribute('href') === '#') { + event.view.scrollTo(0, 0); + } else if (node.hash && (node.getAttribute('href') === node.hash || (baseElement && node.href.indexOf(baseElement.href) >= 0))) { + let scrollTarget = event.view.document.getElementById(node.hash.substr(1, node.hash.length - 1)); + if (scrollTarget) { + scrollTarget.scrollIntoView(); + } + } else { + host.postMessage('did-click-link', node.href.baseVal || node.href); } - } else { - host.postMessage('did-click-link', node.href); + event.preventDefault(); + break; } - event.preventDefault(); - break; + node = node.parentNode; } - node = node.parentNode; - } - }; - - /** - * @param {KeyboardEvent} e - */ - const handleInnerKeydown = (e) => { - host.postMessage('did-keydown', { - key: e.key, - keyCode: e.keyCode, - code: e.code, - shiftKey: e.shiftKey, - altKey: e.altKey, - ctrlKey: e.ctrlKey, - metaKey: e.metaKey, - repeat: e.repeat - }); - }; - - const onMessage = (message) => { - host.postMessage(message.data.command, message.data.data); - }; - - let isHandlingScroll = false; - const handleInnerScroll = (event) => { - if (!event.target || !event.target.body) { - return; - } - if (isHandlingScroll) { - return; - } - - const progress = event.currentTarget.scrollY / event.target.body.clientHeight; - if (isNaN(progress)) { - return; - } + }; + + /** + * @param {KeyboardEvent} e + */ + const handleInnerKeydown = (e) => { + host.postMessage('did-keydown', { + key: e.key, + keyCode: e.keyCode, + code: e.code, + shiftKey: e.shiftKey, + altKey: e.altKey, + ctrlKey: e.ctrlKey, + metaKey: e.metaKey, + repeat: e.repeat + }); + }; - isHandlingScroll = true; - window.requestAnimationFrame(() => { - try { - host.postMessage('did-scroll', progress); - } catch (e) { - // noop + let isHandlingScroll = false; + const handleInnerScroll = (event) => { + if (!event.target || !event.target.body) { + return; } - isHandlingScroll = false; - }); - }; - - document.addEventListener('DOMContentLoaded', () => { - if (!document.body) { - return; - } - - host.onMessage('styles', (_event, variables, activeTheme) => { - initData.styles = variables; - initData.activeTheme = activeTheme; - - const target = getActiveFrame(); - if (!target) { + if (isHandlingScroll) { return; } - if (target.contentDocument) { - applyStyles(target.contentDocument, target.contentDocument.body); + const progress = event.currentTarget.scrollY / event.target.body.clientHeight; + if (isNaN(progress)) { + return; } - }); - // propagate focus - host.onMessage('focus', () => { - const target = getActiveFrame(); - if (target) { - target.contentWindow.focus(); - } - }); + isHandlingScroll = true; + window.requestAnimationFrame(() => { + try { + host.postMessage('did-scroll', progress); + } catch (e) { + // noop + } + isHandlingScroll = false; + }); + }; - // update iframe-contents - host.onMessage('content', (_event, data) => { + /** + * @return {string} + */ + function toContentHtml(data) { const options = data.options; - const text = data.contents; const newDocument = new DOMParser().parseFromString(text, 'text/html'); @@ -250,38 +268,7 @@ module.exports = function createWebviewManager(host) { // apply default script if (options.allowScripts) { const defaultScript = newDocument.createElement('script'); - defaultScript.textContent = ` - const acquireVsCodeApi = (function() { - const originalPostMessage = window.parent.postMessage.bind(window.parent); - let acquired = false; - - let state = ${data.state ? `JSON.parse(${JSON.stringify(data.state)})` : undefined}; - - return () => { - if (acquired) { - throw new Error('An instance of the VS Code API has already been acquired'); - } - acquired = true; - return Object.freeze({ - postMessage: function(msg) { - return originalPostMessage({ command: 'onmessage', data: msg }, '*'); - }, - setState: function(newState) { - state = newState; - originalPostMessage({ command: 'do-update-state', data: JSON.stringify(newState) }, '*'); - return newState; - }, - getState: function() { - return state; - } - }); - }; - })(); - delete window.parent; - delete window.top; - delete window.frameElement; - `; - + defaultScript.textContent = getVsCodeApiScript(data.state); newDocument.head.prepend(defaultScript); } @@ -293,154 +280,219 @@ module.exports = function createWebviewManager(host) { applyStyles(newDocument, newDocument.body); - const frame = getActiveFrame(); - const wasFirstLoad = firstLoad; - // keep current scrollY around and use later - let setInitialScrollPosition; - if (firstLoad) { - firstLoad = false; - setInitialScrollPosition = (body, window) => { - if (!isNaN(initData.initialScrollProgress)) { - if (window.scrollY === 0) { - window.scroll(0, body.clientHeight * initData.initialScrollProgress); - } - } - }; - } else { - const scrollY = frame && frame.contentDocument && frame.contentDocument.body ? frame.contentWindow.scrollY : 0; - setInitialScrollPosition = (body, window) => { - if (window.scrollY === 0) { - window.scroll(0, scrollY); - } - }; - } + // set DOCTYPE for newDocument explicitly as DOMParser.parseFromString strips it off + // and DOCTYPE is needed in the iframe to ensure that the user agent stylesheet is correctly overridden + return '\n' + newDocument.documentElement.outerHTML; + } - // Clean up old pending frames and set current one as new one - const previousPendingFrame = getPendingFrame(); - if (previousPendingFrame) { - previousPendingFrame.setAttribute('id', ''); - document.body.removeChild(previousPendingFrame); - } - if (!wasFirstLoad) { - pendingMessages = []; + document.addEventListener('DOMContentLoaded', () => { + const idMatch = document.location.search.match(/\bid=([\w-]+)/); + const ID = idMatch ? idMatch[1] : undefined; + if (!document.body) { + return; } - const newFrame = document.createElement('iframe'); - newFrame.setAttribute('id', 'pending-frame'); - newFrame.setAttribute('frameborder', '0'); - newFrame.setAttribute('sandbox', options.allowScripts ? 'allow-scripts allow-forms allow-same-origin' : 'allow-same-origin'); - newFrame.style.cssText = 'display: block; margin: 0; overflow: hidden; position: absolute; width: 100%; height: 100%; visibility: hidden'; - document.body.appendChild(newFrame); + host.onMessage('styles', (_event, data) => { + initData.styles = data.styles; + initData.activeTheme = data.activeTheme; - // write new content onto iframe - newFrame.contentDocument.open('text/html', 'replace'); + const target = getActiveFrame(); + if (!target) { + return; + } - newFrame.contentWindow.addEventListener('keydown', handleInnerKeydown); + if (target.contentDocument) { + applyStyles(target.contentDocument, target.contentDocument.body); + } + }); - newFrame.contentWindow.addEventListener('DOMContentLoaded', e => { - const contentDocument = e.target ? (/** @type {HTMLDocument} */ (e.target)) : undefined; - if (contentDocument) { - applyStyles(contentDocument, contentDocument.body); + // propagate focus + host.onMessage('focus', () => { + const target = getActiveFrame(); + if (target) { + target.contentWindow.focus(); } }); - newFrame.contentWindow.onbeforeunload = () => { - if (isInDevelopmentMode) { // Allow reloads while developing a webview - host.postMessage('do-reload'); - return false; + // update iframe-contents + let updateId = 0; + host.onMessage('content', async (_event, data) => { + const currentUpdateId = ++updateId; + await host.ready; + if (currentUpdateId !== updateId) { + return; + } + + const options = data.options; + const newDocument = toContentHtml(data); + + const frame = getActiveFrame(); + const wasFirstLoad = firstLoad; + // keep current scrollY around and use later + let setInitialScrollPosition; + if (firstLoad) { + firstLoad = false; + setInitialScrollPosition = (body, window) => { + if (!isNaN(initData.initialScrollProgress)) { + if (window.scrollY === 0) { + window.scroll(0, body.clientHeight * initData.initialScrollProgress); + } + } + }; + } else { + const scrollY = frame && frame.contentDocument && frame.contentDocument.body ? frame.contentWindow.scrollY : 0; + setInitialScrollPosition = (body, window) => { + if (window.scrollY === 0) { + window.scroll(0, scrollY); + } + }; + } + + // Clean up old pending frames and set current one as new one + const previousPendingFrame = getPendingFrame(); + if (previousPendingFrame) { + previousPendingFrame.setAttribute('id', ''); + document.body.removeChild(previousPendingFrame); + } + if (!wasFirstLoad) { + pendingMessages = []; } - // Block navigation when not in development mode - console.log('prevented webview navigation'); - return false; - }; + const newFrame = document.createElement('iframe'); + newFrame.setAttribute('id', 'pending-frame'); + newFrame.setAttribute('frameborder', '0'); + newFrame.setAttribute('sandbox', options.allowScripts ? 'allow-scripts allow-forms allow-same-origin' : 'allow-same-origin'); + if (host.fakeLoad) { + // We should just be able to use srcdoc, but I wasn't + // seeing the service worker applying properly. + // Fake load an empty on the correct origin and then write real html + // into it to get around this. + newFrame.src = `./fake.html?id=${ID}`; + } + newFrame.style.cssText = 'display: block; margin: 0; overflow: hidden; position: absolute; width: 100%; height: 100%; visibility: hidden'; + document.body.appendChild(newFrame); - const onLoad = (contentDocument, contentWindow) => { - if (contentDocument && contentDocument.body) { - // Workaround for https://github.com/Microsoft/vscode/issues/12865 - // check new scrollY and reset if neccessary - setInitialScrollPosition(contentDocument.body, contentWindow); + if (!host.fakeLoad) { + // write new content onto iframe + newFrame.contentDocument.open(); } - const newFrame = getPendingFrame(); - if (newFrame && newFrame.contentDocument && newFrame.contentDocument === contentDocument) { - const oldActiveFrame = getActiveFrame(); - if (oldActiveFrame) { - document.body.removeChild(oldActiveFrame); + newFrame.contentWindow.addEventListener('keydown', handleInnerKeydown); + + newFrame.contentWindow.addEventListener('DOMContentLoaded', e => { + if (host.fakeLoad) { + newFrame.contentDocument.open(); + newFrame.contentDocument.write(newDocument); + newFrame.contentDocument.close(); + hookupOnLoadHandlers(newFrame); + } + const contentDocument = e.target ? (/** @type {HTMLDocument} */ (e.target)) : undefined; + if (contentDocument) { + applyStyles(contentDocument, contentDocument.body); } - // Styles may have changed since we created the element. Make sure we re-style - applyStyles(newFrame.contentDocument, newFrame.contentDocument.body); - newFrame.setAttribute('id', 'active-frame'); - newFrame.style.visibility = 'visible'; - newFrame.contentWindow.focus(); + }); - contentWindow.addEventListener('scroll', handleInnerScroll); + const onLoad = (contentDocument, contentWindow) => { + if (contentDocument && contentDocument.body) { + // Workaround for https://github.com/Microsoft/vscode/issues/12865 + // check new scrollY and reset if neccessary + setInitialScrollPosition(contentDocument.body, contentWindow); + } - pendingMessages.forEach((data) => { - contentWindow.postMessage(data, '*'); - }); - pendingMessages = []; - } - }; - - clearTimeout(loadTimeout); - loadTimeout = undefined; - loadTimeout = setTimeout(() => { - clearTimeout(loadTimeout); - loadTimeout = undefined; - onLoad(newFrame.contentDocument, newFrame.contentWindow); - }, 200); - - newFrame.contentWindow.addEventListener('load', function (e) { - if (loadTimeout) { + const newFrame = getPendingFrame(); + if (newFrame && newFrame.contentDocument && newFrame.contentDocument === contentDocument) { + const oldActiveFrame = getActiveFrame(); + if (oldActiveFrame) { + document.body.removeChild(oldActiveFrame); + } + // Styles may have changed since we created the element. Make sure we re-style + applyStyles(newFrame.contentDocument, newFrame.contentDocument.body); + newFrame.setAttribute('id', 'active-frame'); + newFrame.style.visibility = 'visible'; + if (host.focusIframeOnCreate) { + newFrame.contentWindow.focus(); + } + + contentWindow.addEventListener('scroll', handleInnerScroll); + + pendingMessages.forEach((data) => { + contentWindow.postMessage(data, '*'); + }); + pendingMessages = []; + } + }; + + /** + * @param {HTMLIFrameElement} newFrame + */ + function hookupOnLoadHandlers(newFrame) { clearTimeout(loadTimeout); loadTimeout = undefined; - onLoad(e.target, this); + loadTimeout = setTimeout(() => { + clearTimeout(loadTimeout); + loadTimeout = undefined; + onLoad(newFrame.contentDocument, newFrame.contentWindow); + }, 200); + + newFrame.contentWindow.addEventListener('load', function (e) { + if (loadTimeout) { + clearTimeout(loadTimeout); + loadTimeout = undefined; + onLoad(e.target, this); + } + }); + + // Bubble out link clicks + newFrame.contentWindow.addEventListener('click', handleInnerClick); + + if (host.onIframeLoaded) { + host.onIframeLoaded(newFrame); + } } - }); - // Bubble out link clicks - newFrame.contentWindow.addEventListener('click', handleInnerClick); + if (!host.fakeLoad) { + hookupOnLoadHandlers(newFrame); + } - // set DOCTYPE for newDocument explicitly as DOMParser.parseFromString strips it off - // and DOCTYPE is needed in the iframe to ensure that the user agent stylesheet is correctly overridden - newFrame.contentDocument.write(''); - newFrame.contentDocument.write(newDocument.documentElement.innerHTML); - newFrame.contentDocument.close(); + if (!host.fakeLoad) { + newFrame.contentDocument.write(newDocument); + newFrame.contentDocument.close(); + } - host.postMessage('did-set-content', undefined); - }); + host.postMessage('did-set-content', undefined); + }); - // Forward message to the embedded iframe - host.onMessage('message', (_event, data) => { - const pending = getPendingFrame(); - if (!pending) { - const target = getActiveFrame(); - if (target) { - target.contentWindow.postMessage(data, '*'); - return; + // Forward message to the embedded iframe + host.onMessage('message', (_event, data) => { + const pending = getPendingFrame(); + if (!pending) { + const target = getActiveFrame(); + if (target) { + target.contentWindow.postMessage(data, '*'); + return; + } } - } - pendingMessages.push(data); - }); + pendingMessages.push(data); + }); - host.onMessage('initial-scroll-position', (_event, progress) => { - initData.initialScrollProgress = progress; - }); + host.onMessage('initial-scroll-position', (_event, progress) => { + initData.initialScrollProgress = progress; + }); - host.onMessage('devtools-opened', () => { - isInDevelopmentMode = true; - }); - trackFocus({ - onFocus: () => host.postMessage('did-focus'), - onBlur: () => host.postMessage('did-blur') - }); + trackFocus({ + onFocus: () => host.postMessage('did-focus'), + onBlur: () => host.postMessage('did-blur') + }); - // Forward messages from the embedded iframe - window.onmessage = onMessage; + // signal ready + host.postMessage('webview-ready', {}); + }); + } - // signal ready - host.postMessage('webview-ready', process.pid); - }); -}; + if (typeof module !== 'undefined') { + module.exports = createWebviewManager; + } else { + window.createWebviewManager = createWebviewManager; + } +}()); diff --git a/src/vs/workbench/contrib/webview/browser/pre/service-worker.js b/src/vs/workbench/contrib/webview/browser/pre/service-worker.js new file mode 100644 index 000000000..8d26680d7 --- /dev/null +++ b/src/vs/workbench/contrib/webview/browser/pre/service-worker.js @@ -0,0 +1,276 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +const VERSION = 1; + +const rootPath = self.location.pathname.replace(/\/service-worker.js$/, ''); + +/** + * Root path for resources + */ +const resourceRoot = rootPath + '/vscode-resource'; + +const resolveTimeout = 30000; + +/** + * @template T + * @typedef {{ + * resolve: (x: T) => void, + * promise: Promise + * }} RequestStoreEntry + */ + +/** + * @template T + */ +class RequestStore { + constructor() { + /** @type {Map>} */ + this.map = new Map(); + } + + /** + * @param {string} webviewId + * @param {string} path + * @return {Promise | undefined} + */ + get(webviewId, path) { + const entry = this.map.get(this._key(webviewId, path)); + return entry && entry.promise; + } + + /** + * @param {string} webviewId + * @param {string} path + * @returns {Promise} + */ + create(webviewId, path) { + const existing = this.get(webviewId, path); + if (existing) { + return existing; + } + let resolve; + const promise = new Promise(r => resolve = r); + const entry = { resolve, promise }; + const key = this._key(webviewId, path); + this.map.set(key, entry); + + const dispose = () => { + clearTimeout(timeout); + const existingEntry = this.map.get(key); + if (existingEntry === entry) { + return this.map.delete(key); + } + }; + const timeout = setTimeout(dispose, resolveTimeout); + return promise; + } + + /** + * @param {string} webviewId + * @param {string} path + * @param {T} result + * @return {boolean} + */ + resolve(webviewId, path, result) { + const entry = this.map.get(this._key(webviewId, path)); + if (!entry) { + return false; + } + entry.resolve(result); + return true; + } + + /** + * @param {string} webviewId + * @param {string} path + * @return {string} + */ + _key(webviewId, path) { + return `${webviewId}@@@${path}`; + } +} + +/** + * Map of requested paths to responses. + * + * @type {RequestStore<{ body: any, mime: string } | undefined>} + */ +const resourceRequestStore = new RequestStore(); + +/** + * Map of requested localhost origins to optional redirects. + * + * @type {RequestStore} + */ +const localhostRequestStore = new RequestStore(); + +const notFound = () => + new Response('Not Found', { status: 404, }); + +self.addEventListener('message', async (event) => { + switch (event.data.channel) { + case 'version': + { + self.clients.get(event.source.id).then(client => { + if (client) { + client.postMessage({ + channel: 'version', + version: VERSION + }); + } + }); + return; + } + case 'did-load-resource': + { + const webviewId = getWebviewIdForClient(event.source); + const data = event.data.data; + const response = data.status === 200 + ? { body: data.data, mime: data.mime } + : undefined; + + if (!resourceRequestStore.resolve(webviewId, data.path, response)) { + console.log('Could not resolve unknown resource', data.path); + } + return; + } + + case 'did-load-localhost': + { + const webviewId = getWebviewIdForClient(event.source); + const data = event.data.data; + if (!localhostRequestStore.resolve(webviewId, data.origin, data.location)) { + console.log('Could not resolve unknown localhost', data.origin); + } + return; + } + } + + console.log('Unknown message'); +}); + +self.addEventListener('fetch', (event) => { + const requestUrl = new URL(event.request.url); + + // See if it's a resource request + if (requestUrl.origin === self.origin && requestUrl.pathname.startsWith(resourceRoot + '/')) { + return event.respondWith(processResourceRequest(event, requestUrl)); + } + + // See if it's a localhost request + if (requestUrl.origin !== self.origin && requestUrl.host.match(/^localhost:(\d+)$/)) { + return event.respondWith(processLocalhostRequest(event, requestUrl)); + } +}); + +self.addEventListener('install', (event) => { + event.waitUntil(self.skipWaiting()); // Activate worker immediately +}); + +self.addEventListener('activate', (event) => { + event.waitUntil(self.clients.claim()); // Become available to all pages +}); + +async function processResourceRequest(event, requestUrl) { + const client = await self.clients.get(event.clientId); + if (!client) { + console.log('Could not find inner client for request'); + return notFound(); + } + + const webviewId = getWebviewIdForClient(client); + const resourcePath = requestUrl.pathname.startsWith(resourceRoot + '/') ? requestUrl.pathname.slice(resourceRoot.length) : requestUrl.pathname; + + function resolveResourceEntry(entry) { + if (!entry) { + return notFound(); + } + return new Response(entry.body, { + status: 200, + headers: { 'Content-Type': entry.mime } + }); + } + + const parentClient = await getOuterIframeClient(webviewId); + if (!parentClient) { + console.log('Could not find parent client for request'); + return notFound(); + } + + // Check if we've already resolved this request + const existing = resourceRequestStore.get(webviewId, resourcePath); + if (existing) { + return existing.then(resolveResourceEntry); + } + + parentClient.postMessage({ + channel: 'load-resource', + path: resourcePath + }); + + return resourceRequestStore.create(webviewId, resourcePath) + .then(resolveResourceEntry); +} + +/** + * @param {*} event + * @param {URL} requestUrl + */ +async function processLocalhostRequest(event, requestUrl) { + const client = await self.clients.get(event.clientId); + if (!client) { + // This is expected when requesting resources on other localhost ports + // that are not spawned by vs code + return undefined; + } + const webviewId = getWebviewIdForClient(client); + const origin = requestUrl.origin; + + const resolveRedirect = redirectOrigin => { + if (!redirectOrigin) { + return fetch(event.request); + } + const location = event.request.url.replace(new RegExp(`^${requestUrl.origin}(/|$)`), `${redirectOrigin}$1`); + return new Response(null, { + status: 302, + headers: { + Location: location + } + }); + }; + + const parentClient = await getOuterIframeClient(webviewId); + if (!parentClient) { + console.log('Could not find parent client for request'); + return notFound(); + } + + // Check if we've already resolved this request + const existing = localhostRequestStore.get(webviewId, origin); + if (existing) { + return existing.then(resolveRedirect); + } + + parentClient.postMessage({ + channel: 'load-localhost', + origin: origin + }); + + return localhostRequestStore.create(webviewId, origin) + .then(resolveRedirect); +} + +function getWebviewIdForClient(client) { + const requesterClientUrl = new URL(client.url); + return requesterClientUrl.search.match(/\bid=([a-z0-9-]+)/i)[1]; +} + +async function getOuterIframeClient(webviewId) { + const allClients = await self.clients.matchAll({ includeUncontrolled: true }); + return allClients.find(client => { + const clientUrl = new URL(client.url); + return (clientUrl.pathname === `${rootPath}/` || clientUrl.pathname === `${rootPath}/index.html`) && clientUrl.search.match(new RegExp('\\bid=' + webviewId)); + }); +} \ No newline at end of file diff --git a/src/vs/workbench/contrib/webview/browser/webview.contribution.ts b/src/vs/workbench/contrib/webview/browser/webview.contribution.ts index f05591890..40dac14b6 100644 --- a/src/vs/workbench/contrib/webview/browser/webview.contribution.ts +++ b/src/vs/workbench/contrib/webview/browser/webview.contribution.ts @@ -4,11 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import { isMacintosh } from 'vs/base/common/platform'; import { localize } from 'vs/nls'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { InputFocusedContextKey } from 'vs/platform/contextkey/common/contextkeys'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; @@ -17,8 +15,8 @@ import { EditorDescriptor, Extensions as EditorExtensions, IEditorRegistry } fro import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; import { Extensions as EditorInputExtensions, IEditorInputFactoryRegistry } from 'vs/workbench/common/editor'; import { WebviewEditorInputFactory } from 'vs/workbench/contrib/webview/browser/webviewEditorInputFactory'; -import { KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE } from 'vs/workbench/contrib/webview/common/webview'; -import { CopyWebviewEditorCommand, CutWebviewEditorCommand, HideWebViewEditorFindCommand, OpenWebviewDeveloperToolsAction, PasteWebviewEditorCommand, RedoWebviewEditorCommand, ReloadWebviewAction, SelectAllWebviewEditorCommand, ShowWebViewEditorFindWidgetCommand, UndoWebviewEditorCommand } from '../browser/webviewCommands'; +import { KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE, webviewDeveloperCategory } from 'vs/workbench/contrib/webview/common/webview'; +import { HideWebViewEditorFindCommand, ReloadWebviewAction, ShowWebViewEditorFindWidgetCommand } from '../browser/webviewCommands'; import { WebviewEditor } from '../browser/webviewEditor'; import { WebviewEditorInput } from '../browser/webviewEditorInput'; import { IWebviewEditorService, WebviewEditorService } from '../browser/webviewEditorService'; @@ -35,12 +33,9 @@ Registry.as(EditorInputExtensions.EditorInputFactor registerSingleton(IWebviewEditorService, WebviewEditorService, true); - -const webviewDeveloperCategory = localize('developer', "Developer"); - const actionRegistry = Registry.as(ActionExtensions.WorkbenchActions); -export function registerWebViewCommands(editorId: string): void { +function registerWebViewCommands(editorId: string): void { const contextKeyExpr = ContextKeyExpr.and(ContextKeyExpr.equals('activeEditor', editorId), ContextKeyExpr.not('editorFocus') /* https://github.com/Microsoft/vscode/issues/58668 */); const showNextFindWidgetCommand = new ShowWebViewEditorFindWidgetCommand({ @@ -63,76 +58,11 @@ export function registerWebViewCommands(editorId: string): void { weight: KeybindingWeight.EditorContrib } })).register(); - - (new SelectAllWebviewEditorCommand({ - id: SelectAllWebviewEditorCommand.ID, - precondition: ContextKeyExpr.and(contextKeyExpr, ContextKeyExpr.not(InputFocusedContextKey)), - kbOpts: { - primary: KeyMod.CtrlCmd | KeyCode.KEY_A, - weight: KeybindingWeight.EditorContrib - } - })).register(); - - // These commands are only needed on MacOS where we have to disable the menu bar commands - if (isMacintosh) { - (new CopyWebviewEditorCommand({ - id: CopyWebviewEditorCommand.ID, - precondition: ContextKeyExpr.and(contextKeyExpr, ContextKeyExpr.not(InputFocusedContextKey)), - kbOpts: { - primary: KeyMod.CtrlCmd | KeyCode.KEY_C, - weight: KeybindingWeight.EditorContrib - } - })).register(); - - (new PasteWebviewEditorCommand({ - id: PasteWebviewEditorCommand.ID, - precondition: ContextKeyExpr.and(contextKeyExpr, ContextKeyExpr.not(InputFocusedContextKey)), - kbOpts: { - primary: KeyMod.CtrlCmd | KeyCode.KEY_V, - weight: KeybindingWeight.EditorContrib - } - })).register(); - - - (new CutWebviewEditorCommand({ - id: CutWebviewEditorCommand.ID, - precondition: ContextKeyExpr.and(contextKeyExpr, ContextKeyExpr.not(InputFocusedContextKey)), - kbOpts: { - primary: KeyMod.CtrlCmd | KeyCode.KEY_X, - weight: KeybindingWeight.EditorContrib - } - })).register(); - - (new UndoWebviewEditorCommand({ - id: UndoWebviewEditorCommand.ID, - precondition: ContextKeyExpr.and(contextKeyExpr, ContextKeyExpr.not(InputFocusedContextKey)), - kbOpts: { - primary: KeyMod.CtrlCmd | KeyCode.KEY_Z, - weight: KeybindingWeight.EditorContrib - } - })).register(); - - (new RedoWebviewEditorCommand({ - id: RedoWebviewEditorCommand.ID, - precondition: ContextKeyExpr.and(contextKeyExpr, ContextKeyExpr.not(InputFocusedContextKey)), - kbOpts: { - primary: KeyMod.CtrlCmd | KeyCode.KEY_Y, - secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z], - mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z }, - weight: KeybindingWeight.EditorContrib - } - })).register(); - } } registerWebViewCommands(WebviewEditor.ID); -actionRegistry.registerWorkbenchAction( - new SyncActionDescriptor(OpenWebviewDeveloperToolsAction, OpenWebviewDeveloperToolsAction.ID, OpenWebviewDeveloperToolsAction.LABEL), - 'Webview Tools', - webviewDeveloperCategory); - actionRegistry.registerWorkbenchAction( new SyncActionDescriptor(ReloadWebviewAction, ReloadWebviewAction.ID, ReloadWebviewAction.LABEL), - 'Reload Webview', + 'Reload Webviews', webviewDeveloperCategory); diff --git a/src/vs/workbench/contrib/webview/browser/webviewCommands.ts b/src/vs/workbench/contrib/webview/browser/webviewCommands.ts index 91b4ad454..a5888e3e6 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewCommands.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewCommands.ts @@ -32,96 +32,6 @@ export class HideWebViewEditorFindCommand extends Command { } } -export class SelectAllWebviewEditorCommand extends Command { - public static readonly ID = 'editor.action.webvieweditor.selectAll'; - - public runCommand(accessor: ServicesAccessor, args: any): void { - const webViewEditor = getActiveWebviewEditor(accessor); - if (webViewEditor) { - webViewEditor.selectAll(); - } - } -} - -export class CopyWebviewEditorCommand extends Command { - public static readonly ID = 'editor.action.webvieweditor.copy'; - - public runCommand(accessor: ServicesAccessor, args: any): void { - const webViewEditor = getActiveWebviewEditor(accessor); - if (webViewEditor) { - webViewEditor.copy(); - } - } -} - -export class PasteWebviewEditorCommand extends Command { - public static readonly ID = 'editor.action.webvieweditor.paste'; - - public runCommand(accessor: ServicesAccessor, args: any): void { - const webViewEditor = getActiveWebviewEditor(accessor); - if (webViewEditor) { - webViewEditor.paste(); - } - } -} - -export class CutWebviewEditorCommand extends Command { - public static readonly ID = 'editor.action.webvieweditor.cut'; - - public runCommand(accessor: ServicesAccessor, args: any): void { - const webViewEditor = getActiveWebviewEditor(accessor); - if (webViewEditor) { - webViewEditor.cut(); - } - } -} - -export class UndoWebviewEditorCommand extends Command { - public static readonly ID = 'editor.action.webvieweditor.undo'; - - public runCommand(accessor: ServicesAccessor, args: any): void { - const webViewEditor = getActiveWebviewEditor(accessor); - if (webViewEditor) { - webViewEditor.undo(); - } - } -} - -export class RedoWebviewEditorCommand extends Command { - public static readonly ID = 'editor.action.webvieweditor.redo'; - - public runCommand(accessor: ServicesAccessor, args: any): void { - const webViewEditor = getActiveWebviewEditor(accessor); - if (webViewEditor) { - webViewEditor.redo(); - } - } -} - -export class OpenWebviewDeveloperToolsAction extends Action { - static readonly ID = 'workbench.action.webview.openDeveloperTools'; - static readonly LABEL = nls.localize('openToolsLabel', "Open Webview Developer Tools"); - - public constructor( - id: string, - label: string - ) { - super(id, label); - } - - public run(): Promise { - const elements = document.querySelectorAll('webview.ready'); - for (let i = 0; i < elements.length; i++) { - try { - (elements.item(i) as Electron.WebviewTag).openDevTools(); - } catch (e) { - console.error(e); - } - } - return Promise.resolve(true); - } -} - export class ReloadWebviewAction extends Action { static readonly ID = 'workbench.action.webview.reloadWebviewAction'; static readonly LABEL = nls.localize('refreshWebviewLabel', "Reload Webviews"); diff --git a/src/vs/workbench/contrib/webview/browser/webviewEditor.ts b/src/vs/workbench/contrib/webview/browser/webviewEditor.ts index 079afa85d..d01dc751d 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewEditor.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewEditor.ts @@ -6,55 +6,50 @@ import * as DOM from 'vs/base/browser/dom'; import { CancellationToken } from 'vs/base/common/cancellation'; import { Emitter, Event } from 'vs/base/common/event'; -import { dispose, IDisposable } from 'vs/base/common/lifecycle'; -import { URI } from 'vs/base/common/uri'; +import { DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IWindowService } from 'vs/platform/windows/common/windows'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { EditorOptions } from 'vs/workbench/common/editor'; import { WebviewEditorInput } from 'vs/workbench/contrib/webview/browser/webviewEditorInput'; -import { IWebviewService, Webview, KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE } from 'vs/workbench/contrib/webview/common/webview'; +import { KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE, Webview, WebviewEditorOverlay } from 'vs/workbench/contrib/webview/common/webview'; import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; - export class WebviewEditor extends BaseEditor { - protected _webview: Webview | undefined; - protected findWidgetVisible: IContextKey; - public static readonly ID = 'WebviewEditor'; - private _editorFrame: HTMLElement; + private readonly _scopedContextKeyService = this._register(new MutableDisposable()); + private _findWidgetVisible: IContextKey; + + private _editorFrame?: HTMLElement; private _content?: HTMLElement; - private _webviewContent: HTMLElement | undefined; - private _webviewFocusTrackerDisposables: IDisposable[] = []; - private _onFocusWindowHandler?: IDisposable; + private readonly _webviewFocusTrackerDisposables = this._register(new DisposableStore()); + private readonly _onFocusWindowHandler = this._register(new MutableDisposable()); private readonly _onDidFocusWebview = this._register(new Emitter()); public get onDidFocus(): Event { return this._onDidFocusWebview.event; } - private pendingMessages: any[] = []; - constructor( @ITelemetryService telemetryService: ITelemetryService, @IThemeService themeService: IThemeService, - @IContextKeyService private _contextKeyService: IContextKeyService, - @IWebviewService private readonly _webviewService: IWebviewService, - @IWorkspaceContextService private readonly _contextService: IWorkspaceContextService, + @IContextKeyService private readonly _contextKeyService: IContextKeyService, @IEditorService private readonly _editorService: IEditorService, @IWindowService private readonly _windowService: IWindowService, @IStorageService storageService: IStorageService ) { super(WebviewEditor.ID, telemetryService, themeService, storageService); - if (_contextKeyService) { - this.findWidgetVisible = KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE.bindTo(_contextKeyService); - } + + this._findWidgetVisible = KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE.bindTo(_contextKeyService); + } + + public get isWebviewEditor() { + return true; } protected createEditor(parent: HTMLElement): void { @@ -63,64 +58,25 @@ export class WebviewEditor extends BaseEditor { parent.appendChild(this._content); } - private doUpdateContainer() { - const webviewContainer = this.input && (this.input as WebviewEditorInput).container; - if (webviewContainer && webviewContainer.parentElement) { - const frameRect = this._editorFrame.getBoundingClientRect(); - const containerRect = webviewContainer.parentElement.getBoundingClientRect(); - - webviewContainer.style.position = 'absolute'; - webviewContainer.style.top = `${frameRect.top - containerRect.top}px`; - webviewContainer.style.left = `${frameRect.left - containerRect.left}px`; - webviewContainer.style.width = `${frameRect.width}px`; - webviewContainer.style.height = `${frameRect.height}px`; - } - } - public dispose(): void { - this.pendingMessages = []; - - // Let the editor input dispose of the webview. - this._webview = undefined; - this._webviewContent = undefined; - - if (this._content && this._content.parentElement) { - this._content.parentElement.removeChild(this._content); + if (this._content) { + this._content.remove(); this._content = undefined; } - this._webviewFocusTrackerDisposables = dispose(this._webviewFocusTrackerDisposables); - - if (this._onFocusWindowHandler) { - this._onFocusWindowHandler.dispose(); - } - super.dispose(); } - public sendMessage(data: any): void { - if (this._webview) { - this._webview.sendMessage(data); - } else { - this.pendingMessages.push(data); - } - } public showFind() { - if (this._webview) { - this._webview.showFind(); - this.findWidgetVisible.set(true); - } + this.withWebview(webview => { + webview.showFind(); + this._findWidgetVisible.set(true); + }); } public hideFind() { - this.findWidgetVisible.reset(); - if (this._webview) { - this._webview.hideFind(); - } - } - - public get isWebviewEditor() { - return true; + this._findWidgetVisible.reset(); + this.withWebview(webview => webview.hideFind()); } public reload() { @@ -128,18 +84,17 @@ export class WebviewEditor extends BaseEditor { } public layout(_dimension: DOM.Dimension): void { - this.withWebview(webview => { - this.doUpdateContainer(); - webview.layout(); - }); + if (this.input && this.input instanceof WebviewEditorInput) { + this.synchronizeWebviewContainerDimensions(this.input.webview); + this.input.webview.layout(); + } } public focus(): void { super.focus(); - if (!this._onFocusWindowHandler) { - + if (!this._onFocusWindowHandler.value) { // Make sure we restore focus when switching back to a VS Code window - this._onFocusWindowHandler = this._windowService.onDidChangeFocus(focused => { + this._onFocusWindowHandler.value = this._windowService.onDidChangeFocus(focused => { if (focused && this._editorService.activeControl === this) { this.focus(); } @@ -148,54 +103,21 @@ export class WebviewEditor extends BaseEditor { this.withWebview(webview => webview.focus()); } - public selectAll(): void { - this.withWebview(webview => webview.selectAll()); - } - - public copy(): void { - this.withWebview(webview => webview.copy()); - } - - public paste(): void { - this.withWebview(webview => webview.paste()); - } - - public cut(): void { - this.withWebview(webview => webview.cut()); - } - - public undo(): void { - this.withWebview(webview => webview.undo()); - } - - public redo(): void { - this.withWebview(webview => webview.redo()); - } - - private withWebview(f: (element: Webview) => void): void { - if (this._webview) { - f(this._webview); + public withWebview(f: (element: Webview) => void): void { + if (this.input && this.input instanceof WebviewEditorInput) { + f(this.input.webview); } } protected setEditorVisible(visible: boolean, group: IEditorGroup): void { - if (this.input && this.input instanceof WebviewEditorInput) { + const webview = this.input && (this.input as WebviewEditorInput).webview; + if (webview) { if (visible) { - this.input.claimWebview(this); + webview.claim(this); } else { - this.input.releaseWebview(this); - } - - this.updateWebview(this.input as WebviewEditorInput); - } - - if (this._webviewContent) { - if (visible) { - this._webviewContent.style.visibility = 'visible'; - this.doUpdateContainer(); - } else { - this._webviewContent.style.visibility = 'hidden'; + webview.release(this); } + this.claimWebview(this.input as WebviewEditorInput); } super.setEditorVisible(visible, group); @@ -203,115 +125,69 @@ export class WebviewEditor extends BaseEditor { public clearInput() { if (this.input && this.input instanceof WebviewEditorInput) { - this.input.releaseWebview(this); + this.input.webview.release(this); } - this._webview = undefined; - this._webviewContent = undefined; - this.pendingMessages = []; - super.clearInput(); } - setInput(input: WebviewEditorInput, options: EditorOptions, token: CancellationToken): Promise { - if (this.input) { - (this.input as WebviewEditorInput).releaseWebview(this); - this._webview = undefined; - this._webviewContent = undefined; - } - this.pendingMessages = []; - return super.setInput(input, options, token) - .then(() => input.resolve()) - .then(() => { - if (token.isCancellationRequested) { - return; - } - if (this.group) { - input.updateGroup(this.group.id); - } - this.updateWebview(input); - }); - } - - private updateWebview(input: WebviewEditorInput) { - const webview = this.getWebview(input); - input.claimWebview(this); - webview.update(input.html, { - allowScripts: input.options.enableScripts, - localResourceRoots: input.options.localResourceRoots || this.getDefaultLocalResourceRoots(), - portMappings: input.options.portMapping, - }, !!input.options.retainContextWhenHidden); - - if (this._webviewContent) { - this._webviewContent.style.visibility = 'visible'; + public async setInput(input: WebviewEditorInput, options: EditorOptions, token: CancellationToken): Promise { + if (this.input && this.input instanceof WebviewEditorInput) { + this.input.webview.release(this); } - this.doUpdateContainer(); - } - - private getDefaultLocalResourceRoots(): URI[] { - const rootPaths = this._contextService.getWorkspace().folders.map(x => x.uri); - const extension = (this.input as WebviewEditorInput).extension; - if (extension) { - rootPaths.push(extension.location); + await super.setInput(input, options, token); + await input.resolve(); + if (token.isCancellationRequested) { + return; } - return rootPaths; - } - private getWebview(input: WebviewEditorInput): Webview { - if (this._webview) { - return this._webview; + if (this.group) { + input.updateGroup(this.group.id); } - this._webviewContent = input.container; - - if (input.webview) { - this._webview = input.webview; - } else { - if (input.options.enableFindWidget) { - this._contextKeyService = this._register(this._contextKeyService.createScoped(this._webviewContent)); - this.findWidgetVisible = KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE.bindTo(this._contextKeyService); - } - - this._webview = this._webviewService.createWebview( - { - allowSvgs: true, - extension: input.extension, - enableFindWidget: input.options.enableFindWidget - }, {}); - this._webview.mountTo(this._webviewContent); - input.webview = this._webview; - - if (input.options.tryRestoreScrollPosition) { - this._webview.initialScrollProgress = input.scrollYPercentage; - } - - this._webview.state = input.webviewState; + this.claimWebview(input); + } - this._content!.setAttribute('aria-flowto', this._webviewContent.id); + private claimWebview(input: WebviewEditorInput): void { + input.webview.claim(this); - this.doUpdateContainer(); + if (input.webview.options.enableFindWidget) { + this._scopedContextKeyService.value = this._contextKeyService.createScoped(input.webview.container); + this._findWidgetVisible = KEYBINDING_CONTEXT_WEBVIEW_FIND_WIDGET_VISIBLE.bindTo(this._scopedContextKeyService.value); } - for (const message of this.pendingMessages) { - this._webview.sendMessage(message); + if (this._content) { + this._content.setAttribute('aria-flowto', input.webview.container.id); } - this.pendingMessages = []; - this.trackFocus(); + this.synchronizeWebviewContainerDimensions(input.webview); + this.trackFocus(input.webview); + } + + private synchronizeWebviewContainerDimensions(webview: WebviewEditorOverlay) { + const webviewContainer = webview.container; + if (webviewContainer && webviewContainer.parentElement && this._editorFrame) { + const frameRect = this._editorFrame.getBoundingClientRect(); + const containerRect = webviewContainer.parentElement.getBoundingClientRect(); - return this._webview; + webviewContainer.style.position = 'absolute'; + webviewContainer.style.top = `${frameRect.top - containerRect.top}px`; + webviewContainer.style.left = `${frameRect.left - containerRect.left}px`; + webviewContainer.style.width = `${frameRect.width}px`; + webviewContainer.style.height = `${frameRect.height}px`; + } } - private trackFocus() { - this._webviewFocusTrackerDisposables = dispose(this._webviewFocusTrackerDisposables); + private trackFocus(webview: WebviewEditorOverlay): void { + this._webviewFocusTrackerDisposables.clear(); // Track focus in webview content - const webviewContentFocusTracker = DOM.trackFocus(this._webviewContent!); - this._webviewFocusTrackerDisposables.push(webviewContentFocusTracker); - this._webviewFocusTrackerDisposables.push(webviewContentFocusTracker.onDidFocus(() => this._onDidFocusWebview.fire())); + const webviewContentFocusTracker = DOM.trackFocus(webview.container); + this._webviewFocusTrackerDisposables.add(webviewContentFocusTracker); + this._webviewFocusTrackerDisposables.add(webviewContentFocusTracker.onDidFocus(() => this._onDidFocusWebview.fire())); // Track focus in webview element - this._webviewFocusTrackerDisposables.push(this._webview!.onDidFocus(() => this._onDidFocusWebview.fire())); + this._webviewFocusTrackerDisposables.add(webview.onDidFocus(() => this._onDidFocusWebview.fire())); } } diff --git a/src/vs/workbench/contrib/webview/browser/webviewEditorInput.ts b/src/vs/workbench/contrib/webview/browser/webviewEditorInput.ts index 0df01ea4d..c91e93d91 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewEditorInput.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewEditorInput.ts @@ -3,124 +3,90 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import * as dom from 'vs/base/browser/dom'; -import { Emitter } from 'vs/base/common/event'; -import { dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { memoize } from 'vs/base/common/decorators'; import { URI } from 'vs/base/common/uri'; import { IEditorModel } from 'vs/platform/editor/common/editor'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { EditorInput, EditorModel, GroupIdentifier, IEditorInput } from 'vs/workbench/common/editor'; -import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; -import { WebviewEvents, WebviewInputOptions } from './webviewEditorService'; -import { Webview, WebviewOptions } from 'vs/workbench/contrib/webview/common/webview'; +import { WebviewEditorOverlay } from 'vs/workbench/contrib/webview/common/webview'; +import { UnownedDisposable as Unowned } from 'vs/base/common/lifecycle'; -export class WebviewEditorInput extends EditorInput { - private static handlePool = 0; - - private static _styleElement?: HTMLStyleElement; +class WebviewIconsManager { + private readonly _icons = new Map(); - private static _icons = new Map(); + @memoize + private get _styleElement(): HTMLStyleElement { + const element = dom.createStyleSheet(); + element.className = 'webview-icons'; + return element; + } - private static updateStyleElement( - id: number, + public setIcons( + webviewId: string, iconPath: { light: URI, dark: URI } | undefined ) { - if (!this._styleElement) { - this._styleElement = dom.createStyleSheet(); - this._styleElement.className = 'webview-icons'; - } - - if (!iconPath) { - this._icons.delete(id); + if (iconPath) { + this._icons.set(webviewId, iconPath); } else { - this._icons.set(id, iconPath); + this._icons.delete(webviewId); } + this.updateStyleSheet(); + } + + private updateStyleSheet() { const cssRules: string[] = []; this._icons.forEach((value, key) => { const webviewSelector = `.show-file-icons .webview-${key}-name-file-icon::before`; if (URI.isUri(value)) { - cssRules.push(`${webviewSelector} { content: ""; background-image: url(${value.toString()}); }`); - } else { - cssRules.push(`.vs ${webviewSelector} { content: ""; background-image: url(${value.light.toString()}); }`); - cssRules.push(`.vs-dark ${webviewSelector} { content: ""; background-image: url(${value.dark.toString()}); }`); + cssRules.push(`${webviewSelector} { content: ""; background-image: url(${dom.asDomUri(value).toString()}); }`); + } + else { + cssRules.push(`.vs ${webviewSelector} { content: ""; background-image: url(${dom.asDomUri(value.light).toString()}); }`); + cssRules.push(`.vs-dark ${webviewSelector} { content: ""; background-image: url(${dom.asDomUri(value.dark).toString()}); }`); } }); this._styleElement.innerHTML = cssRules.join('\n'); } +} + +export class WebviewEditorInput extends EditorInput { public static readonly typeId = 'workbench.editors.webviewInput'; + private static readonly iconsManager = new WebviewIconsManager(); + private _name: string; private _iconPath?: { light: URI, dark: URI }; - private _options: WebviewInputOptions; - private _html: string = ''; - private _currentWebviewHtml: string = ''; - public _events: WebviewEvents | undefined; - private _container?: HTMLElement; - private _webview?: Webview; - private _webviewOwner: any; - private _webviewDisposables: IDisposable[] = []; private _group?: GroupIdentifier; - private _scrollYPercentage: number = 0; - private _state: any; - - public readonly extension?: { - readonly location: URI; - readonly id: ExtensionIdentifier; - }; - private readonly _id: number; + private readonly _webview: WebviewEditorOverlay; constructor( + public readonly id: string, public readonly viewType: string, name: string, - options: WebviewInputOptions, - state: any, - events: WebviewEvents, - extension: undefined | { + public readonly extension: undefined | { readonly location: URI; readonly id: ExtensionIdentifier; }, - @IWorkbenchLayoutService private readonly _layoutService: IWorkbenchLayoutService, + webview: Unowned, ) { super(); - this._id = WebviewEditorInput.handlePool++; - this._name = name; - this._options = options; - this._events = events; - this._state = state; this.extension = extension; + + this._webview = this._register(webview.acquire()); // The input owns this webview } public getTypeId(): string { return WebviewEditorInput.typeId; } - private readonly _onDidChangeIcon = this._register(new Emitter()); - public readonly onDidChangeIcon = this._onDidChangeIcon.event; - - public dispose() { - this.disposeWebview(); - - if (this._container) { - this._container.remove(); - this._container = undefined; - } - - if (this._events && this._events.onDispose) { - this._events.onDispose(); - } - this._events = undefined; - - this._webview = undefined; - super.dispose(); - } - public getResource(): URI { return URI.from({ scheme: 'webview-panel', - path: `webview-panel/webview-${this._id}` + path: `webview-panel/webview-${this.id}` }); } @@ -133,7 +99,7 @@ export class WebviewEditorInput extends EditorInput { } public getDescription() { - return null; + return undefined; } public setName(value: string): void { @@ -141,13 +107,17 @@ export class WebviewEditorInput extends EditorInput { this._onDidChangeLabel.fire(); } + public get webview() { + return this._webview; + } + public get iconPath() { return this._iconPath; } public set iconPath(value: { light: URI, dark: URI } | undefined) { this._iconPath = value; - WebviewEditorInput.updateStyleElement(this._id, value); + WebviewEditorInput.iconsManager.setIcons(this.id, value); } public matches(other: IEditorInput): boolean { @@ -158,166 +128,34 @@ export class WebviewEditorInput extends EditorInput { return this._group; } - public get html(): string { - return this._html; - } - - public set html(value: string) { - if (value === this._currentWebviewHtml) { - return; - } - - this._html = value; - - if (this._webview) { - this._webview.contents = value; - this._currentWebviewHtml = value; - } - } - - public get state(): any { - return this._state; - } - - public set state(value: any) { - this._state = value; - } - - public get webviewState() { - return this._state.state; - } - - public get options(): WebviewInputOptions { - return this._options; - } - - public setOptions(value: WebviewOptions) { - this._options = { - ...this._options, - ...value - }; - - if (this._webview) { - this._webview.options = { - allowScripts: this._options.enableScripts, - localResourceRoots: this._options.localResourceRoots, - portMappings: this._options.portMapping, - }; - } - } - - public resolve(): Promise { - return Promise.resolve(new EditorModel()); + public async resolve(): Promise { + return new EditorModel(); } public supportsSplitEditor() { return false; } - public get container(): HTMLElement { - if (!this._container) { - this._container = document.createElement('div'); - this._container.id = `webview-${this._id}`; - const part = this._layoutService.getContainer(Parts.EDITOR_PART); - part.appendChild(this._container); - } - return this._container; - } - - public get webview(): Webview | undefined { - return this._webview; - } - - public set webview(value: Webview | undefined) { - this._webviewDisposables = dispose(this._webviewDisposables); - - this._webview = value; - if (!this._webview) { - return; - } - - this._webview.onDidClickLink(link => { - if (this._events && this._events.onDidClickLink) { - this._events.onDidClickLink(link, this._options); - } - }, null, this._webviewDisposables); - - this._webview.onMessage(message => { - if (this._events && this._events.onMessage) { - this._events.onMessage(message); - } - }, null, this._webviewDisposables); - - this._webview.onDidScroll(message => { - this._scrollYPercentage = message.scrollYPercentage; - }, null, this._webviewDisposables); - - this._webview.onDidUpdateState(newState => { - this._state.state = newState; - }, null, this._webviewDisposables); - } - - public get scrollYPercentage() { - return this._scrollYPercentage; - } - - public claimWebview(owner: any) { - - this._webviewOwner = owner; - } - - public releaseWebview(owner: any) { - if (this._webviewOwner === owner) { - this._webviewOwner = undefined; - if (this._options.retainContextWhenHidden && this._container) { - this._container.style.visibility = 'hidden'; - } else { - this.disposeWebview(); - } - } - } - - public disposeWebview() { - // The input owns the webview and its parent - if (this._webview) { - this._webview.dispose(); - this._webview = undefined; - } - - this._webviewDisposables = dispose(this._webviewDisposables); - - this._webviewOwner = undefined; - - if (this._container) { - this._container.style.visibility = 'hidden'; - } - - this._currentWebviewHtml = ''; - } - public updateGroup(group: GroupIdentifier): void { this._group = group; } } - export class RevivedWebviewEditorInput extends WebviewEditorInput { private _revived: boolean = false; constructor( + id: string, viewType: string, name: string, - options: WebviewInputOptions, - state: any, - events: WebviewEvents, extension: undefined | { readonly location: URI; readonly id: ExtensionIdentifier }, private readonly reviver: (input: WebviewEditorInput) => Promise, - @IWorkbenchLayoutService partService: IWorkbenchLayoutService, + webview: Unowned, ) { - super(viewType, name, options, state, events, extension, partService); + super(id, viewType, name, extension, webview); } public async resolve(): Promise { @@ -327,4 +165,4 @@ export class RevivedWebviewEditorInput extends WebviewEditorInput { } return super.resolve(); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/contrib/webview/browser/webviewEditorInputFactory.ts b/src/vs/workbench/contrib/webview/browser/webviewEditorInputFactory.ts index 66f9f0b8e..b5f3ce408 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewEditorInputFactory.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewEditorInputFactory.ts @@ -9,6 +9,7 @@ import { WebviewEditorInput } from './webviewEditorInput'; import { IWebviewEditorService, WebviewInputOptions } from './webviewEditorService'; import { URI, UriComponents } from 'vs/base/common/uri'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; +import { generateUuid } from 'vs/base/common/uuid'; interface SerializedIconPath { light: string | UriComponents; @@ -44,10 +45,10 @@ export class WebviewEditorInputFactory implements IEditorInputFactory { const data: SerializedWebview = { viewType: input.viewType, title: input.getName(), - options: input.options, + options: input.webview.options, extensionLocation: input.extension ? input.extension.location : undefined, extensionId: input.extension && input.extension.id ? input.extension.id.value : undefined, - state: input.state, + state: input.webview.state, iconPath: input.iconPath ? { light: input.iconPath.light, dark: input.iconPath.dark, } : undefined, group: input.group }; @@ -67,12 +68,15 @@ export class WebviewEditorInputFactory implements IEditorInputFactory { const extensionLocation = reviveUri(data.extensionLocation); const extensionId = data.extensionId ? new ExtensionIdentifier(data.extensionId) : undefined; const iconPath = reviveIconPath(data.iconPath); - return this._webviewService.reviveWebview(data.viewType, data.title, iconPath, data.state, data.options, extensionLocation ? { + const state = reviveState(data.state); + + return this._webviewService.reviveWebview(generateUuid(), data.viewType, data.title, iconPath, state, data.options, extensionLocation ? { location: extensionLocation, id: extensionId } : undefined, data.group); } } + function reviveIconPath(data: SerializedIconPath | undefined) { if (!data) { return undefined; @@ -97,3 +101,21 @@ function reviveUri(data: string | UriComponents | undefined): URI | undefined { return undefined; } } + + +function reviveState(state: unknown | undefined): undefined | string { + if (!state) { + return undefined; + } + + if (typeof state === 'string') { + return state; + } + + // Likely an old style state. Unwrap to a simple state object + // Remove after 1.37 + if ('state' in (state as any) && typeof (state as any).state === 'string') { + return (state as any).state; + } + return undefined; +} \ No newline at end of file diff --git a/src/vs/workbench/contrib/webview/browser/webviewEditorService.ts b/src/vs/workbench/contrib/webview/browser/webviewEditorService.ts index b12720c63..e81418df6 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewEditorService.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewEditorService.ts @@ -4,16 +4,17 @@ *--------------------------------------------------------------------------------------------*/ import { equals } from 'vs/base/common/arrays'; -import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, toDisposable, UnownedDisposable } from 'vs/base/common/lifecycle'; import { values } from 'vs/base/common/map'; import { URI } from 'vs/base/common/uri'; -import { IWebviewOptions, IWebviewPanelOptions } from 'vs/editor/common/modes'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { GroupIdentifier } from 'vs/workbench/common/editor'; +import { IWebviewService, WebviewOptions, WebviewContentOptions } from 'vs/workbench/contrib/webview/common/webview'; import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { ACTIVE_GROUP_TYPE, IEditorService, SIDE_GROUP_TYPE } from 'vs/workbench/services/editor/common/editorService'; import { RevivedWebviewEditorInput, WebviewEditorInput } from './webviewEditorInput'; +import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; export const IWebviewEditorService = createDecorator('webviewEditorService'); @@ -26,6 +27,7 @@ export interface IWebviewEditorService { _serviceBrand: any; createWebview( + id: string, viewType: string, title: string, showOptions: ICreateWebViewShowOptions, @@ -34,10 +36,10 @@ export interface IWebviewEditorService { location: URI, id: ExtensionIdentifier }, - events: WebviewEvents ): WebviewEditorInput; reviveWebview( + id: string, viewType: string, title: string, iconPath: { light: URI, dark: URI } | undefined, @@ -75,24 +77,20 @@ export interface WebviewReviver { ): Promise; } -export interface WebviewEvents { - onMessage?(message: any): void; - onDispose?(): void; - onDidClickLink?(link: URI, options: IWebviewOptions): void; -} - -export interface WebviewInputOptions extends IWebviewOptions, IWebviewPanelOptions { - tryRestoreScrollPosition?: boolean; +export interface WebviewInputOptions extends WebviewOptions, WebviewContentOptions { + readonly tryRestoreScrollPosition?: boolean; + readonly retainContextWhenHidden?: boolean; + readonly enableCommandUris?: boolean; } export function areWebviewInputOptionsEqual(a: WebviewInputOptions, b: WebviewInputOptions): boolean { return a.enableCommandUris === b.enableCommandUris && a.enableFindWidget === b.enableFindWidget - && a.enableScripts === b.enableScripts + && a.allowScripts === b.allowScripts && a.retainContextWhenHidden === b.retainContextWhenHidden && a.tryRestoreScrollPosition === b.tryRestoreScrollPosition && (a.localResourceRoots === b.localResourceRoots || (Array.isArray(a.localResourceRoots) && Array.isArray(b.localResourceRoots) && equals(a.localResourceRoots, b.localResourceRoots, (a, b) => a.toString() === b.toString()))) - && (a.portMapping === b.portMapping || (Array.isArray(a.portMapping) && Array.isArray(b.portMapping) && equals(a.portMapping, b.portMapping, (a, b) => a.from === b.from && a.to === b.to))); + && (a.portMapping === b.portMapping || (Array.isArray(a.portMapping) && Array.isArray(b.portMapping) && equals(a.portMapping, b.portMapping, (a, b) => a.extensionHostPort === b.extensionHostPort && a.webviewPort === b.webviewPort))); } function canRevive(reviver: WebviewReviver, webview: WebviewEditorInput): boolean { @@ -129,20 +127,24 @@ export class WebviewEditorService implements IWebviewEditorService { @IEditorService private readonly _editorService: IEditorService, @IInstantiationService private readonly _instantiationService: IInstantiationService, @IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService, + @IWebviewService private readonly _webviewService: IWebviewService, + @IWorkspaceContextService private readonly _contextService: IWorkspaceContextService, ) { } public createWebview( + id: string, viewType: string, title: string, showOptions: ICreateWebViewShowOptions, - options: IWebviewOptions, + options: WebviewInputOptions, extension: undefined | { location: URI, id: ExtensionIdentifier }, - events: WebviewEvents ): WebviewEditorInput { - const webviewInput = this._instantiationService.createInstance(WebviewEditorInput, viewType, title, options, {}, events, extension); + const webview = this.createWebiew(id, extension, options); + + const webviewInput = this._instantiationService.createInstance(WebviewEditorInput, id, viewType, title, extension, new UnownedDisposable(webview)); this._editorService.openEditor(webviewInput, { pinned: true, preserveFocus: showOptions.preserveFocus }, showOptions.group); return webviewInput; } @@ -163,6 +165,7 @@ export class WebviewEditorService implements IWebviewEditorService { } public reviveWebview( + id: string, viewType: string, title: string, iconPath: { light: URI, dark: URI } | undefined, @@ -170,11 +173,14 @@ export class WebviewEditorService implements IWebviewEditorService { options: WebviewInputOptions, extension: undefined | { readonly location: URI, - readonly id?: ExtensionIdentifier + readonly id: ExtensionIdentifier }, group: number | undefined, ): WebviewEditorInput { - const webviewInput = this._instantiationService.createInstance(RevivedWebviewEditorInput, viewType, title, options, state, {}, extension, async (webview: WebviewEditorInput): Promise => { + const webview = this.createWebiew(id, extension, options); + webview.state = state; + + const webviewInput = new RevivedWebviewEditorInput(id, viewType, title, extension, async (webview: WebviewEditorInput): Promise => { const didRevive = await this.tryRevive(webview); if (didRevive) { return Promise.resolve(undefined); @@ -185,8 +191,10 @@ export class WebviewEditorService implements IWebviewEditorService { const promise = new Promise(r => { resolve = r; }); this._revivalPool.add(webview, resolve!); return promise; - }); + }, new UnownedDisposable(webview)); + webviewInput.iconPath = iconPath; + if (typeof group === 'number') { webviewInput.updateGroup(group); } @@ -208,7 +216,7 @@ export class WebviewEditorService implements IWebviewEditorService { webview: WebviewEditorInput ): boolean { // Has no state, don't persist - if (!webview.state) { + if (!webview.webview.state) { return false; } @@ -232,4 +240,27 @@ export class WebviewEditorService implements IWebviewEditorService { } return false; } + + private createWebiew(id: string, extension: { location: URI; id: ExtensionIdentifier; } | undefined, options: WebviewInputOptions) { + return this._webviewService.createWebviewEditorOverlay(id, { + allowSvgs: true, + extension: extension, + enableFindWidget: options.enableFindWidget, + retainContextWhenHidden: options.retainContextWhenHidden + }, { + ...options, + localResourceRoots: options.localResourceRoots || this.getDefaultLocalResourceRoots(extension), + }); + } + + private getDefaultLocalResourceRoots(extension: undefined | { + location: URI, + id: ExtensionIdentifier + }): URI[] { + const rootPaths = this._contextService.getWorkspace().folders.map(x => x.uri); + if (extension) { + rootPaths.push(extension.location); + } + return rootPaths; + } } diff --git a/src/vs/workbench/contrib/webview/browser/webviewElement.ts b/src/vs/workbench/contrib/webview/browser/webviewElement.ts new file mode 100644 index 000000000..aa4473313 --- /dev/null +++ b/src/vs/workbench/contrib/webview/browser/webviewElement.ts @@ -0,0 +1,327 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Emitter } from 'vs/base/common/event'; +import { URI } from 'vs/base/common/uri'; +import { Webview, WebviewContentOptions, WebviewOptions } from 'vs/workbench/contrib/webview/common/webview'; +import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { IFileService } from 'vs/platform/files/common/files'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { areWebviewInputOptionsEqual } from 'vs/workbench/contrib/webview/browser/webviewEditorService'; +import { addDisposableListener, addClass } from 'vs/base/browser/dom'; +import { getWebviewThemeData } from 'vs/workbench/contrib/webview/common/themeing'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { loadLocalResource } from 'vs/workbench/contrib/webview/common/resourceLoader'; +import { WebviewPortMappingManager } from 'vs/workbench/contrib/webview/common/portMapping'; +import { ITunnelService } from 'vs/platform/remote/common/tunnel'; + +interface WebviewContent { + readonly html: string; + readonly options: WebviewContentOptions; + readonly state: string | undefined; +} + +export class IFrameWebview extends Disposable implements Webview { + private element?: HTMLIFrameElement; + + private readonly _ready: Promise; + + private content: WebviewContent; + private _focused = false; + + private readonly _portMappingManager: WebviewPortMappingManager; + + constructor( + private readonly id: string, + private _options: WebviewOptions, + contentOptions: WebviewContentOptions, + @IThemeService themeService: IThemeService, + @ITunnelService tunnelService: ITunnelService, + @IEnvironmentService private readonly environmentService: IEnvironmentService, + @IFileService private readonly fileService: IFileService, + @IConfigurationService private readonly _configurationService: IConfigurationService, + ) { + super(); + const useExternalEndpoint = this._configurationService.getValue('webview.experimental.useExternalEndpoint'); + + if (typeof environmentService.webviewEndpoint !== 'string' && !useExternalEndpoint) { + throw new Error('To use iframe based webviews, you must configure `environmentService.webviewEndpoint`'); + } + + this._portMappingManager = this._register(new WebviewPortMappingManager( + this._options.extension ? this._options.extension.location : undefined, + () => this.content.options.portMapping || [], + tunnelService + )); + + this.content = { + html: '', + options: contentOptions, + state: undefined + }; + + this.element = document.createElement('iframe'); + this.element.sandbox.add('allow-scripts', 'allow-same-origin'); + this.element.setAttribute('src', `${this.endpoint}/index.html?id=${this.id}`); + this.element.style.border = 'none'; + this.element.style.width = '100%'; + this.element.style.height = '100%'; + + this._register(addDisposableListener(window, 'message', e => { + if (!e || !e.data || e.data.target !== this.id) { + return; + } + + switch (e.data.channel) { + case 'onmessage': + if (e.data.data) { + this._onMessage.fire(e.data.data); + } + return; + + case 'did-click-link': + const uri = e.data.data; + this._onDidClickLink.fire(URI.parse(uri)); + return; + + case 'did-scroll': + // if (e.args && typeof e.args[0] === 'number') { + // this._onDidScroll.fire({ scrollYPercentage: e.args[0] }); + // } + return; + + case 'do-reload': + this.reload(); + return; + + case 'do-update-state': + const state = e.data.data; + this.state = state; + this._onDidUpdateState.fire(state); + return; + + case 'did-focus': + this.handleFocusChange(true); + return; + + case 'did-blur': + this.handleFocusChange(false); + return; + + case 'load-resource': + { + const requestPath = e.data.data.path; + const uri = URI.file(decodeURIComponent(requestPath)); + this.loadResource(requestPath, uri); + return; + } + + case 'load-localhost': + { + this.localLocalhost(e.data.data.origin); + return; + } + } + })); + + this._ready = new Promise(resolve => { + const subscription = this._register(addDisposableListener(window, 'message', (e) => { + if (e.data && e.data.target === this.id && e.data.channel === 'webview-ready') { + if (this.element) { + addClass(this.element, 'ready'); + } + subscription.dispose(); + resolve(); + } + })); + }); + + this.style(themeService.getTheme()); + this._register(themeService.onThemeChange(this.style, this)); + } + + private get endpoint(): string { + const useExternalEndpoint = this._configurationService.getValue('webview.experimental.useExternalEndpoint'); + const baseEndpoint = useExternalEndpoint ? 'https://{{uuid}}.vscode-webview-test.com/8fa811108f0f0524c473020ef57b6620f6c201e1' : this.environmentService.webviewEndpoint!; + const endpoint = baseEndpoint.replace('{{uuid}}', this.id); + if (endpoint[endpoint.length - 1] === '/') { + return endpoint.slice(0, endpoint.length - 1); + } + return endpoint; + } + + public mountTo(parent: HTMLElement) { + if (this.element) { + parent.appendChild(this.element); + } + } + + public set contentOptions(options: WebviewContentOptions) { + if (areWebviewInputOptionsEqual(options, this.content.options)) { + return; + } + + this.content = { + html: this.content.html, + options: options, + state: this.content.state, + }; + this.doUpdateContent(); + } + + public set html(value: string) { + this.content = { + html: this.preprocessHtml(value), + options: this.content.options, + state: this.content.state, + }; + this.doUpdateContent(); + } + + private preprocessHtml(value: string): string { + return value.replace(/(["'])vscode-resource:([^\s'"]+?)(["'])/gi, (_, startQuote, path, endQuote) => + `${startQuote}${this.endpoint}/vscode-resource${path}${endQuote}`); + } + + public update(html: string, options: WebviewContentOptions, retainContextWhenHidden: boolean) { + if (retainContextWhenHidden && html === this.content.html && areWebviewInputOptionsEqual(options, this.content.options)) { + return; + } + this.content = { + html: this.preprocessHtml(html), + options: options, + state: this.content.state, + }; + this.doUpdateContent(); + } + + private doUpdateContent() { + this._send('content', { + contents: this.content.html, + options: this.content.options, + state: this.content.state + }); + } + + private handleFocusChange(isFocused: boolean): void { + this._focused = isFocused; + if (this._focused) { + this._onDidFocus.fire(); + } + } + + initialScrollProgress: number; + + private readonly _onDidFocus = this._register(new Emitter()); + public readonly onDidFocus = this._onDidFocus.event; + + private readonly _onDidClickLink = this._register(new Emitter()); + public readonly onDidClickLink = this._onDidClickLink.event; + + private readonly _onDidScroll = this._register(new Emitter<{ scrollYPercentage: number }>()); + public readonly onDidScroll = this._onDidScroll.event; + + private readonly _onDidUpdateState = this._register(new Emitter()); + public readonly onDidUpdateState = this._onDidUpdateState.event; + + private readonly _onMessage = this._register(new Emitter()); + public readonly onMessage = this._onMessage.event; + + sendMessage(data: any): void { + this._send('message', data); + } + + layout(): void { + // noop + } + + focus(): void { + if (this.element) { + this.element.focus(); + } + } + + dispose(): void { + if (this.element) { + if (this.element.parentElement) { + this.element.parentElement.removeChild(this.element); + } + } + + this.element = undefined!; + super.dispose(); + } + + reload(): void { + this.doUpdateContent(); + } + + showFind(): void { + throw new Error('Method not implemented.'); + } + + hideFind(): void { + throw new Error('Method not implemented.'); + } + + public set state(state: string | undefined) { + this.content = { + html: this.content.html, + options: this.content.options, + state, + }; + } + + private _send(channel: string, data: any): void { + this._ready + .then(() => { + if (!this.element) { + return; + } + this.element.contentWindow!.postMessage({ + channel: channel, + args: data + }, '*'); + }) + .catch(err => console.error(err)); + } + + private style(theme: ITheme): void { + const { styles, activeTheme } = getWebviewThemeData(theme, this._configurationService); + this._send('styles', { styles, activeTheme }); + } + + private async loadResource(requestPath: string, uri: URI) { + try { + const result = await loadLocalResource(uri, this.fileService, this._options.extension ? this._options.extension.location : undefined, + () => (this.content.options.localResourceRoots || [])); + + if (result.type === 'success') { + return this._send('did-load-resource', { + status: 200, + path: requestPath, + mime: result.mimeType, + data: result.data.buffer + }); + } + } catch { + // noop + } + + return this._send('did-load-resource', { + status: 404, + path: uri.path + }); + } + + private async localLocalhost(origin: string) { + const redirect = await this._portMappingManager.getRedirect(origin); + return this._send('did-load-localhost', { + origin, + location: redirect + }); + } +} diff --git a/src/vs/workbench/contrib/webview/browser/webviewFindWidget.ts b/src/vs/workbench/contrib/webview/browser/webviewFindWidget.ts index e33b782bf..1f337cbc8 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewFindWidget.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewFindWidget.ts @@ -44,6 +44,7 @@ export class WebviewFindWidget extends SimpleFindWidget { } else { this._delegate.stopFind(false); } + return false; } protected onFocusTrackerFocus() { } diff --git a/src/vs/workbench/contrib/webview/browser/webviewService.ts b/src/vs/workbench/contrib/webview/browser/webviewService.ts new file mode 100644 index 000000000..1995a857f --- /dev/null +++ b/src/vs/workbench/contrib/webview/browser/webviewService.ts @@ -0,0 +1,33 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IFrameWebview } from 'vs/workbench/contrib/webview/browser/webviewElement'; +import { IWebviewService, WebviewContentOptions, WebviewEditorOverlay, WebviewElement, WebviewOptions } from 'vs/workbench/contrib/webview/common/webview'; +import { DynamicWebviewEditorOverlay } from './dynamicWebviewEditorOverlay'; + +export class WebviewService implements IWebviewService { + _serviceBrand: any; + + constructor( + @IInstantiationService private readonly _instantiationService: IInstantiationService, + ) { } + + createWebview( + id: string, + options: WebviewOptions, + contentOptions: WebviewContentOptions + ): WebviewElement { + return this._instantiationService.createInstance(IFrameWebview, id, options, contentOptions); + } + + createWebviewEditorOverlay( + id: string, + options: WebviewOptions, + contentOptions: WebviewContentOptions, + ): WebviewEditorOverlay { + return this._instantiationService.createInstance(DynamicWebviewEditorOverlay, id, options, contentOptions); + } +} diff --git a/src/vs/workbench/contrib/webview/common/mimeTypes.ts b/src/vs/workbench/contrib/webview/common/mimeTypes.ts new file mode 100644 index 000000000..0f1f583d4 --- /dev/null +++ b/src/vs/workbench/contrib/webview/common/mimeTypes.ts @@ -0,0 +1,26 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { getMediaMime, MIME_UNKNOWN } from 'vs/base/common/mime'; +import { extname } from 'vs/base/common/path'; +import { URI } from 'vs/base/common/uri'; + +const webviewMimeTypes = new Map([ + ['.svg', 'image/svg+xml'], + ['.txt', 'text/plain'], + ['.css', 'text/css'], + ['.js', 'application/javascript'], + ['.json', 'application/json'], + ['.html', 'text/html'], + ['.htm', 'text/html'], + ['.xhtml', 'application/xhtml+xml'], + ['.oft', 'font/otf'], + ['.xml', 'application/xml'], +]); + +export function getWebviewContentMimeType(normalizedPath: URI): string { + const ext = extname(normalizedPath.fsPath).toLowerCase(); + return webviewMimeTypes.get(ext) || getMediaMime(normalizedPath.fsPath) || MIME_UNKNOWN; +} diff --git a/src/vs/workbench/contrib/webview/common/portMapping.ts b/src/vs/workbench/contrib/webview/common/portMapping.ts new file mode 100644 index 000000000..964c0ac6d --- /dev/null +++ b/src/vs/workbench/contrib/webview/common/portMapping.ts @@ -0,0 +1,87 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Disposable } from 'vs/base/common/lifecycle'; +import { URI } from 'vs/base/common/uri'; +import * as modes from 'vs/editor/common/modes'; +import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; +import { ITunnelService, RemoteTunnel } from 'vs/platform/remote/common/tunnel'; + +export function extractLocalHostUriMetaDataForPortMapping(uri: URI): { address: string, port: number } | undefined { + if (uri.scheme !== 'http' && uri.scheme !== 'https') { + return undefined; + } + const localhostMatch = /^(localhost|127\.0\.0\.1):(\d+)$/.exec(uri.authority); + if (!localhostMatch) { + return undefined; + } + return { + address: localhostMatch[1], + port: +localhostMatch[2], + }; +} + +export class WebviewPortMappingManager extends Disposable { + + private readonly _tunnels = new Map>(); + + constructor( + private readonly extensionLocation: URI | undefined, + private readonly mappings: () => ReadonlyArray, + private readonly tunnelService: ITunnelService + ) { + super(); + } + + public async getRedirect(url: string): Promise { + const uri = URI.parse(url); + const requestLocalHostInfo = extractLocalHostUriMetaDataForPortMapping(uri); + if (!requestLocalHostInfo) { + return undefined; + } + + for (const mapping of this.mappings()) { + if (mapping.webviewPort === requestLocalHostInfo.port) { + if (this.extensionLocation && this.extensionLocation.scheme === REMOTE_HOST_SCHEME) { + const tunnel = await this.getOrCreateTunnel(mapping.extensionHostPort); + if (tunnel) { + return uri.with({ + authority: `127.0.0.1:${tunnel.tunnelLocalPort}`, + }).toString(); + } + } + + if (mapping.webviewPort !== mapping.extensionHostPort) { + return uri.with({ + authority: `${requestLocalHostInfo.address}:${mapping.extensionHostPort}` + }).toString(); + } + } + } + + return undefined; + } + + dispose() { + super.dispose(); + + for (const tunnel of this._tunnels.values()) { + tunnel.then(tunnel => tunnel.dispose()); + } + this._tunnels.clear(); + } + + private getOrCreateTunnel(remotePort: number): Promise | undefined { + const existing = this._tunnels.get(remotePort); + if (existing) { + return existing; + } + const tunnel = this.tunnelService.openTunnel(remotePort); + if (tunnel) { + this._tunnels.set(remotePort, tunnel); + } + return tunnel; + } +} \ No newline at end of file diff --git a/src/vs/workbench/contrib/webview/common/resourceLoader.ts b/src/vs/workbench/contrib/webview/common/resourceLoader.ts new file mode 100644 index 000000000..ea33db2e2 --- /dev/null +++ b/src/vs/workbench/contrib/webview/common/resourceLoader.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 { VSBuffer } from 'vs/base/common/buffer'; +import { sep } from 'vs/base/common/path'; +import { startsWith, endsWith } from 'vs/base/common/strings'; +import { URI } from 'vs/base/common/uri'; +import { IFileService } from 'vs/platform/files/common/files'; +import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; +import { getWebviewContentMimeType } from 'vs/workbench/contrib/webview/common/mimeTypes'; + +class Success { + readonly type = 'success'; + + constructor( + public readonly data: VSBuffer, + public readonly mimeType: string + ) { } +} + +const Failed = new class { readonly type = 'failed'; }; +const AccessDenied = new class { readonly type = 'access-denied'; }; + +type LocalResourceResponse = Success | typeof Failed | typeof AccessDenied; + +async function resolveContent( + fileService: IFileService, + resource: URI, + mime: string +): Promise { + try { + const contents = await fileService.readFile(resource); + return new Success(contents.value, mime); + } catch (err) { + console.log(err); + return Failed; + } +} + +export async function loadLocalResource( + requestUri: URI, + fileService: IFileService, + extensionLocation: URI | undefined, + getRoots: () => ReadonlyArray +): Promise { + const normalizedPath = requestUri.with({ + scheme: 'file', + fragment: '', + query: '', + }); + + for (const root of getRoots()) { + if (!containsResource(root, normalizedPath)) { + continue; + } + + if (extensionLocation && extensionLocation.scheme === REMOTE_HOST_SCHEME) { + const redirectedUri = URI.from({ + scheme: REMOTE_HOST_SCHEME, + authority: extensionLocation.authority, + path: '/vscode-resource', + query: JSON.stringify({ + requestResourcePath: requestUri.path + }) + }); + return resolveContent(fileService, redirectedUri, getWebviewContentMimeType(requestUri)); + } else { + return resolveContent(fileService, normalizedPath, getWebviewContentMimeType(normalizedPath)); + } + } + + return AccessDenied; +} + +function containsResource(root: URI, resource: URI): boolean { + const rootPath = root.fsPath + (endsWith(root.fsPath, sep) ? '' : sep); + return startsWith(resource.fsPath, rootPath); +} diff --git a/src/vs/workbench/contrib/webview/common/themeing.ts b/src/vs/workbench/contrib/webview/common/themeing.ts new file mode 100644 index 000000000..5f0649247 --- /dev/null +++ b/src/vs/workbench/contrib/webview/common/themeing.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 { EDITOR_FONT_DEFAULTS, IEditorOptions } from 'vs/editor/common/config/editorOptions'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import * as colorRegistry from 'vs/platform/theme/common/colorRegistry'; +import { ITheme, LIGHT, DARK } from 'vs/platform/theme/common/themeService'; + +interface WebviewThemeData { + readonly activeTheme: string; + readonly styles: { readonly [key: string]: string | number }; +} + +export function getWebviewThemeData( + theme: ITheme, + configurationService: IConfigurationService +): WebviewThemeData { + const configuration = configurationService.getValue('editor'); + const editorFontFamily = configuration.fontFamily || EDITOR_FONT_DEFAULTS.fontFamily; + const editorFontWeight = configuration.fontWeight || EDITOR_FONT_DEFAULTS.fontWeight; + const editorFontSize = configuration.fontSize || EDITOR_FONT_DEFAULTS.fontSize; + + const exportedColors = colorRegistry.getColorRegistry().getColors().reduce((colors, entry) => { + const color = theme.getColor(entry.id); + if (color) { + colors['vscode-' + entry.id.replace('.', '-')] = color.toString(); + } + return colors; + }, {} as { [key: string]: string }); + + const styles = { + 'vscode-font-family': '-apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "Ubuntu", "Droid Sans", ans-serif', + 'vscode-font-weight': 'normal', + 'vscode-font-size': '13px', + 'vscode-editor-font-family': editorFontFamily, + 'vscode-editor-font-weight': editorFontWeight, + 'vscode-editor-font-size': editorFontSize, + ...exportedColors + }; + + const activeTheme = ApiThemeClassName.fromTheme(theme); + return { styles, activeTheme }; +} + +enum ApiThemeClassName { + light = 'vscode-light', + dark = 'vscode-dark', + highContrast = 'vscode-high-contrast' +} + +namespace ApiThemeClassName { + export function fromTheme(theme: ITheme): ApiThemeClassName { + if (theme.type === LIGHT) { + return ApiThemeClassName.light; + } else if (theme.type === DARK) { + return ApiThemeClassName.dark; + } else { + return ApiThemeClassName.highContrast; + } + } +} \ No newline at end of file diff --git a/src/vs/workbench/contrib/webview/common/webview.ts b/src/vs/workbench/contrib/webview/common/webview.ts index 3358c27dc..d6a73ff5d 100644 --- a/src/vs/workbench/contrib/webview/common/webview.ts +++ b/src/vs/workbench/contrib/webview/common/webview.ts @@ -4,11 +4,13 @@ *--------------------------------------------------------------------------------------------*/ import { Event } from 'vs/base/common/event'; +import { IDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; +import * as modes from 'vs/editor/common/modes'; +import * as nls from 'vs/nls'; +import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; -import * as modes from 'vs/editor/common/modes'; /** * Set when the find widget in a webview is visible. @@ -24,11 +26,20 @@ export interface IWebviewService { _serviceBrand: any; createWebview( + id: string, + options: WebviewOptions, + contentOptions: WebviewContentOptions, + ): WebviewElement; + + createWebviewEditorOverlay( + id: string, options: WebviewOptions, contentOptions: WebviewContentOptions, - ): Webview; + ): WebviewEditorOverlay; } +export const WebviewResourceScheme = 'vscode-resource'; + export interface WebviewOptions { readonly allowSvgs?: boolean; readonly extension?: { @@ -36,19 +47,22 @@ export interface WebviewOptions { readonly id?: ExtensionIdentifier; }; readonly enableFindWidget?: boolean; + readonly tryRestoreScrollPosition?: boolean; + readonly retainContextWhenHidden?: boolean; } export interface WebviewContentOptions { readonly allowScripts?: boolean; readonly svgWhiteList?: string[]; readonly localResourceRoots?: ReadonlyArray; - readonly portMappings?: ReadonlyArray; + readonly portMapping?: ReadonlyArray; + readonly enableCommandUris?: boolean; } -export interface Webview { +export interface Webview extends IDisposable { - contents: string; - options: WebviewContentOptions; + html: string; + contentOptions: WebviewContentOptions; initialScrollProgress: number; state: string | undefined; @@ -60,25 +74,31 @@ export interface Webview { sendMessage(data: any): void; update( - value: string, + html: string, options: WebviewContentOptions, retainContextWhenHidden: boolean ): void; layout(): void; - mountTo(parent: HTMLElement): void; focus(): void; - dispose(): void; - - reload(): void; - selectAll(): void; - copy(): void; - paste(): void; - cut(): void; - undo(): void; - redo(): void; showFind(): void; hideFind(): void; } + +export interface WebviewElement extends Webview { + mountTo(parent: HTMLElement): void; +} + +export interface WebviewEditorOverlay extends Webview { + readonly container: HTMLElement; + readonly options: WebviewOptions; + + claim(owner: any): void; + release(owner: any): void; + + getInnerWebview(): Webview | undefined; +} + +export const webviewDeveloperCategory = nls.localize('developer', "Developer"); diff --git a/src/vs/workbench/contrib/webview/electron-browser/pre/electron-index.js b/src/vs/workbench/contrib/webview/electron-browser/pre/electron-index.js index 21e15e0ee..6992535ea 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/pre/electron-index.js +++ b/src/vs/workbench/contrib/webview/electron-browser/pre/electron-index.js @@ -28,16 +28,64 @@ // @ts-ignore const ipcRenderer = require('electron').ipcRenderer; - require('../../browser/pre/main')({ + let isInDevelopmentMode = false; + + /** + * @type {import('../../browser/pre/main').WebviewHost} + */ + const host = { postMessage: (channel, data) => { ipcRenderer.sendToHost(channel, data); }, onMessage: (channel, handler) => { ipcRenderer.on(channel, handler); + }, + focusIframeOnCreate: true, + onIframeLoaded: (newFrame) => { + newFrame.contentWindow.onbeforeunload = () => { + if (isInDevelopmentMode) { // Allow reloads while developing a webview + host.postMessage('do-reload'); + return false; + } + // Block navigation when not in development mode + console.log('prevented webview navigation'); + return false; + }; + + // Electron 4 eats mouseup events from inside webviews + // https://github.com/microsoft/vscode/issues/75090 + // Try to fix this by rebroadcasting mouse moves and mouseups so that we can + // emulate these on the main window + let isMouseDown = false; + newFrame.contentWindow.addEventListener('mousedown', () => { + isMouseDown = true; + }); + + const tryDispatchSyntheticMouseEvent = (e) => { + if (!isMouseDown) { + host.postMessage('synthetic-mouse-event', { type: e.type, screenX: e.screenX, screenY: e.screenY, clientX: e.clientX, clientY: e.clientY }); + } + }; + newFrame.contentWindow.addEventListener('mouseup', e => { + tryDispatchSyntheticMouseEvent(e); + isMouseDown = false; + }); + newFrame.contentWindow.addEventListener('mousemove', tryDispatchSyntheticMouseEvent); } + }; + + host.onMessage('devtools-opened', () => { + isInDevelopmentMode = true; }); document.addEventListener('DOMContentLoaded', () => { registerVscodeResourceScheme(); + + // Forward messages from the embedded iframe + window.onmessage = (message) => { + ipcRenderer.sendToHost(message.data.command, message.data.data); + }; }); + + require('../../browser/pre/main')(host); }()); \ No newline at end of file diff --git a/src/vs/workbench/contrib/webview/electron-browser/webview.contribution.ts b/src/vs/workbench/contrib/webview/electron-browser/webview.contribution.ts index 7b7b2c2dc..084163f04 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webview.contribution.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webview.contribution.ts @@ -3,8 +3,90 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; +import { isMacintosh } from 'vs/base/common/platform'; +import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; +import { InputFocusedContextKey } from 'vs/platform/contextkey/common/contextkeys'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IWebviewService } from 'vs/workbench/contrib/webview/common/webview'; -import { WebviewService } from 'vs/workbench/contrib/webview/electron-browser/webviewService'; +import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; +import { WebviewEditor } from 'vs/workbench/contrib/webview/browser/webviewEditor'; +import { IWebviewService, webviewDeveloperCategory } from 'vs/workbench/contrib/webview/common/webview'; +import * as webviewCommands from 'vs/workbench/contrib/webview/electron-browser/webviewCommands'; +import { ElectronWebviewService } from 'vs/workbench/contrib/webview/electron-browser/webviewService'; -registerSingleton(IWebviewService, WebviewService, true); +registerSingleton(IWebviewService, ElectronWebviewService, true); + +const actionRegistry = Registry.as(ActionExtensions.WorkbenchActions); + +actionRegistry.registerWorkbenchAction( + new SyncActionDescriptor(webviewCommands.OpenWebviewDeveloperToolsAction, webviewCommands.OpenWebviewDeveloperToolsAction.ID, webviewCommands.OpenWebviewDeveloperToolsAction.LABEL), + webviewCommands.OpenWebviewDeveloperToolsAction.ALIAS, + webviewDeveloperCategory); + +function registerWebViewCommands(editorId: string): void { + const contextKeyExpr = ContextKeyExpr.and(ContextKeyExpr.equals('activeEditor', editorId), ContextKeyExpr.not('editorFocus') /* https://github.com/Microsoft/vscode/issues/58668 */); + + (new webviewCommands.SelectAllWebviewEditorCommand({ + id: webviewCommands.SelectAllWebviewEditorCommand.ID, + precondition: ContextKeyExpr.and(contextKeyExpr, ContextKeyExpr.not(InputFocusedContextKey)), + kbOpts: { + primary: KeyMod.CtrlCmd | KeyCode.KEY_A, + weight: KeybindingWeight.EditorContrib + } + })).register(); + + // These commands are only needed on MacOS where we have to disable the menu bar commands + if (isMacintosh) { + (new webviewCommands.CopyWebviewEditorCommand({ + id: webviewCommands.CopyWebviewEditorCommand.ID, + precondition: ContextKeyExpr.and(contextKeyExpr, ContextKeyExpr.not(InputFocusedContextKey)), + kbOpts: { + primary: KeyMod.CtrlCmd | KeyCode.KEY_C, + weight: KeybindingWeight.EditorContrib + } + })).register(); + + (new webviewCommands.PasteWebviewEditorCommand({ + id: webviewCommands.PasteWebviewEditorCommand.ID, + precondition: ContextKeyExpr.and(contextKeyExpr, ContextKeyExpr.not(InputFocusedContextKey)), + kbOpts: { + primary: KeyMod.CtrlCmd | KeyCode.KEY_V, + weight: KeybindingWeight.EditorContrib + } + })).register(); + + (new webviewCommands.CutWebviewEditorCommand({ + id: webviewCommands.CutWebviewEditorCommand.ID, + precondition: ContextKeyExpr.and(contextKeyExpr, ContextKeyExpr.not(InputFocusedContextKey)), + kbOpts: { + primary: KeyMod.CtrlCmd | KeyCode.KEY_X, + weight: KeybindingWeight.EditorContrib + } + })).register(); + + (new webviewCommands.UndoWebviewEditorCommand({ + id: webviewCommands.UndoWebviewEditorCommand.ID, + precondition: ContextKeyExpr.and(contextKeyExpr, ContextKeyExpr.not(InputFocusedContextKey)), + kbOpts: { + primary: KeyMod.CtrlCmd | KeyCode.KEY_Z, + weight: KeybindingWeight.EditorContrib + } + })).register(); + + (new webviewCommands.RedoWebviewEditorCommand({ + id: webviewCommands.RedoWebviewEditorCommand.ID, + precondition: ContextKeyExpr.and(contextKeyExpr, ContextKeyExpr.not(InputFocusedContextKey)), + kbOpts: { + primary: KeyMod.CtrlCmd | KeyCode.KEY_Y, + secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z], + mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_Z }, + weight: KeybindingWeight.EditorContrib + } + })).register(); + } +} + +registerWebViewCommands(WebviewEditor.ID); \ No newline at end of file diff --git a/src/vs/workbench/contrib/webview/electron-browser/webviewCommands.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewCommands.ts new file mode 100644 index 000000000..a1d8ecda0 --- /dev/null +++ b/src/vs/workbench/contrib/webview/electron-browser/webviewCommands.ts @@ -0,0 +1,104 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Action } from 'vs/base/common/actions'; +import * as nls from 'vs/nls'; +import { Command, ServicesAccessor } from 'vs/editor/browser/editorExtensions'; +import { WebviewEditor } from 'vs/workbench/contrib/webview/browser/webviewEditor'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { ElectronWebviewBasedWebview } from 'vs/workbench/contrib/webview/electron-browser/webviewElement'; +import { WebviewEditorOverlay } from 'vs/workbench/contrib/webview/common/webview'; + +export class OpenWebviewDeveloperToolsAction extends Action { + static readonly ID = 'workbench.action.webview.openDeveloperTools'; + static readonly ALIAS = 'Open Webview Developer Tools'; + static readonly LABEL = nls.localize('openToolsLabel', "Open Webview Developer Tools"); + + public constructor(id: string, label: string) { + super(id, label); + } + + public run(): Promise { + const elements = document.querySelectorAll('webview.ready'); + for (let i = 0; i < elements.length; i++) { + try { + (elements.item(i) as Electron.WebviewTag).openDevTools(); + } catch (e) { + console.error(e); + } + } + return Promise.resolve(true); + } +} + +export class SelectAllWebviewEditorCommand extends Command { + public static readonly ID = 'editor.action.webvieweditor.selectAll'; + + public runCommand(accessor: ServicesAccessor, args: any): void { + withActiveWebviewBasedWebview(accessor, webview => webview.selectAll()); + } +} + +export class CopyWebviewEditorCommand extends Command { + public static readonly ID = 'editor.action.webvieweditor.copy'; + + public runCommand(accessor: ServicesAccessor, _args: any): void { + withActiveWebviewBasedWebview(accessor, webview => webview.copy()); + } +} + +export class PasteWebviewEditorCommand extends Command { + public static readonly ID = 'editor.action.webvieweditor.paste'; + + public runCommand(accessor: ServicesAccessor, _args: any): void { + withActiveWebviewBasedWebview(accessor, webview => webview.paste()); + } +} + +export class CutWebviewEditorCommand extends Command { + public static readonly ID = 'editor.action.webvieweditor.cut'; + + public runCommand(accessor: ServicesAccessor, _args: any): void { + withActiveWebviewBasedWebview(accessor, webview => webview.cut()); + } +} + +export class UndoWebviewEditorCommand extends Command { + public static readonly ID = 'editor.action.webvieweditor.undo'; + + public runCommand(accessor: ServicesAccessor, args: any): void { + withActiveWebviewBasedWebview(accessor, webview => webview.undo()); + } +} + +export class RedoWebviewEditorCommand extends Command { + public static readonly ID = 'editor.action.webvieweditor.redo'; + + public runCommand(accessor: ServicesAccessor, args: any): void { + withActiveWebviewBasedWebview(accessor, webview => webview.redo()); + } +} + +function getActiveWebviewEditor(accessor: ServicesAccessor): WebviewEditor | undefined { + const editorService = accessor.get(IEditorService); + const activeControl = editorService.activeControl as WebviewEditor; + return activeControl.isWebviewEditor ? activeControl : undefined; +} + +function withActiveWebviewBasedWebview(accessor: ServicesAccessor, f: (webview: ElectronWebviewBasedWebview) => void): void { + const webViewEditor = getActiveWebviewEditor(accessor); + if (webViewEditor) { + webViewEditor.withWebview(webview => { + if (webview instanceof ElectronWebviewBasedWebview) { + f(webview); + } else if ((webview as WebviewEditorOverlay).getInnerWebview) { + const innerWebview = (webview as WebviewEditorOverlay).getInnerWebview(); + if (innerWebview instanceof ElectronWebviewBasedWebview) { + f(innerWebview); + } + } + }); + } +} \ No newline at end of file diff --git a/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts index 1477b88a2..3c030feb2 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts @@ -11,44 +11,19 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { isMacintosh } from 'vs/base/common/platform'; import { endsWith } from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; -import { EDITOR_FONT_DEFAULTS, IEditorOptions } from 'vs/editor/common/config/editorOptions'; import * as modes from 'vs/editor/common/modes'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; -import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; +import { IFileService } from 'vs/platform/files/common/files'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; -import { ITunnelService, RemoteTunnel } from 'vs/platform/remote/common/tunnel'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import * as colorRegistry from 'vs/platform/theme/common/colorRegistry'; -import { DARK, ITheme, IThemeService, LIGHT } from 'vs/platform/theme/common/themeService'; -import { Webview, WebviewContentOptions, WebviewOptions } from 'vs/workbench/contrib/webview/common/webview'; -import { registerFileProtocol, WebviewProtocol } from 'vs/workbench/contrib/webview/electron-browser/webviewProtocols'; +import { ITunnelService } from 'vs/platform/remote/common/tunnel'; +import { ITheme, IThemeService } from 'vs/platform/theme/common/themeService'; +import { WebviewPortMappingManager } from 'vs/workbench/contrib/webview/common/portMapping'; +import { getWebviewThemeData } from 'vs/workbench/contrib/webview/common/themeing'; +import { Webview, WebviewContentOptions, WebviewOptions, WebviewResourceScheme } from 'vs/workbench/contrib/webview/common/webview'; +import { registerFileProtocol } from 'vs/workbench/contrib/webview/electron-browser/webviewProtocols'; import { areWebviewInputOptionsEqual } from '../browser/webviewEditorService'; import { WebviewFindWidget } from '../browser/webviewFindWidget'; -export interface WebviewPortMapping { - readonly port: number; - readonly resolvedPort: number; -} - -export interface WebviewOptions { - readonly allowSvgs?: boolean; - readonly extension?: { - readonly location: URI; - readonly id?: ExtensionIdentifier; - }; - readonly enableFindWidget?: boolean; -} - -export interface WebviewContentOptions { - readonly allowScripts?: boolean; - readonly svgWhiteList?: string[]; - readonly localResourceRoots?: ReadonlyArray; - readonly portMappings?: ReadonlyArray; -} - interface IKeydownEvent { key: string; keyCode: number; @@ -117,8 +92,7 @@ class WebviewProtocolProvider extends Disposable { webview: Electron.WebviewTag, private readonly _extensionLocation: URI | undefined, private readonly _getLocalResourceRoots: () => ReadonlyArray, - private readonly _environmentService: IEnvironmentService, - private readonly _textFileService: ITextFileService, + private readonly _fileService: IFileService, ) { super(); @@ -135,13 +109,7 @@ class WebviewProtocolProvider extends Disposable { return; } - const appRootUri = URI.file(this._environmentService.appRoot); - - registerFileProtocol(contents, WebviewProtocol.CoreResource, this._textFileService, undefined, () => [ - appRootUri - ]); - - registerFileProtocol(contents, WebviewProtocol.VsCodeResource, this._textFileService, this._extensionLocation, () => + registerFileProtocol(contents, WebviewResourceScheme, this._fileService, this._extensionLocation, () => this._getLocalResourceRoots() ); } @@ -149,88 +117,22 @@ class WebviewProtocolProvider extends Disposable { class WebviewPortMappingProvider extends Disposable { - private readonly _tunnels = new Map>(); + private readonly _manager: WebviewPortMappingManager; constructor( session: WebviewSession, extensionLocation: URI | undefined, mappings: () => ReadonlyArray, - private readonly tunnelService: ITunnelService, - extensionId: ExtensionIdentifier | undefined, - @ITelemetryService telemetryService: ITelemetryService + tunnelService: ITunnelService, ) { super(); + this._manager = this._register(new WebviewPortMappingManager(extensionLocation, mappings, tunnelService)); - let hasLogged = false; - - session.onBeforeRequest(async (details) => { - const uri = URI.parse(details.url); - if (uri.scheme !== 'http' && uri.scheme !== 'https') { - return undefined; - } - - const localhostMatch = /^localhost:(\d+)$/.exec(uri.authority); - if (localhostMatch) { - if (!hasLogged && extensionId) { - hasLogged = true; - - /* __GDPR__ - "webview.accessLocalhost" : { - "extension" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } - } - */ - telemetryService.publicLog('webview.accessLocalhost', { extension: extensionId.value }); - } - - const port = +localhostMatch[1]; - for (const mapping of mappings()) { - if (mapping.webviewPort === port) { - if (extensionLocation && extensionLocation.scheme === REMOTE_HOST_SCHEME) { - const tunnel = await this.getOrCreateTunnel(mapping.extensionHostPort); - if (tunnel) { - return { - redirectURL: details.url.replace( - new RegExp(`^${uri.scheme}://localhost:${mapping.webviewPort}/`), - `${uri.scheme}://localhost:${tunnel.tunnelLocalPort}/`) - }; - } - } - - if (mapping.webviewPort !== mapping.extensionHostPort) { - return { - redirectURL: details.url.replace( - new RegExp(`^${uri.scheme}://localhost:${mapping.webviewPort}/`), - `${uri.scheme}://localhost:${mapping.extensionHostPort}/`) - }; - } - } - } - } - - return undefined; + session.onBeforeRequest(async details => { + const redirect = await this._manager.getRedirect(details.url); + return redirect ? { redirectURL: redirect } : undefined; }); } - - dispose() { - super.dispose(); - - for (const tunnel of this._tunnels.values()) { - tunnel.then(tunnel => tunnel.dispose()); - } - this._tunnels.clear(); - } - - private getOrCreateTunnel(remotePort: number): Promise | undefined { - const existing = this._tunnels.get(remotePort); - if (existing) { - return existing; - } - const tunnel = this.tunnelService.openTunnel(remotePort); - if (tunnel) { - this._tunnels.set(remotePort, tunnel); - } - return tunnel; - } } class SvgBlocker extends Disposable { @@ -257,7 +159,8 @@ class SvgBlocker extends Disposable { }); session.onHeadersReceived((details) => { - const contentType: string[] = details.responseHeaders['content-type'] || details.responseHeaders['Content-Type']; + const headers: any = details.responseHeaders; + const contentType: string[] = headers['content-type'] || headers['Content-Type']; if (contentType && Array.isArray(contentType) && contentType.some(x => x.toLowerCase().indexOf('image/svg') >= 0)) { const uri = URI.parse(details.url); if (uri && !this.isAllowedSvg(uri)) { @@ -354,35 +257,43 @@ class WebviewKeyboardHandler extends Disposable { } } +interface WebviewContent { + readonly html: string; + readonly options: WebviewContentOptions; + readonly state: string | undefined; +} -export class WebviewElement extends Disposable implements Webview { - private _webview: Electron.WebviewTag; +export class ElectronWebviewBasedWebview extends Disposable implements Webview { + private _webview: Electron.WebviewTag | undefined; private _ready: Promise; - private _webviewFindWidget: WebviewFindWidget; + private _webviewFindWidget: WebviewFindWidget | undefined; private _findStarted: boolean = false; - private _contents: string = ''; - private _state: string | undefined = undefined; + private content: WebviewContent; + private _focused = false; private readonly _onDidFocus = this._register(new Emitter()); - public get onDidFocus(): Event { return this._onDidFocus.event; } + public readonly onDidFocus: Event = this._onDidFocus.event; constructor( private readonly _options: WebviewOptions, - private _contentOptions: WebviewContentOptions, + contentOptions: WebviewContentOptions, @IInstantiationService instantiationService: IInstantiationService, @IThemeService themeService: IThemeService, - @IEnvironmentService environmentService: IEnvironmentService, - @ITextFileService textFileService: ITextFileService, + @IFileService fileService: IFileService, @ITunnelService tunnelService: ITunnelService, - @ITelemetryService telemetryService: ITelemetryService, @IConfigurationService private readonly _configurationService: IConfigurationService, ) { super(); + this.content = { + html: '', + options: contentOptions, + state: undefined + }; + this._webview = document.createElement('webview'); this._webview.setAttribute('partition', `webview${Date.now()}`); - this._webview.setAttribute('webpreferences', 'contextIsolation=yes'); this._webview.style.flex = '0 1'; @@ -394,8 +305,8 @@ export class WebviewElement extends Disposable implements Webview { this._webview.src = 'data:text/html;charset=utf-8,%3C%21DOCTYPE%20html%3E%0D%0A%3Chtml%20lang%3D%22en%22%20style%3D%22width%3A%20100%25%3B%20height%3A%20100%25%22%3E%0D%0A%3Chead%3E%0D%0A%09%3Ctitle%3EVirtual%20Document%3C%2Ftitle%3E%0D%0A%3C%2Fhead%3E%0D%0A%3Cbody%20style%3D%22margin%3A%200%3B%20overflow%3A%20hidden%3B%20width%3A%20100%25%3B%20height%3A%20100%25%22%3E%0D%0A%3C%2Fbody%3E%0D%0A%3C%2Fhtml%3E'; this._ready = new Promise(resolve => { - const subscription = this._register(addDisposableListener(this._webview, 'ipc-message', (event) => { - if (event.channel === 'webview-ready') { + const subscription = this._register(addDisposableListener(this._webview!, 'ipc-message', (event) => { + if (this._webview && event.channel === 'webview-ready') { // console.info('[PID Webview] ' event.args[0]); addClass(this._webview, 'ready'); // can be found by debug command @@ -410,21 +321,18 @@ export class WebviewElement extends Disposable implements Webview { this._register(new WebviewProtocolProvider( this._webview, this._options.extension ? this._options.extension.location : undefined, - () => (this._contentOptions.localResourceRoots || []), - environmentService, - textFileService)); + () => (this.content.options.localResourceRoots || []), + fileService)); this._register(new WebviewPortMappingProvider( session, _options.extension ? _options.extension.location : undefined, - () => (this._contentOptions.portMappings || []), + () => (this.content.options.portMapping || []), tunnelService, - _options.extension ? _options.extension.id : undefined, - telemetryService )); if (!this._options.allowSvgs) { - const svgBlocker = this._register(new SvgBlocker(session, this._contentOptions)); + const svgBlocker = this._register(new SvgBlocker(session, this.content.options)); svgBlocker.onDidBlockSvg(() => this.onDidBlockSvg()); } @@ -437,7 +345,7 @@ export class WebviewElement extends Disposable implements Webview { this.layout(); // Workaround for https://github.com/electron/electron/issues/14474 - if (this._focused || document.activeElement === this._webview) { + if (this._webview && (this._focused || document.activeElement === this._webview)) { this._webview.blur(); this._webview.focus(); } @@ -446,6 +354,10 @@ export class WebviewElement extends Disposable implements Webview { console.error('embedded page crashed'); })); this._register(addDisposableListener(this._webview, 'ipc-message', (event) => { + if (!this._webview) { + return; + } + switch (event.channel) { case 'onmessage': if (event.args && event.args.length) { @@ -458,6 +370,18 @@ export class WebviewElement extends Disposable implements Webview { this._onDidClickLink.fire(URI.parse(uri)); return; + case 'synthetic-mouse-event': + { + const rawEvent = event.args[0]; + const bounds = this._webview.getBoundingClientRect(); + window.dispatchEvent(new MouseEvent(rawEvent.type, { + ...rawEvent, + clientX: rawEvent.clientX + bounds.left, + clientY: rawEvent.clientY + bounds.top, + })); + return; + } + case 'did-set-content': this._webview.style.flex = ''; this._webview.style.width = '100%'; @@ -476,8 +400,9 @@ export class WebviewElement extends Disposable implements Webview { return; case 'do-update-state': - this._state = event.args[0]; - this._onDidUpdateState.fire(this._state); + const state = event.args[0]; + this.state = state; + this._onDidUpdateState.fire(state); return; case 'did-focus': @@ -498,10 +423,14 @@ export class WebviewElement extends Disposable implements Webview { } this.style(themeService.getTheme()); - themeService.onThemeChange(this.style, this, this._toDispose); + this._register(themeService.onThemeChange(this.style, this)); } public mountTo(parent: HTMLElement) { + if (!this._webview) { + return; + } + if (this._webviewFindWidget) { parent.appendChild(this._webviewFindWidget.getDomNode()!); } @@ -513,10 +442,13 @@ export class WebviewElement extends Disposable implements Webview { if (this._webview.parentElement) { this._webview.parentElement.removeChild(this._webview); } + this._webview = undefined; } - this._webview = undefined!; - this._webviewFindWidget = undefined!; + if (this._webviewFindWidget) { + this._webviewFindWidget.dispose(); + this._webviewFindWidget = undefined; + } super.dispose(); } @@ -532,9 +464,13 @@ export class WebviewElement extends Disposable implements Webview { private readonly _onMessage = this._register(new Emitter()); public readonly onMessage = this._onMessage.event; - private _send(channel: string, ...args: any[]): void { + private _send(channel: string, data?: any): void { this._ready - .then(() => this._webview.send(channel, ...args)) + .then(() => { + if (this._webview) { + this._webview.send(channel, data); + } + }) .catch(err => console.error(err)); } @@ -542,46 +478,60 @@ export class WebviewElement extends Disposable implements Webview { this._send('initial-scroll-position', value); } - public set state(value: string | undefined) { - this._state = value; + public set state(state: string | undefined) { + this.content = { + html: this.content.html, + options: this.content.options, + state, + }; } - public set options(value: WebviewContentOptions) { - if (this._contentOptions && areWebviewInputOptionsEqual(value, this._contentOptions)) { + public set contentOptions(options: WebviewContentOptions) { + if (areWebviewInputOptionsEqual(options, this.content.options)) { return; } - this._contentOptions = value; - this._send('content', { - contents: this._contents, - options: this._contentOptions, - state: this._state - }); + this.content = { + html: this.content.html, + options: options, + state: this.content.state, + }; + this.doUpdateContent(); } - public set contents(value: string) { - this._contents = value; - this._send('content', { - contents: value, - options: this._contentOptions, - state: this._state - }); + public set html(value: string) { + this.content = { + html: value, + options: this.content.options, + state: this.content.state, + }; + this.doUpdateContent(); } - public update(value: string, options: WebviewContentOptions, retainContextWhenHidden: boolean) { - if (retainContextWhenHidden && value === this._contents && this._contentOptions && areWebviewInputOptionsEqual(options, this._contentOptions)) { + public update(html: string, options: WebviewContentOptions, retainContextWhenHidden: boolean) { + if (retainContextWhenHidden && html === this.content.html && areWebviewInputOptionsEqual(options, this.content.options)) { return; } - this._contents = value; - this._contentOptions = options; + this.content = { + html: html, + options: options, + state: this.content.state, + }; + this.doUpdateContent(); + } + + private doUpdateContent() { this._send('content', { - contents: this._contents, - options: this._contentOptions, - state: this._state + contents: this.content.html, + options: this.content.options, + state: this.content.state }); } public focus(): void { + if (!this._webview) { + return; + } this._webview.focus(); this._send('focus'); @@ -607,32 +557,8 @@ export class WebviewElement extends Disposable implements Webview { } private style(theme: ITheme): void { - const configuration = this._configurationService.getValue('editor'); - const editorFontFamily = configuration.fontFamily || EDITOR_FONT_DEFAULTS.fontFamily; - const editorFontWeight = configuration.fontWeight || EDITOR_FONT_DEFAULTS.fontWeight; - const editorFontSize = configuration.fontSize || EDITOR_FONT_DEFAULTS.fontSize; - - const exportedColors = colorRegistry.getColorRegistry().getColors().reduce((colors, entry) => { - const color = theme.getColor(entry.id); - if (color) { - colors['vscode-' + entry.id.replace('.', '-')] = color.toString(); - } - return colors; - }, {} as { [key: string]: string }); - - - const styles = { - 'vscode-font-family': '-apple-system, BlinkMacSystemFont, "Segoe WPC", "Segoe UI", "Ubuntu", "Droid Sans", sans-serif', - 'vscode-font-weight': 'normal', - 'vscode-font-size': '13px', - 'vscode-editor-font-family': editorFontFamily, - 'vscode-editor-font-weight': editorFontWeight, - 'vscode-editor-font-size': editorFontSize, - ...exportedColors - }; - - const activeTheme = ApiThemeClassName.fromTheme(theme); - this._send('styles', styles, activeTheme); + const { styles, activeTheme } = getWebviewThemeData(theme, this._configurationService); + this._send('styles', { styles, activeTheme }); if (this._webviewFindWidget) { this._webviewFindWidget.updateTheme(theme); @@ -640,6 +566,9 @@ export class WebviewElement extends Disposable implements Webview { } public layout(): void { + if (!this._webview) { + return; + } const contents = this._webview.getWebContents(); if (!contents || contents.isDestroyed()) { return; @@ -658,7 +587,7 @@ export class WebviewElement extends Disposable implements Webview { } public startFind(value: string, options?: Electron.FindInPageOptions) { - if (!value) { + if (!value || !this._webview) { return; } @@ -685,6 +614,10 @@ export class WebviewElement extends Disposable implements Webview { * @param value The string to search for. Empty strings are ignored. */ public find(value: string, previous: boolean): void { + if (!this._webview) { + return; + } + // Searching with an empty value will throw an exception if (!value) { return; @@ -700,6 +633,9 @@ export class WebviewElement extends Disposable implements Webview { } public stopFind(keepSelection?: boolean): void { + if (!this._webview) { + return; + } this._findStarted = false; this._webview.stopFindInPage(keepSelection ? 'keepSelection' : 'clearSelection'); } @@ -717,49 +653,42 @@ export class WebviewElement extends Disposable implements Webview { } public reload() { - this.contents = this._contents; + this.doUpdateContent(); } public selectAll() { - this._webview.selectAll(); + if (this._webview) { + this._webview.selectAll(); + } } public copy() { - this._webview.copy(); + if (this._webview) { + this._webview.copy(); + } } public paste() { - this._webview.paste(); + if (this._webview) { + this._webview.paste(); + } } public cut() { - this._webview.cut(); + if (this._webview) { + this._webview.cut(); + } } public undo() { - this._webview.undo(); + if (this._webview) { + this._webview.undo(); + } } public redo() { - this._webview.redo(); - } -} - - -enum ApiThemeClassName { - light = 'vscode-light', - dark = 'vscode-dark', - highContrast = 'vscode-high-contrast' -} - -namespace ApiThemeClassName { - export function fromTheme(theme: ITheme): ApiThemeClassName { - if (theme.type === LIGHT) { - return ApiThemeClassName.light; - } else if (theme.type === DARK) { - return ApiThemeClassName.dark; - } else { - return ApiThemeClassName.highContrast; + if (this._webview) { + this._webview.redo(); } } } diff --git a/src/vs/workbench/contrib/webview/electron-browser/webviewProtocols.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewProtocols.ts index 37ea9bbf6..95d41d147 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webviewProtocols.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webviewProtocols.ts @@ -2,64 +2,36 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { getMediaMime, MIME_UNKNOWN } from 'vs/base/common/mime'; -import { extname, sep } from 'vs/base/common/path'; -import { startsWith } from 'vs/base/common/strings'; +import * as electron from 'electron'; import { URI } from 'vs/base/common/uri'; -import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; -import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; - -export const enum WebviewProtocol { - CoreResource = 'vscode-core-resource', - VsCodeResource = 'vscode-resource', -} - -function resolveContent(textFileService: ITextFileService, resource: URI, mime: string, callback: any): void { - textFileService.read(resource, { encoding: 'binary' }).then(contents => { - callback({ - data: Buffer.from(contents.value, contents.encoding), - mimeType: mime - }); - }, (err) => { - console.log(err); - callback({ error: -2 /* FAILED: https://cs.chromium.org/chromium/src/net/base/net_error_list.h */ }); - }); -} +import { IFileService } from 'vs/platform/files/common/files'; +import { loadLocalResource } from 'vs/workbench/contrib/webview/common/resourceLoader'; export function registerFileProtocol( - contents: Electron.WebContents, - protocol: WebviewProtocol, - textFileService: ITextFileService, + contents: electron.WebContents, + protocol: string, + fileService: IFileService, extensionLocation: URI | undefined, getRoots: () => ReadonlyArray ) { - contents.session.protocol.registerBufferProtocol(protocol, (request, callback: any) => { - const requestPath = URI.parse(request.url).path; - const normalizedPath = URI.file(requestPath); - for (const root of getRoots()) { - if (!startsWith(normalizedPath.fsPath, root.fsPath + sep)) { - continue; - } - - if (extensionLocation && extensionLocation.scheme === REMOTE_HOST_SCHEME) { - const requestUri = URI.parse(request.url); - const redirectedUri = URI.from({ - scheme: REMOTE_HOST_SCHEME, - authority: extensionLocation.authority, - path: '/vscode-resource', - query: JSON.stringify({ - requestResourcePath: requestUri.path - }) + contents.session.protocol.registerBufferProtocol(protocol, async (request, callback: any) => { + try { + const result = await loadLocalResource(URI.parse(request.url), fileService, extensionLocation, getRoots); + if (result.type === 'success') { + return callback({ + data: Buffer.from(result.data.buffer), + mimeType: result.mimeType }); - resolveContent(textFileService, redirectedUri, getMimeType(requestUri), callback); - return; - } else { - resolveContent(textFileService, normalizedPath, getMimeType(normalizedPath), callback); - return; } + if (result.type === 'access-denied') { + console.error('Webview: Cannot load resource outside of protocol root'); + return callback({ error: -10 /* ACCESS_DENIED: https://cs.chromium.org/chromium/src/net/base/net_error_list.h */ }); + } + } catch { + // noop } - console.error('Webview: Cannot load resource outside of protocol root'); - callback({ error: -10 /* ACCESS_DENIED: https://cs.chromium.org/chromium/src/net/base/net_error_list.h */ }); + + return callback({ error: -2 /* FAILED: https://cs.chromium.org/chromium/src/net/base/net_error_list.h */ }); }, (error) => { if (error) { console.error(`Failed to register '${protocol}' protocol`); @@ -67,20 +39,3 @@ export function registerFileProtocol( }); } -const webviewMimeTypes = { - '.svg': 'image/svg+xml', - '.txt': 'text/plain', - '.css': 'text/css', - '.js': 'application/javascript', - '.json': 'application/json', - '.html': 'text/html', - '.htm': 'text/html', - '.xhtml': 'application/xhtml+xml', - '.oft': 'font/otf', - '.xml': 'application/xml', -}; - -function getMimeType(normalizedPath: URI): string { - const ext = extname(normalizedPath.fsPath).toLowerCase(); - return webviewMimeTypes[ext] || getMediaMime(normalizedPath.fsPath) || MIME_UNKNOWN; -} diff --git a/src/vs/workbench/contrib/webview/electron-browser/webviewService.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewService.ts index e341b1864..ae8eb72d0 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webviewService.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webviewService.ts @@ -3,25 +3,39 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IWebviewService, Webview, WebviewContentOptions, WebviewOptions } from 'vs/workbench/contrib/webview/common/webview'; -import { WebviewElement } from 'vs/workbench/contrib/webview/electron-browser/webviewElement'; +import { DynamicWebviewEditorOverlay } from 'vs/workbench/contrib/webview/browser/dynamicWebviewEditorOverlay'; +import { IFrameWebview } from 'vs/workbench/contrib/webview/browser/webviewElement'; +import { IWebviewService, WebviewContentOptions, WebviewEditorOverlay, WebviewElement, WebviewOptions } from 'vs/workbench/contrib/webview/common/webview'; +import { ElectronWebviewBasedWebview } from 'vs/workbench/contrib/webview/electron-browser/webviewElement'; -export class WebviewService implements IWebviewService { +export class ElectronWebviewService implements IWebviewService { _serviceBrand: any; constructor( @IInstantiationService private readonly _instantiationService: IInstantiationService, + @IConfigurationService private readonly _configService: IConfigurationService, ) { } createWebview( + id: string, options: WebviewOptions, contentOptions: WebviewContentOptions - ): Webview { - const element = this._instantiationService.createInstance(WebviewElement, - options, - contentOptions); + ): WebviewElement { + const useExternalEndpoint = this._configService.getValue('webview.experimental.useExternalEndpoint'); + if (useExternalEndpoint) { + return this._instantiationService.createInstance(IFrameWebview, id, options, contentOptions); + } else { + return this._instantiationService.createInstance(ElectronWebviewBasedWebview, options, contentOptions); + } + } - return element; + createWebviewEditorOverlay( + id: string, + options: WebviewOptions, + contentOptions: WebviewContentOptions, + ): WebviewEditorOverlay { + return this._instantiationService.createInstance(DynamicWebviewEditorOverlay, id, options, contentOptions); } } \ No newline at end of file diff --git a/src/vs/workbench/contrib/welcome/gettingStarted/electron-browser/telemetryOptOut.ts b/src/vs/workbench/contrib/welcome/gettingStarted/electron-browser/telemetryOptOut.ts index 2c31578ab..f137c1a6f 100644 --- a/src/vs/workbench/contrib/welcome/gettingStarted/electron-browser/telemetryOptOut.ts +++ b/src/vs/workbench/contrib/welcome/gettingStarted/electron-browser/telemetryOptOut.ts @@ -13,7 +13,7 @@ import { URI } from 'vs/base/common/uri'; import { localize } from 'vs/nls'; import { onUnexpectedError } from 'vs/base/common/errors'; import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows'; -import { IExperimentService, ExperimentState } from 'vs/workbench/contrib/experiments/node/experimentService'; +import { IExperimentService, ExperimentState } from 'vs/workbench/contrib/experiments/common/experimentService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { language, locale } from 'vs/base/common/platform'; import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; @@ -90,13 +90,13 @@ export class TelemetryOptOut implements IWorkbenchContribution { return undefined; } const extensionToFetchTranslationsFrom = tagResult.firstPage.filter(e => e.publisher === 'MS-CEINTL' && e.name.indexOf('vscode-language-pack') === 0)[0] || tagResult.firstPage[0]; - if (!extensionToFetchTranslationsFrom.assets || !extensionToFetchTranslationsFrom.assets.coreTranslations) { + if (!extensionToFetchTranslationsFrom.assets || !extensionToFetchTranslationsFrom.assets.coreTranslations.length) { return undefined; } return this.galleryService.getCoreTranslation(extensionToFetchTranslationsFrom, locale!) .then(translation => { - const translationsFromPack = translation && translation.contents ? translation.contents['vs/workbench/contrib/welcome/gettingStarted/electron-browser/telemetryOptOut'] : {}; + const translationsFromPack: any = translation && translation.contents ? translation.contents['vs/workbench/contrib/welcome/gettingStarted/electron-browser/telemetryOptOut'] : {}; if (!!translationsFromPack[promptMessageKey] && !!translationsFromPack[yesLabelKey] && !!translationsFromPack[noLabelKey]) { promptMessage = translationsFromPack[promptMessageKey].replace('{0}', this.privacyUrl) + ' (Please help Microsoft improve Visual Studio Code by allowing the collection of usage data.)'; yesLabel = translationsFromPack[yesLabelKey] + ' (Yes)'; @@ -109,12 +109,14 @@ export class TelemetryOptOut implements IWorkbenchContribution { } const logTelemetry = (optout?: boolean) => { - /* __GDPR__ - "experiments:optout" : { - "optOut": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } - } - */ - this.telemetryService.publicLog('experiments:optout', typeof optout === 'boolean' ? { optout } : {}); + type ExperimentsOptOutClassification = { + optout?: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + }; + + type ExperimentsOptOutEvent = { + optout?: boolean; + }; + this.telemetryService.publicLog2('experiments:optout', typeof optout === 'boolean' ? { optout } : {}); }; queryPromise.then(() => { diff --git a/src/vs/workbench/contrib/welcome/overlay/browser/welcomeOverlay.ts b/src/vs/workbench/contrib/welcome/overlay/browser/welcomeOverlay.ts index 84b1219c4..a56cff41c 100644 --- a/src/vs/workbench/contrib/welcome/overlay/browser/welcomeOverlay.ts +++ b/src/vs/workbench/contrib/welcome/overlay/browser/welcomeOverlay.ts @@ -15,7 +15,7 @@ import { Action } from 'vs/base/common/actions'; 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'; +import { Disposable } from 'vs/base/common/lifecycle'; import { RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { KeyCode } from 'vs/base/common/keyCodes'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -150,9 +150,8 @@ export class HideWelcomeOverlayAction extends Action { } } -class WelcomeOverlay { +class WelcomeOverlay extends Disposable { - private _toDispose: IDisposable[] = []; private _overlayVisible: IContextKey; private _overlay: HTMLElement; @@ -163,6 +162,7 @@ class WelcomeOverlay { @IContextKeyService private readonly _contextKeyService: IContextKeyService, @IKeybindingService private readonly keybindingService: IKeybindingService ) { + super(); this._overlayVisible = OVERLAY_VISIBLE.bindTo(this._contextKeyService); this.create(); } @@ -177,7 +177,7 @@ class WelcomeOverlay { this._overlay.style.display = 'none'; this._overlay.tabIndex = -1; - this._toDispose.push(dom.addStandardDisposableListener(this._overlay, 'click', () => this.hide())); + this._register(dom.addStandardDisposableListener(this._overlay, 'click', () => this.hide())); this.commandService.onWillExecuteCommand(() => this.hide()); dom.append(this._overlay, $('.commandPalettePlaceholder')); @@ -214,7 +214,7 @@ class WelcomeOverlay { } private updateProblemsKey() { - const problems = document.querySelector('.task-statusbar-item'); + const problems = document.querySelector('div[id="workbench.parts.statusbar"] .statusbar-item.left .octicon.octicon-warning'); const key = this._overlay.querySelector('.key.problems') as HTMLElement; if (problems instanceof HTMLElement) { const target = problems.getBoundingClientRect(); @@ -237,10 +237,6 @@ class WelcomeOverlay { this._overlayVisible.reset(); } } - - dispose() { - this._toDispose = dispose(this._toDispose); - } } Registry.as(Extensions.WorkbenchActions) diff --git a/src/vs/workbench/contrib/welcome/page/browser/vs_code_welcome_page.ts b/src/vs/workbench/contrib/welcome/page/browser/vs_code_welcome_page.ts index d4cd52581..be63cb5a8 100644 --- a/src/vs/workbench/contrib/welcome/page/browser/vs_code_welcome_page.ts +++ b/src/vs/workbench/contrib/welcome/page/browser/vs_code_welcome_page.ts @@ -44,6 +44,7 @@ export default () => `
  • ${escape(localize('welcomePage.productDocumentation', "Product documentation"))}
  • ${escape(localize('welcomePage.gitHubRepository', "GitHub repository"))}
  • ${escape(localize('welcomePage.stackOverflow', "Stack Overflow"))}
  • +
  • ${escape(localize('welcomePage.newsletterSignup', "Join our Newsletter"))}
  • diff --git a/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts index b26ccbb85..ab0d4193c 100644 --- a/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts +++ b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts @@ -17,15 +17,16 @@ import { IWindowService, IURIToOpen } from 'vs/platform/windows/common/windows'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { localize } from 'vs/nls'; -import { Action } from 'vs/base/common/actions'; +import { Action, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { Schemas } from 'vs/base/common/network'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { getInstalledExtensions, IExtensionStatus, onExtensionChanged, isKeymapExtension } from 'vs/workbench/contrib/extensions/common/extensionsUtils'; -import { IExtensionEnablementService, IExtensionManagementService, IExtensionGalleryService, IExtensionTipsService, EnablementState, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementService, IExtensionGalleryService, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionEnablementService, EnablementState, IExtensionTipsService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { used } from 'vs/workbench/contrib/welcome/page/browser/vs_code_welcome_page'; import { ILifecycleService, StartupKind } from 'vs/platform/lifecycle/common/lifecycle'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { Disposable } from 'vs/base/common/lifecycle'; import { splitName } from 'vs/base/common/labels'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { registerColor, focusBorder, textLinkForeground, textLinkActiveForeground, foreground, descriptionForeground, contrastBorder, activeContrastBorder } from 'vs/platform/theme/common/colorRegistry'; @@ -151,7 +152,7 @@ const extensionPacks: ExtensionSuggestion[] = [ // { 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' }, + { name: localize('welcomePage.docker', "Docker"), id: 'ms-azuretools.vscode-docker' }, ]; const keymapExtensions: ExtensionSuggestion[] = [ @@ -245,9 +246,7 @@ const keymapStrings: Strings = { const welcomeInputTypeId = 'workbench.editors.welcomePageInput'; -class WelcomePage { - - private disposables: IDisposable[] = []; +class WelcomePage extends Disposable { readonly editorInput: WalkThroughInput; @@ -267,7 +266,8 @@ class WelcomePage { @ILifecycleService lifecycleService: ILifecycleService, @ITelemetryService private readonly telemetryService: ITelemetryService ) { - this.disposables.push(lifecycleService.onShutdown(() => this.dispose())); + super(); + this._register(lifecycleService.onShutdown(() => this.dispose())); const recentlyOpened = this.windowService.getRecentlyOpened(); const installedExtensions = this.instantiationService.invokeFunction(getInstalledExtensions); @@ -321,14 +321,14 @@ class WelcomePage { ul.append(...listEntries, moreRecent); }; updateEntries(); - this.disposables.push(this.labelService.onDidChangeFormatters(updateEntries)); + this._register(this.labelService.onDidChangeFormatters(updateEntries)); }).then(undefined, onUnexpectedError); this.addExtensionList(container, '.extensionPackList', extensionPacks, extensionPackStrings); this.addExtensionList(container, '.keymapList', keymapExtensions, keymapStrings); this.updateInstalledExtensions(container, installedExtensions); - this.disposables.push(this.instantiationService.invokeFunction(onExtensionChanged)(ids => { + this._register(this.instantiationService.invokeFunction(onExtensionChanged)(ids => { for (const id of ids) { if (container.querySelector(`.installExtension[data-extension="${id.id}"], .enabledExtension[data-extension="${id.id}"]`)) { const installedExtensions = this.instantiationService.invokeFunction(getInstalledExtensions); @@ -361,13 +361,7 @@ class WelcomePage { a.setAttribute('aria-label', localize('welcomePage.openFolderWithPath', "Open folder {0} with path {1}", name, parentPath)); 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', { + this.telemetryService.publicLog2('workbenchActionExecuted', { id: 'openRecentFolder', from: telemetryFrom }); @@ -464,7 +458,7 @@ class WelcomePage { .then(installed => { const local = installed.filter(i => areSameExtensions(extension.identifier, i.identifier))[0]; // TODO: Do this as part of the install to avoid multiple events. - return this.extensionEnablementService.setEnablement([local], EnablementState.Disabled).then(() => local); + return this.extensionEnablementService.setEnablement([local], EnablementState.DisabledGlobally).then(() => local); }); }); @@ -479,12 +473,12 @@ class WelcomePage { this.notificationService.info(strings.installing.replace('{0}', extensionSuggestion.name)); }, 300); const extensionsToDisable = extensions.filter(extension => isKeymapExtension(this.tipsService, extension) && extension.globallyEnabled).map(extension => extension.local); - extensionsToDisable.length ? this.extensionEnablementService.setEnablement(extensionsToDisable, EnablementState.Disabled) : Promise.resolve() + extensionsToDisable.length ? this.extensionEnablementService.setEnablement(extensionsToDisable, EnablementState.DisabledGlobally) : Promise.resolve() .then(() => { return foundAndInstalled.then(foundExtension => { messageDelay.cancel(); if (foundExtension) { - return this.extensionEnablementService.setEnablement([foundExtension], EnablementState.Enabled) + return this.extensionEnablementService.setEnablement([foundExtension], EnablementState.EnabledGlobally) .then(() => { /* __GDPR__FRAGMENT__ "WelcomePageInstalled-2" : { @@ -593,10 +587,6 @@ class WelcomePage { }); }).then(undefined, onUnexpectedError); } - - dispose(): void { - this.disposables = dispose(this.disposables); - } } export class WelcomeInputFactory implements IEditorInputFactory { diff --git a/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts index a51b73abb..afd74dc85 100644 --- a/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts +++ b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts @@ -8,7 +8,7 @@ import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableEle import { ScrollbarVisibility } from 'vs/base/common/scrollable'; import * as strings from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; -import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { EditorOptions, IEditorMemento } from 'vs/workbench/common/editor'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -56,7 +56,7 @@ export class WalkThroughPart extends BaseEditor { static readonly ID: string = 'workbench.editor.walkThroughPart'; - private disposables: IDisposable[] = []; + private readonly disposables = new DisposableStore(); private contentDisposables: IDisposable[] = []; private content: HTMLDivElement; private scrollbar: DomScrollableElement; @@ -92,13 +92,13 @@ export class WalkThroughPart extends BaseEditor { horizontal: ScrollbarVisibility.Auto, vertical: ScrollbarVisibility.Auto }); - this.disposables.push(this.scrollbar); + this.disposables.add(this.scrollbar); container.appendChild(this.scrollbar.getDomNode()); this.registerFocusHandlers(); this.registerClickHandler(); - this.disposables.push(this.scrollbar.onScroll(e => this.updatedScrollPosition())); + this.disposables.add(this.scrollbar.onScroll(e => this.updatedScrollPosition())); } private updatedScrollPosition() { @@ -120,16 +120,16 @@ export class WalkThroughPart extends BaseEditor { } private registerFocusHandlers() { - this.disposables.push(this.addEventListener(this.content, 'mousedown', e => { + this.disposables.add(this.addEventListener(this.content, 'mousedown', e => { this.focus(); })); - this.disposables.push(this.addEventListener(this.content, 'focus', e => { + this.disposables.add(this.addEventListener(this.content, 'focus', e => { this.editorFocus.set(true); })); - this.disposables.push(this.addEventListener(this.content, 'blur', e => { + this.disposables.add(this.addEventListener(this.content, 'blur', e => { this.editorFocus.reset(); })); - this.disposables.push(this.addEventListener(this.content, 'focusin', e => { + this.disposables.add(this.addEventListener(this.content, 'focusin', (e: FocusEvent) => { // Work around scrolling as side-effect of setting focus on the offscreen zone widget (#18929) if (e.target instanceof HTMLElement && e.target.classList.contains('zone-widget-container')) { const scrollPosition = this.scrollbar.getScrollPosition(); @@ -301,12 +301,6 @@ export class WalkThroughPart extends BaseEditor { const div = innerContent.querySelector(`#${id.replace(/\./g, '\\.')}`) as HTMLElement; const options = this.getEditorOptions(snippet.textEditorModel.getModeId()); - /* __GDPR__FRAGMENT__ - "EditorTelemetryData" : { - "target" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "snippet": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } - } - */ const telemetryData = { target: this.input instanceof WalkThroughInput ? this.input.getTelemetryFrom() : undefined, snippet: i @@ -356,43 +350,33 @@ export class WalkThroughPart extends BaseEditor { } })); + type WalkThroughSnippetInteractionClassification = { + from?: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + type: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + snippet: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + }; + type WalkThroughSnippetInteractionEvent = { + from?: string, + type: string, + snippet: number + }; + this.contentDisposables.push(Event.once(editor.onMouseDown)(() => { - /* __GDPR__ - "walkThroughSnippetInteraction" : { - "from" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "type": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "snippet": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } - } - */ - this.telemetryService.publicLog('walkThroughSnippetInteraction', { + this.telemetryService.publicLog2('walkThroughSnippetInteraction', { from: this.input instanceof WalkThroughInput ? this.input.getTelemetryFrom() : undefined, type: 'mouseDown', snippet: i }); })); this.contentDisposables.push(Event.once(editor.onKeyDown)(() => { - /* __GDPR__ - "walkThroughSnippetInteraction" : { - "from" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "type": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "snippet": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } - } - */ - this.telemetryService.publicLog('walkThroughSnippetInteraction', { + this.telemetryService.publicLog2('walkThroughSnippetInteraction', { from: this.input instanceof WalkThroughInput ? this.input.getTelemetryFrom() : undefined, type: 'keyDown', snippet: i }); })); this.contentDisposables.push(Event.once(editor.onDidChangeModelContent)(() => { - /* __GDPR__ - "walkThroughSnippetInteraction" : { - "from" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "type": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "snippet": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } - } - */ - this.telemetryService.publicLog('walkThroughSnippetInteraction', { + this.telemetryService.publicLog2('walkThroughSnippetInteraction', { from: this.input instanceof WalkThroughInput ? this.input.getTelemetryFrom() : undefined, type: 'changeModelContent', snippet: i @@ -514,7 +498,7 @@ export class WalkThroughPart extends BaseEditor { dispose(): void { this.editorFocus.reset(); this.contentDisposables = dispose(this.contentDisposables); - this.disposables = dispose(this.disposables); + this.disposables.dispose(); super.dispose(); } } diff --git a/src/vs/workbench/contrib/welcome/walkThrough/common/walkThroughContentProvider.ts b/src/vs/workbench/contrib/welcome/walkThrough/common/walkThroughContentProvider.ts index f76817286..49584361d 100644 --- a/src/vs/workbench/contrib/welcome/walkThrough/common/walkThroughContentProvider.ts +++ b/src/vs/workbench/contrib/welcome/walkThrough/common/walkThroughContentProvider.ts @@ -39,7 +39,7 @@ export class WalkThroughContentProvider implements ITextModelContentProvider, IW return content.then(content => { let codeEditorModel = this.modelService.getModel(resource); if (!codeEditorModel) { - codeEditorModel = this.modelService.createModel(content, this.modeService.createByFilepathOrFirstLine(resource.fsPath), resource); + codeEditorModel = this.modelService.createModel(content, this.modeService.createByFilepathOrFirstLine(resource), resource); } else { this.modelService.updateModel(codeEditorModel, content); } diff --git a/src/vs/workbench/contrib/welcome/walkThrough/common/walkThroughInput.ts b/src/vs/workbench/contrib/welcome/walkThrough/common/walkThroughInput.ts index 338d372c6..6d69a2758 100644 --- a/src/vs/workbench/contrib/welcome/walkThrough/common/walkThroughInput.ts +++ b/src/vs/workbench/contrib/welcome/walkThrough/common/walkThroughInput.ts @@ -6,7 +6,7 @@ import * as strings from 'vs/base/common/strings'; import { EditorInput, EditorModel, ITextEditorModel } from 'vs/workbench/common/editor'; import { URI } from 'vs/base/common/uri'; -import { IReference, IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IReference } from 'vs/base/common/lifecycle'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import * as marked from 'vs/base/common/marked/marked'; import { Schemas } from 'vs/base/common/network'; @@ -46,8 +46,6 @@ export interface WalkThroughInputOptions { export class WalkThroughInput extends EditorInput { - private disposables: IDisposable[] = []; - private promise: Promise | null = null; private maxTopScroll = 0; @@ -80,7 +78,7 @@ export class WalkThroughInput extends EditorInput { return this.options.telemetryFrom; } - getTelemetryDescriptor(): object { + getTelemetryDescriptor(): { [key: string]: unknown } { const descriptor = super.getTelemetryDescriptor(); descriptor['target'] = this.getTelemetryFrom(); /* __GDPR__FRAGMENT__ @@ -139,8 +137,6 @@ export class WalkThroughInput extends EditorInput { } dispose(): void { - this.disposables = dispose(this.disposables); - if (this.promise) { this.promise.then(model => model.dispose()); this.promise = null; diff --git a/src/vs/workbench/electron-browser/actions/developerActions.ts b/src/vs/workbench/electron-browser/actions/developerActions.ts index 5199d7547..4da3b429e 100644 --- a/src/vs/workbench/electron-browser/actions/developerActions.ts +++ b/src/vs/workbench/electron-browser/actions/developerActions.ts @@ -6,16 +6,6 @@ import { Action } from 'vs/base/common/actions'; import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows'; import * as nls from 'vs/nls'; -import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { domEvent } from 'vs/base/browser/event'; -import { Event } from 'vs/base/common/event'; -import { IDisposable, toDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; -import { getDomNodePagePosition, createStyleSheet, createCSSRule, append, $ } from 'vs/base/browser/dom'; -import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { Context } from 'vs/platform/contextkey/browser/contextKeyService'; -import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import { timeout } from 'vs/base/common/async'; -import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; export class ToggleDevToolsAction extends Action { @@ -44,176 +34,3 @@ export class ToggleSharedProcessAction extends Action { return this.windowsService.toggleSharedProcess(); } } - -export class InspectContextKeysAction extends Action { - - static readonly ID = 'workbench.action.inspectContextKeys'; - static LABEL = nls.localize('inspect context keys', "Inspect Context Keys"); - - constructor( - id: string, - label: string, - @IContextKeyService private readonly contextKeyService: IContextKeyService, - @IWindowService private readonly windowService: IWindowService, - ) { - super(id, label); - } - - run(): Promise { - const disposables: IDisposable[] = []; - - const stylesheet = createStyleSheet(); - disposables.push(toDisposable(() => { - if (stylesheet.parentNode) { - stylesheet.parentNode.removeChild(stylesheet); - } - })); - createCSSRule('*', 'cursor: crosshair !important;', stylesheet); - - const hoverFeedback = document.createElement('div'); - document.body.appendChild(hoverFeedback); - disposables.push(toDisposable(() => document.body.removeChild(hoverFeedback))); - - hoverFeedback.style.position = 'absolute'; - hoverFeedback.style.pointerEvents = 'none'; - hoverFeedback.style.backgroundColor = 'rgba(255, 0, 0, 0.5)'; - hoverFeedback.style.zIndex = '1000'; - - const onMouseMove = domEvent(document.body, 'mousemove', true); - disposables.push(onMouseMove(e => { - const target = e.target as HTMLElement; - const position = getDomNodePagePosition(target); - - hoverFeedback.style.top = `${position.top}px`; - hoverFeedback.style.left = `${position.left}px`; - hoverFeedback.style.width = `${position.width}px`; - hoverFeedback.style.height = `${position.height}px`; - })); - - const onMouseDown = Event.once(domEvent(document.body, 'mousedown', true)); - onMouseDown(e => { e.preventDefault(); e.stopPropagation(); }, null, disposables); - - const onMouseUp = Event.once(domEvent(document.body, 'mouseup', true)); - onMouseUp(e => { - e.preventDefault(); - e.stopPropagation(); - - const context = this.contextKeyService.getContext(e.target as HTMLElement) as Context; - console.log(context.collectAllValues()); - this.windowService.openDevTools(); - - dispose(disposables); - }, null, disposables); - - return Promise.resolve(); - } -} - -export class ToggleScreencastModeAction extends Action { - - static readonly ID = 'workbench.action.toggleScreencastMode'; - static LABEL = nls.localize('toggle screencast mode', "Toggle Screencast Mode"); - - static disposable: IDisposable | undefined; - - constructor( - id: string, - label: string, - @IKeybindingService private readonly keybindingService: IKeybindingService, - @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService - ) { - super(id, label); - } - - async run(): Promise { - if (ToggleScreencastModeAction.disposable) { - ToggleScreencastModeAction.disposable.dispose(); - ToggleScreencastModeAction.disposable = undefined; - return; - } - - const container = this.layoutService.getWorkbenchElement(); - - const mouseMarker = append(container, $('div')); - mouseMarker.style.position = 'absolute'; - mouseMarker.style.border = '2px solid red'; - mouseMarker.style.borderRadius = '20px'; - mouseMarker.style.width = '20px'; - mouseMarker.style.height = '20px'; - mouseMarker.style.top = '0'; - mouseMarker.style.left = '0'; - mouseMarker.style.zIndex = '100000'; - mouseMarker.style.content = ' '; - mouseMarker.style.pointerEvents = 'none'; - mouseMarker.style.display = 'none'; - - const onMouseDown = domEvent(container, 'mousedown', true); - const onMouseUp = domEvent(container, 'mouseup', true); - const onMouseMove = domEvent(container, 'mousemove', true); - - const mouseListener = onMouseDown(e => { - mouseMarker.style.top = `${e.clientY - 10}px`; - mouseMarker.style.left = `${e.clientX - 10}px`; - mouseMarker.style.display = 'block'; - - const mouseMoveListener = onMouseMove(e => { - mouseMarker.style.top = `${e.clientY - 10}px`; - mouseMarker.style.left = `${e.clientX - 10}px`; - }); - - Event.once(onMouseUp)(() => { - mouseMarker.style.display = 'none'; - mouseMoveListener.dispose(); - }); - }); - - const keyboardMarker = append(container, $('div')); - keyboardMarker.style.position = 'absolute'; - keyboardMarker.style.backgroundColor = 'rgba(0, 0, 0 ,0.5)'; - keyboardMarker.style.width = '100%'; - keyboardMarker.style.height = '100px'; - keyboardMarker.style.bottom = '20%'; - keyboardMarker.style.left = '0'; - keyboardMarker.style.zIndex = '100000'; - keyboardMarker.style.pointerEvents = 'none'; - keyboardMarker.style.color = 'white'; - keyboardMarker.style.lineHeight = '100px'; - keyboardMarker.style.textAlign = 'center'; - keyboardMarker.style.fontSize = '56px'; - keyboardMarker.style.display = 'none'; - - const onKeyDown = domEvent(container, 'keydown', true); - let keyboardTimeout: IDisposable = Disposable.None; - - const keyboardListener = onKeyDown(e => { - keyboardTimeout.dispose(); - - const event = new StandardKeyboardEvent(e); - const keybinding = this.keybindingService.resolveKeyboardEvent(event); - const label = keybinding.getLabel(); - - if (!event.ctrlKey && !event.altKey && !event.metaKey && !event.shiftKey && this.keybindingService.mightProducePrintableCharacter(event) && label) { - keyboardMarker.textContent += ' ' + label; - } else { - keyboardMarker.textContent = label; - } - - keyboardMarker.style.display = 'block'; - - const promise = timeout(800); - keyboardTimeout = toDisposable(() => promise.cancel()); - - promise.then(() => { - keyboardMarker.textContent = ''; - keyboardMarker.style.display = 'none'; - }); - }); - - ToggleScreencastModeAction.disposable = toDisposable(() => { - mouseListener.dispose(); - keyboardListener.dispose(); - mouseMarker.remove(); - keyboardMarker.remove(); - }); - } -} diff --git a/src/vs/workbench/electron-browser/actions/helpActions.ts b/src/vs/workbench/electron-browser/actions/helpActions.ts index 79e2ba298..3c5d242f9 100644 --- a/src/vs/workbench/electron-browser/actions/helpActions.ts +++ b/src/vs/workbench/electron-browser/actions/helpActions.ts @@ -7,6 +7,7 @@ import { Action } from 'vs/base/common/actions'; import * as nls from 'vs/nls'; import product from 'vs/platform/product/node/product'; import { isMacintosh, isLinux, language } from 'vs/base/common/platform'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; export class KeybindingsReferenceAction extends Action { @@ -91,11 +92,34 @@ export class OpenTipsAndTricksUrlAction extends Action { run(): Promise { window.open(OpenTipsAndTricksUrlAction.URL); - return Promise.resolve(); } } +export class OpenNewsletterSignupUrlAction extends Action { + + static readonly ID = 'workbench.action.openNewsletterSignupUrl'; + static readonly LABEL = nls.localize('newsletterSignup', "Signup for the VS Code Newsletter"); + private telemetryService: ITelemetryService; + private static readonly URL = product.newsletterSignupUrl; + static readonly AVAILABLE = !!OpenNewsletterSignupUrlAction.URL; + + constructor( + id: string, + label: string, + @ITelemetryService telemetryService: ITelemetryService + ) { + super(id, label); + this.telemetryService = telemetryService; + } + + async run(): Promise { + const info = await this.telemetryService.getTelemetryInfo(); + + window.open(`${OpenNewsletterSignupUrlAction.URL}?machineId=${encodeURIComponent(info.machineId)}`); + } +} + export class OpenTwitterUrlAction extends Action { static readonly ID = 'workbench.action.openTwitterUrl'; diff --git a/src/vs/workbench/electron-browser/actions/media/actions.css b/src/vs/workbench/electron-browser/actions/media/actions.css deleted file mode 100644 index b8a660c32..000000000 --- a/src/vs/workbench/electron-browser/actions/media/actions.css +++ /dev/null @@ -1,13 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -.vs .action-remove-from-recently-opened { - background: url("remove.svg") center center no-repeat; -} - -.vs-dark .action-remove-from-recently-opened, -.hc-black .action-remove-from-recently-opened { - background: url("remove-dark.svg") center center no-repeat; -} \ No newline at end of file diff --git a/src/vs/workbench/electron-browser/actions/media/remove-dark.svg b/src/vs/workbench/electron-browser/actions/media/remove-dark.svg deleted file mode 100644 index 751e89b3b..000000000 --- a/src/vs/workbench/electron-browser/actions/media/remove-dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/electron-browser/actions/media/remove.svg b/src/vs/workbench/electron-browser/actions/media/remove.svg deleted file mode 100644 index fde34404d..000000000 --- a/src/vs/workbench/electron-browser/actions/media/remove.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/electron-browser/actions/windowActions.ts b/src/vs/workbench/electron-browser/actions/windowActions.ts index 223fda7d7..7bb652eb2 100644 --- a/src/vs/workbench/electron-browser/actions/windowActions.ts +++ b/src/vs/workbench/electron-browser/actions/windowActions.ts @@ -3,29 +3,22 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import 'vs/css!./media/actions'; - import { URI } from 'vs/base/common/uri'; import { Action } from 'vs/base/common/actions'; -import { IWindowService, IWindowsService, IURIToOpen } from 'vs/platform/windows/common/windows'; +import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows'; import * as nls from 'vs/nls'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { isMacintosh } from 'vs/base/common/platform'; import * as browser from 'vs/base/browser/browser'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { webFrame } from 'electron'; import { FileKind } from 'vs/platform/files/common/files'; -import { ILabelService } from 'vs/platform/label/common/label'; import { IModelService } from 'vs/editor/common/services/modelService'; import { IModeService } from 'vs/editor/common/services/modeService'; -import { IQuickInputService, IQuickInputButton, IQuickPickSeparator, IKeyMods } from 'vs/platform/quickinput/common/quickInput'; +import { IQuickInputService, IQuickInputButton } from 'vs/platform/quickinput/common/quickInput'; import { getIconClasses } from 'vs/editor/common/services/getIconClasses'; import product from 'vs/platform/product/node/product'; import { ICommandHandler } from 'vs/platform/commands/common/commands'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IRecentFolder, IRecentFile, IRecentWorkspace, IRecent, isRecentFolder, isRecentWorkspace } from 'vs/platform/history/common/history'; -import { splitName } from 'vs/base/common/labels'; export class CloseCurrentWindowAction extends Action { @@ -61,20 +54,6 @@ export class NewWindowAction extends Action { } } -export class ToggleFullScreenAction extends Action { - - static readonly ID = 'workbench.action.toggleFullScreen'; - static LABEL = nls.localize('toggleFullScreen', "Toggle Full Screen"); - - constructor(id: string, label: string, @IWindowService private readonly windowService: IWindowService) { - super(id, label); - } - - run(): Promise { - return this.windowService.toggleFullScreen(); - } -} - export abstract class BaseZoomAction extends Action { private static readonly SETTING_KEY = 'window.zoomLevel'; @@ -86,7 +65,7 @@ export abstract class BaseZoomAction extends Action { super(id, label); } - protected setConfiguredZoomLevel(level: number): void { + protected async setConfiguredZoomLevel(level: number): Promise { level = Math.round(level); // when reaching smallest zoom, prevent fractional zoom levels const applyZoom = () => { @@ -98,7 +77,9 @@ export abstract class BaseZoomAction extends Action { browser.setZoomLevel(webFrame.getZoomLevel(), /*isTrusted*/false); }; - this.configurationService.updateValue(BaseZoomAction.SETTING_KEY, level).then(() => applyZoom()); + await this.configurationService.updateValue(BaseZoomAction.SETTING_KEY, level); + + applyZoom(); } } @@ -162,24 +143,6 @@ export class ZoomResetAction extends BaseZoomAction { } } -export class ReloadWindowAction extends Action { - - static readonly ID = 'workbench.action.reloadWindow'; - static LABEL = nls.localize('reloadWindow', "Reload Window"); - - constructor( - id: string, - label: string, - @IWindowService private readonly windowService: IWindowService - ) { - super(id, label); - } - - run(): Promise { - return this.windowService.reloadWindow().then(() => true); - } -} - export class ReloadWindowWithExtensionsDisabledAction extends Action { static readonly ID = 'workbench.action.reloadWindowWithExtensionsDisabled'; @@ -193,8 +156,10 @@ export class ReloadWindowWithExtensionsDisabledAction extends Action { super(id, label); } - run(): Promise { - return this.windowService.reloadWindow({ _: [], 'disable-extensions': true }).then(() => true); + async run(): Promise { + await this.windowService.reloadWindow({ _: [], 'disable-extensions': true }); + + return true; } } @@ -221,41 +186,38 @@ export abstract class BaseSwitchWindow extends Action { protected abstract isQuickNavigate(): boolean; - run(): Promise { + async run(): Promise { const currentWindowId = this.windowService.windowId; - return this.windowsService.getWindows().then(windows => { - const placeHolder = nls.localize('switchWindowPlaceHolder', "Select a window to switch to"); - const picks = windows.map(win => { - const resource = win.filename ? URI.file(win.filename) : win.folderUri ? win.folderUri : win.workspace ? win.workspace.configPath : undefined; - const fileKind = win.filename ? FileKind.FILE : win.workspace ? FileKind.ROOT_FOLDER : win.folderUri ? FileKind.FOLDER : FileKind.FILE; - return { - payload: win.id, - label: win.title, - iconClasses: getIconClasses(this.modelService, this.modeService, resource, fileKind), - description: (currentWindowId === win.id) ? nls.localize('current', "Current Window") : undefined, - buttons: (!this.isQuickNavigate() && currentWindowId !== win.id) ? [this.closeWindowAction] : undefined - }; - }); - - const autoFocusIndex = (picks.indexOf(picks.filter(pick => pick.payload === currentWindowId)[0]) + 1) % picks.length; - - return this.quickInputService.pick(picks, { - contextKey: 'inWindowsPicker', - activeItem: picks[autoFocusIndex], - placeHolder, - quickNavigate: this.isQuickNavigate() ? { keybindings: this.keybindingService.lookupKeybindings(this.id) } : undefined, - onDidTriggerItemButton: context => { - this.windowsService.closeWindow(context.item.payload).then(() => { - context.removeItem(); - }); - } - }); - }).then(pick => { - if (pick) { - this.windowsService.focusWindow(pick.payload); + const windows = await this.windowsService.getWindows(); + const placeHolder = nls.localize('switchWindowPlaceHolder', "Select a window to switch to"); + const picks = windows.map(win => { + const resource = win.filename ? URI.file(win.filename) : win.folderUri ? win.folderUri : win.workspace ? win.workspace.configPath : undefined; + const fileKind = win.filename ? FileKind.FILE : win.workspace ? FileKind.ROOT_FOLDER : win.folderUri ? FileKind.FOLDER : FileKind.FILE; + return { + payload: win.id, + label: win.title, + iconClasses: getIconClasses(this.modelService, this.modeService, resource, fileKind), + description: (currentWindowId === win.id) ? nls.localize('current', "Current Window") : undefined, + buttons: (!this.isQuickNavigate() && currentWindowId !== win.id) ? [this.closeWindowAction] : undefined + }; + }); + const autoFocusIndex = (picks.indexOf(picks.filter(pick => pick.payload === currentWindowId)[0]) + 1) % picks.length; + + const pick = await this.quickInputService.pick(picks, { + contextKey: 'inWindowsPicker', + activeItem: picks[autoFocusIndex], + placeHolder, + quickNavigate: this.isQuickNavigate() ? { keybindings: this.keybindingService.lookupKeybindings(this.id) } : undefined, + onDidTriggerItemButton: async context => { + await this.windowsService.closeWindow(context.item.payload); + context.removeItem(); } }); + + if (pick) { + this.windowsService.focusWindow(pick.payload); + } } } @@ -305,149 +267,6 @@ export class QuickSwitchWindow extends BaseSwitchWindow { } } -export const inRecentFilesPickerContextKey = 'inRecentFilesPicker'; - -export abstract class BaseOpenRecentAction extends Action { - - private removeFromRecentlyOpened: IQuickInputButton = { - iconClass: 'action-remove-from-recently-opened', - tooltip: nls.localize('remove', "Remove from Recently Opened") - }; - - constructor( - id: string, - label: string, - private windowService: IWindowService, - private windowsService: IWindowsService, - private quickInputService: IQuickInputService, - private contextService: IWorkspaceContextService, - private labelService: ILabelService, - private keybindingService: IKeybindingService, - private modelService: IModelService, - private modeService: IModeService, - ) { - super(id, label); - } - - protected abstract isQuickNavigate(): boolean; - - run(): Promise { - return this.windowService.getRecentlyOpened() - .then(({ workspaces, files }) => this.openRecent(workspaces, files)); - } - - private openRecent(recentWorkspaces: Array, recentFiles: IRecentFile[]): void { - - const toPick = (recent: IRecent, labelService: ILabelService, buttons: IQuickInputButton[] | undefined) => { - let uriToOpen: IURIToOpen | undefined; - let iconClasses: string[]; - let fullLabel: string | undefined; - let resource: URI | undefined; - if (isRecentFolder(recent)) { - resource = recent.folderUri; - iconClasses = getIconClasses(this.modelService, this.modeService, resource, FileKind.FOLDER); - uriToOpen = { folderUri: resource }; - fullLabel = recent.label || labelService.getWorkspaceLabel(resource, { verbose: true }); - } else if (isRecentWorkspace(recent)) { - resource = recent.workspace.configPath; - iconClasses = getIconClasses(this.modelService, this.modeService, resource, FileKind.ROOT_FOLDER); - uriToOpen = { workspaceUri: resource }; - fullLabel = recent.label || labelService.getWorkspaceLabel(recent.workspace, { verbose: true }); - } else { - resource = recent.fileUri; - iconClasses = getIconClasses(this.modelService, this.modeService, resource, FileKind.FILE); - uriToOpen = { fileUri: resource }; - fullLabel = recent.label || labelService.getUriLabel(resource); - } - const { name, parentPath } = splitName(fullLabel); - return { - iconClasses, - label: name, - description: parentPath, - buttons, - uriToOpen, - resource - }; - }; - const workspacePicks = recentWorkspaces.map(workspace => toPick(workspace, this.labelService, !this.isQuickNavigate() ? [this.removeFromRecentlyOpened] : undefined)); - const filePicks = recentFiles.map(p => toPick(p, this.labelService, !this.isQuickNavigate() ? [this.removeFromRecentlyOpened] : undefined)); - - // focus second entry if the first recent workspace is the current workspace - const firstEntry = recentWorkspaces[0]; - let autoFocusSecondEntry: boolean = firstEntry && this.contextService.isCurrentWorkspace(isRecentWorkspace(firstEntry) ? firstEntry.workspace : firstEntry.folderUri); - - let keyMods: IKeyMods; - const workspaceSeparator: IQuickPickSeparator = { type: 'separator', label: nls.localize('workspaces', "workspaces") }; - const fileSeparator: IQuickPickSeparator = { type: 'separator', label: nls.localize('files', "files") }; - const picks = [workspaceSeparator, ...workspacePicks, fileSeparator, ...filePicks]; - this.quickInputService.pick(picks, { - contextKey: inRecentFilesPickerContextKey, - activeItem: [...workspacePicks, ...filePicks][autoFocusSecondEntry ? 1 : 0], - 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, - onKeyMods: mods => keyMods = mods, - quickNavigate: this.isQuickNavigate() ? { keybindings: this.keybindingService.lookupKeybindings(this.id) } : undefined, - onDidTriggerItemButton: context => { - this.windowsService.removeFromRecentlyOpened([context.item.resource]).then(() => context.removeItem()); - } - }).then((pick): Promise | void => { - if (pick) { - const forceNewWindow = keyMods.ctrlCmd; - return this.windowService.openWindow([pick.uriToOpen], { forceNewWindow }); - } - }); - } -} - -export class OpenRecentAction extends BaseOpenRecentAction { - - static readonly ID = 'workbench.action.openRecent'; - static readonly LABEL = nls.localize('openRecent', "Open Recent..."); - - constructor( - id: string, - label: string, - @IWindowService windowService: IWindowService, - @IWindowsService windowsService: IWindowsService, - @IQuickInputService quickInputService: IQuickInputService, - @IWorkspaceContextService contextService: IWorkspaceContextService, - @IKeybindingService keybindingService: IKeybindingService, - @IModelService modelService: IModelService, - @IModeService modeService: IModeService, - @ILabelService labelService: ILabelService - ) { - super(id, label, windowService, windowsService, quickInputService, contextService, labelService, keybindingService, modelService, modeService); - } - - protected isQuickNavigate(): boolean { - return false; - } -} - -export class QuickOpenRecentAction extends BaseOpenRecentAction { - - static readonly ID = 'workbench.action.quickOpenRecent'; - static readonly LABEL = nls.localize('quickOpenRecent', "Quick Open Recent..."); - - constructor( - id: string, - label: string, - @IWindowService windowService: IWindowService, - @IWindowsService windowsService: IWindowsService, - @IQuickInputService quickInputService: IQuickInputService, - @IWorkspaceContextService contextService: IWorkspaceContextService, - @IKeybindingService keybindingService: IKeybindingService, - @IModelService modelService: IModelService, - @IModeService modeService: IModeService, - @ILabelService labelService: ILabelService - ) { - super(id, label, windowService, windowsService, quickInputService, contextService, labelService, keybindingService, modelService, modeService); - } - - protected isQuickNavigate(): boolean { - return true; - } -} export class ShowAboutDialogAction extends Action { diff --git a/src/vs/workbench/electron-browser/main.contribution.ts b/src/vs/workbench/electron-browser/main.contribution.ts index de7017c8e..10557fcca 100644 --- a/src/vs/workbench/electron-browser/main.contribution.ts +++ b/src/vs/workbench/electron-browser/main.contribution.ts @@ -11,20 +11,19 @@ import { IConfigurationRegistry, Extensions as ConfigurationExtensions, Configur 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 { KeybindingsReferenceAction, OpenDocumentationUrlAction, OpenIntroductoryVideosUrlAction, OpenTipsAndTricksUrlAction, OpenTwitterUrlAction, OpenRequestFeatureUrlAction, OpenPrivacyStatementUrlAction, OpenLicenseUrlAction } from 'vs/workbench/electron-browser/actions/helpActions'; -import { ToggleSharedProcessAction, InspectContextKeysAction, ToggleScreencastModeAction, ToggleDevToolsAction } from 'vs/workbench/electron-browser/actions/developerActions'; -import { ShowAboutDialogAction, ZoomResetAction, ZoomOutAction, ZoomInAction, ToggleFullScreenAction, CloseCurrentWindowAction, SwitchWindow, NewWindowAction, QuickSwitchWindow, QuickOpenRecentAction, inRecentFilesPickerContextKey, OpenRecentAction, ReloadWindowWithExtensionsDisabledAction, NewWindowTabHandler, ReloadWindowAction, ShowPreviousWindowTabHandler, ShowNextWindowTabHandler, MoveWindowTabToNewWindowHandler, MergeWindowTabsHandlerHandler, ToggleWindowTabsBarHandler } from 'vs/workbench/electron-browser/actions/windowActions'; -import { AddRootFolderAction, GlobalRemoveRootFolderAction, OpenWorkspaceAction, SaveWorkspaceAsAction, OpenWorkspaceConfigFileAction, DuplicateWorkspaceInNewWindowAction, OpenFileFolderAction, OpenFileAction, OpenFolderAction, CloseWorkspaceAction, OpenLocalFileAction, OpenLocalFolderAction, OpenLocalFileFolderAction } from 'vs/workbench/browser/actions/workspaceActions'; +import { KeybindingsReferenceAction, OpenDocumentationUrlAction, OpenIntroductoryVideosUrlAction, OpenTipsAndTricksUrlAction, OpenTwitterUrlAction, OpenRequestFeatureUrlAction, OpenPrivacyStatementUrlAction, OpenLicenseUrlAction, OpenNewsletterSignupUrlAction } from 'vs/workbench/electron-browser/actions/helpActions'; +import { ToggleSharedProcessAction, ToggleDevToolsAction } from 'vs/workbench/electron-browser/actions/developerActions'; +import { ShowAboutDialogAction, ZoomResetAction, ZoomOutAction, ZoomInAction, CloseCurrentWindowAction, SwitchWindow, NewWindowAction, QuickSwitchWindow, ReloadWindowWithExtensionsDisabledAction, NewWindowTabHandler, ShowPreviousWindowTabHandler, ShowNextWindowTabHandler, MoveWindowTabToNewWindowHandler, MergeWindowTabsHandlerHandler, ToggleWindowTabsBarHandler } from 'vs/workbench/electron-browser/actions/windowActions'; +import { AddRootFolderAction, GlobalRemoveRootFolderAction, SaveWorkspaceAsAction, OpenWorkspaceConfigFileAction, DuplicateWorkspaceInNewWindowAction, CloseWorkspaceAction } 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, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ADD_ROOT_FOLDER_COMMAND_ID } from 'vs/workbench/browser/actions/workspaceCommands'; -import { SupportsWorkspacesContext, IsMacContext, HasMacNativeTabsContext, IsDevelopmentContext, WorkbenchStateContext, WorkspaceFolderCountContext, RemoteFileDialogContext } from 'vs/workbench/common/contextkeys'; +import { SupportsWorkspacesContext, IsMacContext, HasMacNativeTabsContext, IsDevelopmentContext, WorkbenchStateContext, WorkspaceFolderCountContext } from 'vs/workbench/browser/contextkeys'; import { NoEditorsVisibleContext, SingleEditorGroupsContext } from 'vs/workbench/common/editor'; import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows'; -import { LogStorageAction } from 'vs/platform/storage/node/storageService'; +import product from 'vs/platform/product/node/product'; // Actions (function registerActions(): void { @@ -34,41 +33,7 @@ import { LogStorageAction } from 'vs/platform/storage/node/storageService'; (function registerFileActions(): void { const fileCategory = nls.localize('file', "File"); - if (isMacintosh) { - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileFolderAction, OpenFileFolderAction.ID, OpenFileFolderAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'File: Open...', fileCategory); - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenLocalFileFolderAction, OpenLocalFileFolderAction.ID, OpenLocalFileFolderAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }, RemoteFileDialogContext), 'File: Open Local...', fileCategory, RemoteFileDialogContext); - } else { - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFileAction, OpenFileAction.ID, OpenFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }), 'File: Open File...', fileCategory); - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenFolderAction, OpenFolderAction.ID, OpenFolderAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_O) }), 'File: Open Folder...', fileCategory); - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenLocalFileAction, OpenLocalFileAction.ID, OpenLocalFileAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_O }, RemoteFileDialogContext), 'File: Open Local File...', fileCategory, RemoteFileDialogContext); - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenLocalFolderAction, OpenLocalFolderAction.ID, OpenLocalFolderAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.KEY_O) }, RemoteFileDialogContext), 'File: Open Local Folder...', fileCategory, RemoteFileDialogContext); - } - - registry.registerWorkbenchAction(new SyncActionDescriptor(QuickOpenRecentAction, QuickOpenRecentAction.ID, QuickOpenRecentAction.LABEL), 'File: Quick Open Recent...', fileCategory); - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenRecentAction, OpenRecentAction.ID, OpenRecentAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_R, mac: { primary: KeyMod.WinCtrl | KeyCode.KEY_R } }), 'File: Open Recent...', fileCategory); registry.registerWorkbenchAction(new SyncActionDescriptor(CloseWorkspaceAction, CloseWorkspaceAction.ID, CloseWorkspaceAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_F) }), 'File: Close Workspace', fileCategory); - - const recentFilesPickerContext = ContextKeyExpr.and(inQuickOpenContext, ContextKeyExpr.has(inRecentFilesPickerContextKey)); - - const quickOpenNavigateNextInRecentFilesPickerId = 'workbench.action.quickOpenNavigateNextInRecentFilesPicker'; - KeybindingsRegistry.registerCommandAndKeybindingRule({ - id: quickOpenNavigateNextInRecentFilesPickerId, - weight: KeybindingWeight.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: KeybindingWeight.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: View @@ -78,7 +43,6 @@ import { LogStorageAction } from 'vs/platform/storage/node/storageService'; registry.registerWorkbenchAction(new SyncActionDescriptor(ZoomInAction, ZoomInAction.ID, ZoomInAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.US_EQUAL, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_EQUAL, KeyMod.CtrlCmd | KeyCode.NUMPAD_ADD] }), 'View: Zoom In', viewCategory); registry.registerWorkbenchAction(new SyncActionDescriptor(ZoomOutAction, ZoomOutAction.ID, ZoomOutAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.US_MINUS, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.US_MINUS, KeyMod.CtrlCmd | KeyCode.NUMPAD_SUBTRACT], linux: { primary: KeyMod.CtrlCmd | KeyCode.US_MINUS, secondary: [KeyMod.CtrlCmd | KeyCode.NUMPAD_SUBTRACT] } }), 'View: Zoom Out', viewCategory); registry.registerWorkbenchAction(new SyncActionDescriptor(ZoomResetAction, ZoomResetAction.ID, ZoomResetAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.NUMPAD_0 }), 'View: Reset Zoom', viewCategory); - registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleFullScreenAction, ToggleFullScreenAction.ID, ToggleFullScreenAction.LABEL, { primary: KeyCode.F11, mac: { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.KEY_F } }), 'View: Toggle Full Screen', viewCategory); })(); // Actions: Window @@ -118,7 +82,6 @@ import { LogStorageAction } from 'vs/platform/storage/node/storageService'; registry.registerWorkbenchAction(new SyncActionDescriptor(AddRootFolderAction, AddRootFolderAction.ID, AddRootFolderAction.LABEL), 'Workspaces: Add Folder to Workspace...', workspacesCategory, SupportsWorkspacesContext); registry.registerWorkbenchAction(new SyncActionDescriptor(GlobalRemoveRootFolderAction, GlobalRemoveRootFolderAction.ID, GlobalRemoveRootFolderAction.LABEL), 'Workspaces: Remove Folder from Workspace...', workspacesCategory); - registry.registerWorkbenchAction(new SyncActionDescriptor(OpenWorkspaceAction, OpenWorkspaceAction.ID, OpenWorkspaceAction.LABEL), 'Workspaces: Open Workspace...', workspacesCategory, SupportsWorkspacesContext); registry.registerWorkbenchAction(new SyncActionDescriptor(SaveWorkspaceAsAction, SaveWorkspaceAsAction.ID, SaveWorkspaceAsAction.LABEL), 'Workspaces: Save Workspace As...', workspacesCategory, SupportsWorkspacesContext); registry.registerWorkbenchAction(new SyncActionDescriptor(DuplicateWorkspaceInNewWindowAction, DuplicateWorkspaceInNewWindowAction.ID, DuplicateWorkspaceInNewWindowAction.LABEL), 'Workspaces: Duplicate Workspace in New Window', workspacesCategory); @@ -160,20 +123,9 @@ import { LogStorageAction } from 'vs/platform/storage/node/storageService'; (function registerDeveloperActions(): void { const developerCategory = nls.localize('developer', "Developer"); registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleSharedProcessAction, ToggleSharedProcessAction.ID, ToggleSharedProcessAction.LABEL), 'Developer: Toggle Shared Process', developerCategory); - registry.registerWorkbenchAction(new SyncActionDescriptor(InspectContextKeysAction, InspectContextKeysAction.ID, InspectContextKeysAction.LABEL), 'Developer: Inspect Context Keys', developerCategory); - registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleScreencastModeAction, ToggleScreencastModeAction.ID, ToggleScreencastModeAction.LABEL), 'Developer: Toggle Screencast Mode', developerCategory); - registry.registerWorkbenchAction(new SyncActionDescriptor(ReloadWindowWithExtensionsDisabledAction, ReloadWindowWithExtensionsDisabledAction.ID, ReloadWindowWithExtensionsDisabledAction.LABEL), 'Developer: Reload Window Without Extensions', developerCategory); - registry.registerWorkbenchAction(new SyncActionDescriptor(LogStorageAction, LogStorageAction.ID, LogStorageAction.LABEL), 'Developer: Log Storage', developerCategory); - registry.registerWorkbenchAction(new SyncActionDescriptor(ReloadWindowAction, ReloadWindowAction.ID, ReloadWindowAction.LABEL), 'Developer: Reload Window', developerCategory); + registry.registerWorkbenchAction(new SyncActionDescriptor(ReloadWindowWithExtensionsDisabledAction, ReloadWindowWithExtensionsDisabledAction.ID, ReloadWindowWithExtensionsDisabledAction.LABEL), 'Developer: Reload Window With Extensions Disabled', developerCategory); registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleDevToolsAction, ToggleDevToolsAction.ID, ToggleDevToolsAction.LABEL), 'Developer: Toggle Developer Tools', developerCategory); - KeybindingsRegistry.registerKeybindingRule({ - id: ReloadWindowAction.ID, - weight: KeybindingWeight.WorkbenchContrib + 50, - when: IsDevelopmentContext, - primary: KeyMod.CtrlCmd | KeyCode.KEY_R - }); - KeybindingsRegistry.registerKeybindingRule({ id: ToggleDevToolsAction.ID, weight: KeybindingWeight.WorkbenchContrib + 50, @@ -203,11 +155,15 @@ import { LogStorageAction } from 'vs/platform/storage/node/storageService'; registry.registerWorkbenchAction(new SyncActionDescriptor(OpenTipsAndTricksUrlAction, OpenTipsAndTricksUrlAction.ID, OpenTipsAndTricksUrlAction.LABEL), 'Help: Tips and Tricks', helpCategory); } + if (OpenNewsletterSignupUrlAction.AVAILABLE) { + registry.registerWorkbenchAction(new SyncActionDescriptor(OpenNewsletterSignupUrlAction, OpenNewsletterSignupUrlAction.ID, OpenNewsletterSignupUrlAction.LABEL), 'Help: Tips and Tricks', helpCategory); + } + registry.registerWorkbenchAction(new SyncActionDescriptor(OpenTwitterUrlAction, OpenTwitterUrlAction.ID, OpenTwitterUrlAction.LABEL), 'Help: Join Us on Twitter', helpCategory); registry.registerWorkbenchAction(new SyncActionDescriptor(OpenRequestFeatureUrlAction, OpenRequestFeatureUrlAction.ID, OpenRequestFeatureUrlAction.LABEL), 'Help: Search Feature Requests', helpCategory); registry.registerWorkbenchAction(new SyncActionDescriptor(OpenLicenseUrlAction, OpenLicenseUrlAction.ID, OpenLicenseUrlAction.LABEL), 'Help: View License', helpCategory); registry.registerWorkbenchAction(new SyncActionDescriptor(OpenPrivacyStatementUrlAction, OpenPrivacyStatementUrlAction.ID, OpenPrivacyStatementUrlAction.LABEL), 'Help: Privacy Statement', helpCategory); - registry.registerWorkbenchAction(new SyncActionDescriptor(ShowAboutDialogAction, ShowAboutDialogAction.ID, ShowAboutDialogAction.LABEL), 'Help: About', helpCategory); + registry.registerWorkbenchAction(new SyncActionDescriptor(ShowAboutDialogAction, ShowAboutDialogAction.ID, ShowAboutDialogAction.LABEL), `Help: About ${product.applicationName}`, helpCategory); })(); })(); @@ -222,62 +178,6 @@ import { LogStorageAction } from 'vs/platform/storage/node/storageService'; order: 2 }); - if (isMacintosh) { - MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { - group: '2_open', - command: { - id: OpenFileFolderAction.ID, - title: nls.localize({ key: 'miOpen', comment: ['&& denotes a mnemonic'] }, "&&Open...") - }, - order: 1 - }); - } else { - MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { - group: '2_open', - command: { - id: OpenFileAction.ID, - title: nls.localize({ key: 'miOpenFile', comment: ['&& denotes a mnemonic'] }, "&&Open File...") - }, - order: 1 - }); - - MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { - group: '2_open', - command: { - id: OpenFolderAction.ID, - title: nls.localize({ key: 'miOpenFolder', comment: ['&& denotes a mnemonic'] }, "Open &&Folder...") - }, - order: 2 - }); - } - - MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { - group: '2_open', - command: { - id: OpenWorkspaceAction.ID, - title: nls.localize({ key: 'miOpenWorkspace', comment: ['&& denotes a mnemonic'] }, "Open Wor&&kspace...") - }, - order: 3, - when: SupportsWorkspacesContext - }); - - MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { - title: nls.localize({ key: 'miOpenRecent', comment: ['&& denotes a mnemonic'] }, "Open &&Recent"), - submenu: MenuId.MenubarRecentMenu, - group: '2_open', - order: 4 - }); - - // More - MenuRegistry.appendMenuItem(MenuId.MenubarRecentMenu, { - group: 'y_more', - command: { - id: OpenRecentAction.ID, - title: nls.localize({ key: 'miMore', comment: ['&& denotes a mnemonic'] }, "&&More...") - }, - order: 1 - }); - MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { group: '3_workspace', command: { @@ -298,14 +198,6 @@ import { LogStorageAction } from 'vs/platform/storage/node/storageService'; when: SupportsWorkspacesContext }); - MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { - title: nls.localize({ key: 'miPreferences', comment: ['&& denotes a mnemonic'] }, "&&Preferences"), - submenu: MenuId.MenubarPreferencesMenu, - group: '5_autosave', - order: 2, - when: IsMacContext.toNegated() - }); - MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { group: '6_close', command: { @@ -346,23 +238,6 @@ import { LogStorageAction } from 'vs/platform/storage/node/storageService'; when: IsMacContext.toNegated() }); - // Appereance menu - MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { - group: '2_appearance', - title: nls.localize({ key: 'miAppearance', comment: ['&& denotes a mnemonic'] }, "&&Appearance"), - submenu: MenuId.MenubarAppearanceMenu, - order: 1 - }); - - MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { - group: '1_toggle_view', - command: { - id: ToggleFullScreenAction.ID, - title: nls.localize({ key: 'miToggleFullScreen', comment: ['&& denotes a mnemonic'] }, "Toggle &&Full Screen") - }, - order: 1 - }); - // Zoom MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { @@ -546,18 +421,6 @@ import { LogStorageAction } from 'vs/platform/storage/node/storageService'; nls.localize('openFilesInNewWindowMac', "Controls whether files should open in a new window. \nNote that there can still be cases where this setting is ignored (e.g. when using the `--new-window` or `--reuse-window` command line option).") : nls.localize('openFilesInNewWindow', "Controls whether files should open in a new window.\nNote 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', - 'enum': ['on', 'off', 'default'], - 'enumDescriptions': [ - nls.localize('window.openFoldersInNewWindow.on', "Folders will open in a new window."), - nls.localize('window.openFoldersInNewWindow.off', "Folders will replace the last active window."), - nls.localize('window.openFoldersInNewWindow.default', "Folders will open in a new window unless a folder is picked from within the application (e.g. via the File menu).") - ], - 'default': 'default', - 'scope': ConfigurationScope.APPLICATION, - 'markdownDescription': nls.localize('openFoldersInNewWindow', "Controls whether folders should open in a new window or replace the last active window.\nNote 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.openWithoutArgumentsInNewWindow': { 'type': 'string', 'enum': ['on', 'off'], @@ -611,27 +474,6 @@ import { LogStorageAction } from 'vs/platform/storage/node/storageService'; 'default': false, 'description': nls.localize('closeWhenEmpty', "Controls whether closing the last editor should also close the window. This setting only applies for windows that do not show folders.") }, - 'window.menuBarVisibility': { - 'type': 'string', - 'enum': ['default', 'visible', 'toggle', 'hidden'], - 'enumDescriptions': [ - nls.localize('window.menuBarVisibility.default', "Menu is only hidden in full screen mode."), - nls.localize('window.menuBarVisibility.visible', "Menu is always visible even in full screen mode."), - nls.localize('window.menuBarVisibility.toggle', "Menu is hidden but can be displayed via Alt key."), - nls.localize('window.menuBarVisibility.hidden', "Menu is always hidden.") - ], - 'default': 'default', - 'scope': ConfigurationScope.APPLICATION, - 'description': nls.localize('menuBarVisibility', "Control the visibility of the menu bar. A setting of 'toggle' means that the menu bar is hidden and a single press of the Alt key will show it. By default, the menu bar will be visible, unless the window is full screen."), - 'included': isWindows || isLinux - }, - 'window.enableMenuBarMnemonics': { - 'type': 'boolean', - 'default': true, - 'scope': ConfigurationScope.APPLICATION, - 'description': nls.localize('enableMenuBarMnemonics', "If enabled, the main menus can be opened via Alt-key shortcuts. Disabling mnemonics allows to bind these Alt-key shortcuts to editor commands instead."), - 'included': isWindows || isLinux - }, 'window.autoDetectHighContrast': { 'type': 'boolean', 'default': true, @@ -664,7 +506,7 @@ import { LogStorageAction } from 'vs/platform/storage/node/storageService'; 'default': true, 'description': nls.localize('window.nativeFullScreen', "Controls if native full-screen should be used on macOS. Disable this option to prevent macOS from creating a new space when going full-screen."), 'scope': ConfigurationScope.APPLICATION, - 'included': isMacintosh + 'included': false /* isMacintosh */ }, 'window.clickThroughInactive': { 'type': 'boolean', diff --git a/src/vs/workbench/electron-browser/main.ts b/src/vs/workbench/electron-browser/main.ts index 1d13aba37..61c920df2 100644 --- a/src/vs/workbench/electron-browser/main.ts +++ b/src/vs/workbench/electron-browser/main.ts @@ -19,17 +19,15 @@ import { WorkbenchEnvironmentService } from 'vs/workbench/services/environment/n import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { stat } from 'vs/base/node/pfs'; -import { KeyboardMapperFactory } from 'vs/workbench/services/keybinding/electron-browser/keybindingService'; +import { KeyboardMapperFactory } from 'vs/workbench/services/keybinding/electron-browser/nativeKeymapService'; import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; import { webFrame } from 'electron'; import { ISingleFolderWorkspaceIdentifier, IWorkspaceInitializationPayload, ISingleFolderWorkspaceInitializationPayload, reviveWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; -import { createSpdLogService } from 'vs/platform/log/node/spdlogService'; import { ConsoleLogService, MultiplexLogService, ILogService } from 'vs/platform/log/common/log'; import { StorageService } from 'vs/platform/storage/node/storageService'; -import { LogLevelSetterChannelClient, FollowerLogService } from 'vs/platform/log/node/logIpc'; +import { LogLevelSetterChannelClient, FollowerLogService } from 'vs/platform/log/common/logIpc'; import { Schemas } from 'vs/base/common/network'; import { sanitizeFilePath } from 'vs/base/common/extpath'; -import { basename } from 'vs/base/common/path'; import { GlobalStorageDatabaseChannelClient } from 'vs/platform/storage/node/storageIpc'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -41,21 +39,27 @@ import { RemoteAuthorityResolverService } from 'vs/platform/remote/electron-brow import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; -import { FileService } from 'vs/workbench/services/files/common/fileService'; +import { FileService } from 'vs/platform/files/common/fileService'; import { IFileService } from 'vs/platform/files/common/files'; -import { DiskFileSystemProvider } from 'vs/workbench/services/files/electron-browser/diskFileSystemProvider'; +import { DiskFileSystemProvider } from 'vs/platform/files/electron-browser/diskFileSystemProvider'; import { IChannel } from 'vs/base/parts/ipc/common/ipc'; import { REMOTE_FILE_SYSTEM_CHANNEL_NAME, RemoteExtensionsFileSystemProvider } from 'vs/platform/remote/common/remoteAgentFileSystemChannel'; import { DefaultConfigurationExportHelper } from 'vs/workbench/services/configuration/node/configurationExportHelper'; import { ConfigurationCache } from 'vs/workbench/services/configuration/node/configurationCache'; -import { ConfigurationFileService } from 'vs/workbench/services/configuration/node/configurationFileService'; +import { SpdLogService } from 'vs/platform/log/node/spdlogService'; +import { SignService } from 'vs/platform/sign/node/signService'; +import { ISignService } from 'vs/platform/sign/common/sign'; +import { FileUserDataProvider } from 'vs/workbench/services/userData/common/fileUserDataProvider'; +import { basename } from 'vs/base/common/resources'; class CodeRendererMain extends Disposable { private workbench: Workbench; + private readonly environmentService: WorkbenchEnvironmentService; - constructor(private readonly configuration: IWindowConfiguration) { + constructor(configuration: IWindowConfiguration) { super(); + this.environmentService = new WorkbenchEnvironmentService(configuration, configuration.execPath); this.init(); } @@ -69,29 +73,29 @@ class CodeRendererMain extends Disposable { this.reviveUris(); // Setup perf - importEntries(this.configuration.perfEntries); + importEntries(this.environmentService.configuration.perfEntries); // Browser config setZoomFactor(webFrame.getZoomFactor()); // Ensure others can listen to zoom level changes setZoomLevel(webFrame.getZoomLevel(), true /* isTrusted */); // Can be trusted because we are not setting it ourselves (https://github.com/Microsoft/vscode/issues/26151) - setFullscreen(!!this.configuration.fullscreen); + setFullscreen(!!this.environmentService.configuration.fullscreen); // Keyboard support KeyboardMapperFactory.INSTANCE._onKeyboardLayoutChanged(); } private reviveUris() { - if (this.configuration.folderUri) { - this.configuration.folderUri = URI.revive(this.configuration.folderUri); + if (this.environmentService.configuration.folderUri) { + this.environmentService.configuration.folderUri = URI.revive(this.environmentService.configuration.folderUri); } - if (this.configuration.workspace) { - this.configuration.workspace = reviveWorkspaceIdentifier(this.configuration.workspace); + if (this.environmentService.configuration.workspace) { + this.environmentService.configuration.workspace = reviveWorkspaceIdentifier(this.environmentService.configuration.workspace); } - const filesToWait = this.configuration.filesToWait; + const filesToWait = this.environmentService.configuration.filesToWait; const filesToWaitPaths = filesToWait && filesToWait.paths; - [filesToWaitPaths, this.configuration.filesToOpenOrCreate, this.configuration.filesToDiff].forEach(paths => { + [filesToWaitPaths, this.environmentService.configuration.filesToOpenOrCreate, this.environmentService.configuration.filesToDiff].forEach(paths => { if (Array.isArray(paths)) { paths.forEach(path => { if (path.fileUri) { @@ -106,42 +110,39 @@ class CodeRendererMain extends Disposable { } } - open(): Promise { - return this.initServices().then(services => { + async open(): Promise { + const services = await this.initServices(); + await domContentLoaded(); + mark('willStartWorkbench'); - return domContentLoaded().then(() => { - mark('willStartWorkbench'); + // Create Workbench + this.workbench = new Workbench(document.body, services.serviceCollection, services.logService); - // Create Workbench - this.workbench = new Workbench(document.body, services.serviceCollection, services.logService); + // Layout + this._register(addDisposableListener(window, EventType.RESIZE, e => this.onWindowResize(e, true))); - // Layout - this._register(addDisposableListener(window, EventType.RESIZE, e => this.onWindowResize(e, true))); + // Workbench Lifecycle + this._register(this.workbench.onShutdown(() => this.dispose())); + this._register(this.workbench.onWillShutdown(event => event.join(services.storageService.close()))); - // Workbench Lifecycle - this._register(this.workbench.onShutdown(() => this.dispose())); - this._register(this.workbench.onWillShutdown(event => event.join(services.storageService.close()))); + // Startup + const instantiationService = this.workbench.startup(); - // Startup - const instantiationService = this.workbench.startup(); + // Window + this._register(instantiationService.createInstance(ElectronWindow)); - // Window - this._register(instantiationService.createInstance(ElectronWindow)); - - // Driver - if (this.configuration.driver) { - instantiationService.invokeFunction(accessor => registerWindowDriver(accessor).then(disposable => this._register(disposable))); - } + // Driver + if (this.environmentService.configuration.driver) { + instantiationService.invokeFunction(async accessor => this._register(await registerWindowDriver(accessor))); + } - // Config Exporter - if (this.configuration['export-default-configuration']) { - instantiationService.createInstance(DefaultConfigurationExportHelper); - } + // Config Exporter + if (this.environmentService.configuration['export-default-configuration']) { + instantiationService.createInstance(DefaultConfigurationExportHelper); + } - // Logging - services.logService.trace('workbench configuration', JSON.stringify(this.configuration)); - }); - }); + // Logging + services.logService.trace('workbench configuration', JSON.stringify(this.environmentService.configuration)); } private onWindowResize(e: Event, retry: boolean): void { @@ -162,7 +163,7 @@ class CodeRendererMain extends Disposable { } } - private initServices(): Promise<{ serviceCollection: ServiceCollection, logService: ILogService, storageService: StorageService }> { + private async initServices(): Promise<{ serviceCollection: ServiceCollection, logService: ILogService, storageService: StorageService }> { const serviceCollection = new ServiceCollection(); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -171,22 +172,25 @@ class CodeRendererMain extends Disposable { // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // Main Process - const mainProcessService = this._register(new MainProcessService(this.configuration.windowId)); + const mainProcessService = this._register(new MainProcessService(this.environmentService.configuration.windowId)); serviceCollection.set(IMainProcessService, mainProcessService); // Environment - const environmentService = new WorkbenchEnvironmentService(this.configuration, this.configuration.execPath); - serviceCollection.set(IWorkbenchEnvironmentService, environmentService); + serviceCollection.set(IWorkbenchEnvironmentService, this.environmentService); // Log - const logService = this._register(this.createLogService(mainProcessService, environmentService)); + const logService = this._register(this.createLogService(mainProcessService, this.environmentService)); serviceCollection.set(ILogService, logService); // Remote const remoteAuthorityResolverService = new RemoteAuthorityResolverService(); serviceCollection.set(IRemoteAuthorityResolverService, remoteAuthorityResolverService); - const remoteAgentService = this._register(new RemoteAgentService(this.configuration, environmentService, remoteAuthorityResolverService)); + // Sign + const signService = new SignService(); + serviceCollection.set(ISignService, signService); + + const remoteAgentService = this._register(new RemoteAgentService(this.environmentService.configuration, this.environmentService, remoteAuthorityResolverService, signService)); serviceCollection.set(IRemoteAgentService, remoteAgentService); // Files @@ -196,6 +200,9 @@ class CodeRendererMain extends Disposable { const diskFileSystemProvider = this._register(new DiskFileSystemProvider(logService)); fileService.registerProvider(Schemas.file, diskFileSystemProvider); + // User Data Provider + fileService.registerProvider(Schemas.userData, new FileUserDataProvider(this.environmentService.appSettingsHome, this.environmentService.backupHome, diskFileSystemProvider, this.environmentService)); + const connection = remoteAgentService.getConnection(); if (connection) { const channel = connection.getChannel(REMOTE_FILE_SYSTEM_CHANNEL_NAME); @@ -203,8 +210,10 @@ class CodeRendererMain extends Disposable { fileService.registerProvider(Schemas.vscodeRemote, remoteFileSystemProvider); } - return this.resolveWorkspaceInitializationPayload(environmentService).then(payload => Promise.all([ - this.createWorkspaceService(payload, environmentService, fileService, remoteAgentService, logService).then(service => { + const payload = await this.resolveWorkspaceInitializationPayload(); + + const services = await Promise.all([ + this.createWorkspaceService(payload, fileService, remoteAgentService, logService).then(service => { // Workspace serviceCollection.set(IWorkspaceContextService, service); @@ -215,54 +224,53 @@ class CodeRendererMain extends Disposable { return service; }), - this.createStorageService(payload, environmentService, logService, mainProcessService).then(service => { + this.createStorageService(payload, logService, mainProcessService).then(service => { // Storage serviceCollection.set(IStorageService, service); return service; }) - ]).then(services => ({ serviceCollection, logService, storageService: services[1] }))); + ]); + + return { serviceCollection, logService, storageService: services[1] }; } - private resolveWorkspaceInitializationPayload(environmentService: IWorkbenchEnvironmentService): Promise { + private async resolveWorkspaceInitializationPayload(): Promise { // Multi-root workspace - if (this.configuration.workspace) { - return Promise.resolve(this.configuration.workspace); + if (this.environmentService.configuration.workspace) { + return this.environmentService.configuration.workspace; } // Single-folder workspace - let workspaceInitializationPayload: Promise = Promise.resolve(undefined); - if (this.configuration.folderUri) { - workspaceInitializationPayload = this.resolveSingleFolderWorkspaceInitializationPayload(this.configuration.folderUri); + let workspaceInitializationPayload: IWorkspaceInitializationPayload | undefined; + if (this.environmentService.configuration.folderUri) { + workspaceInitializationPayload = await this.resolveSingleFolderWorkspaceInitializationPayload(this.environmentService.configuration.folderUri); } - return workspaceInitializationPayload.then(payload => { - - // Fallback to empty workspace if we have no payload yet. - if (!payload) { - let id: string; - if (this.configuration.backupPath) { - id = basename(this.configuration.backupPath); // we know the backupPath must be a unique path so we leverage its name as workspace ID - } else if (environmentService.isExtensionDevelopment) { - id = 'ext-dev'; // extension development window never stores backups and is a singleton - } else { - return Promise.reject(new Error('Unexpected window configuration without backupPath')); - } - - payload = { id }; + // Fallback to empty workspace if we have no payload yet. + if (!workspaceInitializationPayload) { + let id: string; + if (this.environmentService.configuration.backupWorkspaceResource) { + id = basename(this.environmentService.configuration.backupWorkspaceResource); // we know the backupPath must be a unique path so we leverage its name as workspace ID + } else if (this.environmentService.isExtensionDevelopment) { + id = 'ext-dev'; // extension development window never stores backups and is a singleton + } else { + throw new Error('Unexpected window configuration without backupPath'); } - return payload; - }); + workspaceInitializationPayload = { id }; + } + + return workspaceInitializationPayload; } - private resolveSingleFolderWorkspaceInitializationPayload(folderUri: ISingleFolderWorkspaceIdentifier): Promise { + private async resolveSingleFolderWorkspaceInitializationPayload(folderUri: ISingleFolderWorkspaceIdentifier): Promise { // Return early the folder is not local if (folderUri.scheme !== Schemas.file) { - return Promise.resolve({ id: createHash('md5').update(folderUri.toString()).digest('hex'), folder: folderUri }); + return { id: createHash('md5').update(folderUri.toString()).digest('hex'), folder: folderUri }; } function computeLocalDiskFolderId(folder: URI, stat: fs.Stats): string { @@ -285,45 +293,56 @@ class CodeRendererMain extends Disposable { } // For local: ensure path is absolute and exists - const sanitizedFolderPath = sanitizeFilePath(folderUri.fsPath, process.env['VSCODE_CWD'] || process.cwd()); - return stat(sanitizedFolderPath).then(stat => { + try { + const sanitizedFolderPath = sanitizeFilePath(folderUri.fsPath, process.env['VSCODE_CWD'] || process.cwd()); + const fileStat = await stat(sanitizedFolderPath); + const sanitizedFolderUri = URI.file(sanitizedFolderPath); return { - id: computeLocalDiskFolderId(sanitizedFolderUri, stat), + id: computeLocalDiskFolderId(sanitizedFolderUri, fileStat), folder: sanitizedFolderUri }; - }, error => onUnexpectedError(error)); + } catch (error) { + onUnexpectedError(error); + } + + return; } - private createWorkspaceService(payload: IWorkspaceInitializationPayload, environmentService: IWorkbenchEnvironmentService, fileService: FileService, remoteAgentService: IRemoteAgentService, logService: ILogService): Promise { - const configurationFileService = new ConfigurationFileService(); - configurationFileService.fileService = fileService; + private async createWorkspaceService(payload: IWorkspaceInitializationPayload, fileService: FileService, remoteAgentService: IRemoteAgentService, logService: ILogService): Promise { + const workspaceService = new WorkspaceService({ remoteAuthority: this.environmentService.configuration.remoteAuthority, configurationCache: new ConfigurationCache(this.environmentService) }, this.environmentService, fileService, remoteAgentService); - const workspaceService = new WorkspaceService({ userSettingsResource: URI.file(environmentService.appSettingsPath), remoteAuthority: this.configuration.remoteAuthority, configurationCache: new ConfigurationCache(environmentService) }, configurationFileService, remoteAgentService); + try { + await workspaceService.initialize(payload); - return workspaceService.initialize(payload).then(() => workspaceService, error => { + return workspaceService; + } catch (error) { onUnexpectedError(error); logService.error(error); return workspaceService; - }); + } } - private createStorageService(payload: IWorkspaceInitializationPayload, environmentService: IWorkbenchEnvironmentService, logService: ILogService, mainProcessService: IMainProcessService): Promise { + private async createStorageService(payload: IWorkspaceInitializationPayload, logService: ILogService, mainProcessService: IMainProcessService): Promise { const globalStorageDatabase = new GlobalStorageDatabaseChannelClient(mainProcessService.getChannel('storage')); - const storageService = new StorageService(globalStorageDatabase, logService, environmentService); + const storageService = new StorageService(globalStorageDatabase, logService, this.environmentService); + + try { + await storageService.initialize(payload); - return storageService.initialize(payload).then(() => storageService, error => { + return storageService; + } catch (error) { onUnexpectedError(error); logService.error(error); return storageService; - }); + } } private createLogService(mainProcessService: IMainProcessService, environmentService: IWorkbenchEnvironmentService): ILogService { - const spdlogService = createSpdLogService(`renderer${this.configuration.windowId}`, this.configuration.logLevel, environmentService.logsPath); - const consoleLogService = new ConsoleLogService(this.configuration.logLevel); + const spdlogService = new SpdLogService(`renderer${this.environmentService.configuration.windowId}`, environmentService.logsPath, this.environmentService.configuration.logLevel); + const consoleLogService = new ConsoleLogService(this.environmentService.configuration.logLevel); const logService = new MultiplexLogService([consoleLogService, spdlogService]); const logLevelClient = new LogLevelSetterChannelClient(mainProcessService.getChannel('loglevel')); diff --git a/src/vs/workbench/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts index 768718371..e10a49bae 100644 --- a/src/vs/workbench/electron-browser/window.ts +++ b/src/vs/workbench/electron-browser/window.ts @@ -21,14 +21,14 @@ import { IWorkbenchThemeService, VS_HC_THEME } from 'vs/workbench/services/theme import * as browser from 'vs/base/browser/browser'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IResourceInput } from 'vs/platform/editor/common/editor'; -import { KeyboardMapperFactory } from 'vs/workbench/services/keybinding/electron-browser/keybindingService'; +import { KeyboardMapperFactory } from 'vs/workbench/services/keybinding/electron-browser/nativeKeymapService'; import { ipcRenderer as ipc, webFrame, crashReporter, Event } from 'electron'; 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 { fillInActionBarActions } from 'vs/platform/actions/browser/menuItemActionItem'; +import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { RunOnceScheduler } from 'vs/base/common/async'; -import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { LifecyclePhase, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces'; import { IIntegrityService } from 'vs/workbench/services/integrity/common/integrity'; @@ -43,6 +43,8 @@ import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessi import { WorkbenchState, IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { coalesce } from 'vs/base/common/arrays'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; +import { isEqual } from 'vs/base/common/resources'; const TextInputActions: IAction[] = [ new Action('undo', nls.localize('undo', "Undo"), undefined, true, () => Promise.resolve(document.execCommand('undo'))), @@ -59,7 +61,7 @@ export class ElectronWindow extends Disposable { private touchBarMenu?: IMenu; private touchBarUpdater: RunOnceScheduler; - private touchBarDisposables: IDisposable[]; + private readonly touchBarDisposables = this._register(new DisposableStore()); private lastInstalledTouchedBar: ICommandAction[][]; private previousConfiguredZoomLevel: number; @@ -88,12 +90,11 @@ export class ElectronWindow extends Disposable { @IIntegrityService private readonly integrityService: IIntegrityService, @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, @IAccessibilityService private readonly accessibilityService: IAccessibilityService, - @IWorkspaceContextService private readonly contextService: IWorkspaceContextService + @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, + @ITextFileService private readonly textFileService: ITextFileService ) { super(); - this.touchBarDisposables = []; - this.pendingFoldersToAdd = []; this.addFoldersScheduler = this._register(new RunOnceScheduler(() => this.doAddFolders(), 100)); @@ -114,7 +115,7 @@ export class ElectronWindow extends Disposable { }); // Support runAction event - ipc.on('vscode:runAction', (event: Event, request: IRunActionInWindowRequest) => { + ipc.on('vscode:runAction', async (event: Event, request: IRunActionInWindowRequest) => { const args: unknown[] = request.args || []; // If we run an action from the touchbar, we fill in the currently active resource @@ -131,17 +132,17 @@ export class ElectronWindow extends Disposable { args.push({ from: request.from }); // TODO@telemetry this is a bit weird to send this to every action? } - this.commandService.executeCommand(request.id, ...args).then(_ => { - /* __GDPR__ - "commandExecuted" : { - "id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "from": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } - } - */ - this.telemetryService.publicLog('commandExecuted', { id: request.id, from: request.from }); - }, err => { - this.notificationService.error(err); - }); + try { + await this.commandService.executeCommand(request.id, ...args); + + type CommandExecutedClassifcation = { + id: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + from: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + }; + this.telemetryService.publicLog2<{ id: String, from: String }, CommandExecutedClassifcation>('commandExecuted', { id: request.id, from: request.from }); + } catch (error) { + this.notificationService.error(error); + } }); // Support runKeybinding event @@ -170,34 +171,30 @@ export class ElectronWindow extends Disposable { }); // Fullscreen Events - ipc.on('vscode:enterFullScreen', () => { - this.lifecycleService.when(LifecyclePhase.Ready).then(() => { - browser.setFullscreen(true); - }); + ipc.on('vscode:enterFullScreen', async () => { + await this.lifecycleService.when(LifecyclePhase.Ready); + browser.setFullscreen(true); }); - ipc.on('vscode:leaveFullScreen', () => { - this.lifecycleService.when(LifecyclePhase.Ready).then(() => { - browser.setFullscreen(false); - }); + ipc.on('vscode:leaveFullScreen', async () => { + await this.lifecycleService.when(LifecyclePhase.Ready); + browser.setFullscreen(false); }); // High Contrast Events - ipc.on('vscode:enterHighContrast', () => { + ipc.on('vscode:enterHighContrast', async () => { const windowConfig = this.configurationService.getValue('window'); if (windowConfig && windowConfig.autoDetectHighContrast) { - this.lifecycleService.when(LifecyclePhase.Ready).then(() => { - this.themeService.setColorTheme(VS_HC_THEME, undefined); - }); + await this.lifecycleService.when(LifecyclePhase.Ready); + this.themeService.setColorTheme(VS_HC_THEME, undefined); } }); - ipc.on('vscode:leaveHighContrast', () => { + ipc.on('vscode:leaveHighContrast', async () => { const windowConfig = this.configurationService.getValue('window'); if (windowConfig && windowConfig.autoDetectHighContrast) { - this.lifecycleService.when(LifecyclePhase.Ready).then(() => { - this.themeService.restoreColorTheme(); - }); + await this.lifecycleService.when(LifecyclePhase.Ready); + this.themeService.restoreColorTheme(); } }); @@ -228,11 +225,10 @@ export class ElectronWindow extends Disposable { // Listen to editor closing (if we run with --wait) const filesToWait = this.environmentService.configuration.filesToWait; if (filesToWait) { - const resourcesToWaitFor = coalesce(filesToWait.paths.map(p => p.fileUri)); const waitMarkerFile = filesToWait.waitMarkerFileUri; - const listenerDispose = this.editorService.onDidCloseEditor(() => this.onEditorClosed(listenerDispose, resourcesToWaitFor, waitMarkerFile)); + const resourcesToWaitFor = coalesce(filesToWait.paths.map(p => p.fileUri)); - this._register(listenerDispose); + this._register(this.trackClosedWaitFiles(waitMarkerFile, resourcesToWaitFor)); } } @@ -257,17 +253,6 @@ export class ElectronWindow extends Disposable { } } - 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. - if (resourcesToWaitFor.every(resource => !this.editorService.isOpen({ resource }))) { - listenerDispose.dispose(); - this.fileService.del(waitMarkerFile); - } - } - private onContextMenu(e: MouseEvent): void { if (e.target instanceof HTMLElement) { const target = e.target; @@ -319,9 +304,7 @@ export class ElectronWindow extends Disposable { }; // Emit event when vscode is ready - this.lifecycleService.when(LifecyclePhase.Ready).then(() => { - ipc.send('vscode:workbenchReady', this.windowService.windowId); - }); + this.lifecycleService.when(LifecyclePhase.Ready).then(() => ipc.send('vscode:workbenchReady', this.windowService.windowId)); // Integrity warning this.integrityService.isPure().then(res => this.titleService.updateProperties({ isPure: res.isPure })); @@ -330,7 +313,7 @@ export class ElectronWindow extends Disposable { this.lifecycleService.when(LifecyclePhase.Restored).then(() => { let isAdminPromise: Promise; if (isWindows) { - isAdminPromise = import('native-is-elevated').then(isElevated => isElevated()); + isAdminPromise = import('native-is-elevated').then(isElevated => isElevated()); // not using async here due to https://github.com/microsoft/vscode/issues/74321 } else { isAdminPromise = Promise.resolve(isRootUser()); } @@ -365,26 +348,26 @@ export class ElectronWindow extends Disposable { } // Dispose old - this.touchBarDisposables = dispose(this.touchBarDisposables); + this.touchBarDisposables.clear(); this.touchBarMenu = undefined; // Create new (delayed) this.touchBarUpdater = new RunOnceScheduler(() => this.doUpdateTouchbarMenu(), 300); - this.touchBarDisposables.push(this.touchBarUpdater); + this.touchBarDisposables.add(this.touchBarUpdater); this.touchBarUpdater.schedule(); } private doUpdateTouchbarMenu(): void { if (!this.touchBarMenu) { this.touchBarMenu = this.editorService.invokeWithinEditorContext(accessor => this.menuService.createMenu(MenuId.TouchBarContext, accessor.get(IContextKeyService))); - this.touchBarDisposables.push(this.touchBarMenu); - this.touchBarDisposables.push(this.touchBarMenu.onDidChange(() => this.touchBarUpdater.schedule())); + this.touchBarDisposables.add(this.touchBarMenu); + this.touchBarDisposables.add(this.touchBarMenu.onDidChange(() => this.touchBarUpdater.schedule())); } const actions: Array = []; // Fill actions into groups respecting order - fillInActionBarActions(this.touchBarMenu, undefined, actions); + this.touchBarDisposables.add(createAndFillInActionBarActions(this.touchBarMenu, undefined, actions)); // Convert into command action multi array const items: ICommandAction[][] = []; @@ -417,13 +400,13 @@ export class ElectronWindow extends Disposable { } } - private setupCrashReporter(): void { + private async setupCrashReporter(): Promise { // base options with product info const options = { companyName: product.crashReporter.companyName, productName: product.crashReporter.productName, - submitURL: isWindows ? product.hockeyApp[`win32-${process.arch}`] : isLinux ? product.hockeyApp[`linux-${process.arch}`] : product.hockeyApp.darwin, + submitURL: isWindows ? product.hockeyApp[process.arch === 'ia32' ? 'win32-ia32' : 'win32-x64'] : isLinux ? product.hockeyApp[`linux-x64`] : product.hockeyApp.darwin, extra: { vscode_version: pkg.version, vscode_commit: product.commit @@ -431,18 +414,14 @@ export class ElectronWindow extends Disposable { }; // mixin telemetry info - this.telemetryService.getTelemetryInfo() - .then(info => { - assign(options.extra, { - vscode_sessionId: info.sessionId - }); + const info = await this.telemetryService.getTelemetryInfo(); + assign(options.extra, { vscode_sessionId: info.sessionId }); - // start crash reporter right here - crashReporter.start(deepClone(options)); + // start crash reporter right here + crashReporter.start(deepClone(options)); - // start crash reporter in the main process - return this.windowsService.startCrashReporter(options); - }); + // start crash reporter in the main process + return this.windowsService.startCrashReporter(options); } private onAddFoldersRequest(request: IAddFoldersRequest): void { @@ -488,38 +467,66 @@ export class ElectronWindow extends Disposable { // 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.revive(p.fileUri)); const waitMarkerFile = URI.revive(request.filesToWait.waitMarkerFileUri); - const unbind = this.editorService.onDidCloseEditor(() => { - if (resourcesToWaitFor.every(resource => !this.editorService.isOpen({ resource }))) { - unbind.dispose(); - this.fileService.del(waitMarkerFile); - } - }); + const resourcesToWaitFor = coalesce(request.filesToWait.paths.map(p => URI.revive(p.fileUri))); + this.trackClosedWaitFiles(waitMarkerFile, resourcesToWaitFor); } } - private openResources(resources: Array, diffMode: boolean): void { - this.lifecycleService.when(LifecyclePhase.Ready).then((): Promise => { + private trackClosedWaitFiles(waitMarkerFile: URI, resourcesToWaitFor: URI[]): IDisposable { + const listener = this.editorService.onDidCloseEditor(async () => { + // 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. + if (resourcesToWaitFor.every(resource => !this.editorService.isOpen({ resource }))) { + // If auto save is configured with the default delay (1s) it is possible + // to close the editor while the save still continues in the background. As such + // we have to also check if the files to wait for are dirty and if so wait + // for them to get saved before deleting the wait marker file. + const dirtyFilesToWait = this.textFileService.getDirty(resourcesToWaitFor); + if (dirtyFilesToWait.length > 0) { + await Promise.all(dirtyFilesToWait.map(async dirtyFileToWait => await this.joinResourceSaved(dirtyFileToWait))); + } - // In diffMode we open 2 resources as diff - if (diffMode && resources.length === 2) { - return this.editorService.openEditor({ leftResource: resources[0].resource!, rightResource: resources[1].resource!, options: { pinned: true } }); + listener.dispose(); + await this.fileService.del(waitMarkerFile); } + }); - // For one file, just put it into the current active editor - if (resources.length === 1) { - return this.editorService.openEditor(resources[0]); + return listener; + } + + private joinResourceSaved(resource: URI): Promise { + return new Promise(resolve => { + if (!this.textFileService.isDirty(resource)) { + return resolve(); // return early if resource is not dirty } - // Otherwise open all - return this.editorService.openEditors(resources); + // Otherwise resolve promise when resource is saved + const listener = this.textFileService.models.onModelSaved(e => { + if (isEqual(resource, e.resource)) { + listener.dispose(); + + resolve(); + } + }); }); } - dispose(): void { - this.touchBarDisposables = dispose(this.touchBarDisposables); + private async openResources(resources: Array, diffMode: boolean): Promise { + await this.lifecycleService.when(LifecyclePhase.Ready); + + // In diffMode we open 2 resources as diff + if (diffMode && resources.length === 2) { + return this.editorService.openEditor({ leftResource: resources[0].resource!, rightResource: resources[1].resource!, options: { pinned: true } }); + } + + // For one file, just put it into the current active editor + if (resources.length === 1) { + return this.editorService.openEditor(resources[0]); + } - super.dispose(); + // Otherwise open all + return this.editorService.openEditors(resources); } } diff --git a/src/vs/workbench/services/accessibility/node/accessibilityService.ts b/src/vs/workbench/services/accessibility/node/accessibilityService.ts index d9ace4fc4..02b215b5a 100644 --- a/src/vs/workbench/services/accessibility/node/accessibilityService.ts +++ b/src/vs/workbench/services/accessibility/node/accessibilityService.ts @@ -5,19 +5,23 @@ import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; import { isWindows } from 'vs/base/common/platform'; -import { Emitter, Event } from 'vs/base/common/event'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { AbstractAccessibilityService } from 'vs/platform/accessibility/common/abstractAccessibilityService'; -export class AccessibilityService implements IAccessibilityService { +export class AccessibilityService extends AbstractAccessibilityService implements IAccessibilityService { _serviceBrand: any; private _accessibilitySupport = AccessibilitySupport.Unknown; - private readonly _onDidChangeAccessibilitySupport = new Emitter(); - readonly onDidChangeAccessibilitySupport: Event = this._onDidChangeAccessibilitySupport.event; constructor( - @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService - ) { } + @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, + @IContextKeyService readonly contextKeyService: IContextKeyService, + @IConfigurationService readonly configurationService: IConfigurationService + ) { + super(contextKeyService, configurationService); + } alwaysUnderlineAccessKeys(): Promise { if (!isWindows) { diff --git a/src/vs/workbench/services/backup/common/backup.ts b/src/vs/workbench/services/backup/common/backup.ts index b1f30ade0..771cba84a 100644 --- a/src/vs/workbench/services/backup/common/backup.ts +++ b/src/vs/workbench/services/backup/common/backup.ts @@ -4,22 +4,35 @@ *--------------------------------------------------------------------------------------------*/ import { URI } from 'vs/base/common/uri'; -import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; import { ITextBufferFactory, ITextSnapshot } from 'vs/editor/common/model'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { joinPath, relativePath } from 'vs/base/common/resources'; export const IBackupFileService = createDecorator('backupFileService'); +export interface IResolvedBackup { + value: ITextBufferFactory; + meta?: T; +} + /** * A service that handles any I/O and state associated with the backup system. */ export interface IBackupFileService { - _serviceBrand: any; + + _serviceBrand: ServiceIdentifier; /** * Finds out if there are any backups stored. */ hasBackups(): Promise; + /** + * Finds out if the provided resource with the given version is backed up. + */ + hasBackupSync(resource: URI, versionId?: number): boolean; + /** * Loads the backup resource for a particular resource within the current workspace. * @@ -42,8 +55,10 @@ export interface IBackupFileService { * @param resource The resource to back up. * @param content The content of the resource as snapshot. * @param versionId The version id of the resource to backup. + * @param meta The (optional) meta data of the resource to backup. This information + * can be restored later when loading the backup again. */ - backupResource(resource: URI, content: ITextSnapshot, versionId?: number): Promise; + backupResource(resource: URI, content: ITextSnapshot, versionId?: number, meta?: T): Promise; /** * Gets a list of file backups for the current workspace. @@ -55,10 +70,10 @@ export interface IBackupFileService { /** * Resolves the backup for the given resource. * - * @param value The contents from a backup resource as stream. - * @return The backup file's backed up content as text buffer factory. + * @param resource The resource to get the backup for. + * @return The backup file's backed up content and metadata if available. */ - resolveBackupContent(backup: URI): Promise; + resolveBackupContent(resource: URI): Promise>; /** * Discards the backup associated with a resource if it exists.. @@ -73,3 +88,7 @@ export interface IBackupFileService { */ discardAllWorkspaceBackups(): Promise; } + +export function toBackupWorkspaceResource(backupWorkspacePath: string, environmentService: IEnvironmentService): URI { + return joinPath(environmentService.userRoamingDataHome, relativePath(URI.file(environmentService.userDataPath), URI.file(backupWorkspacePath))!); +} \ No newline at end of file diff --git a/src/vs/workbench/services/backup/common/backupFileService.ts b/src/vs/workbench/services/backup/common/backupFileService.ts new file mode 100644 index 000000000..3193fee95 --- /dev/null +++ b/src/vs/workbench/services/backup/common/backupFileService.ts @@ -0,0 +1,443 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { join } from 'vs/base/common/path'; +import { joinPath } from 'vs/base/common/resources'; +import { URI } from 'vs/base/common/uri'; +import { hash } from 'vs/base/common/hash'; +import { coalesce } from 'vs/base/common/arrays'; +import { equals, deepClone } from 'vs/base/common/objects'; +import { ResourceQueue } from 'vs/base/common/async'; +import { IBackupFileService, IResolvedBackup } from 'vs/workbench/services/backup/common/backup'; +import { IFileService } from 'vs/platform/files/common/files'; +import { ITextSnapshot } from 'vs/editor/common/model'; +import { createTextBufferFactoryFromStream, createTextBufferFactoryFromSnapshot } from 'vs/editor/common/model/textModel'; +import { keys, ResourceMap } from 'vs/base/common/map'; +import { Schemas } from 'vs/base/common/network'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { VSBuffer } from 'vs/base/common/buffer'; +import { TextSnapshotReadable } from 'vs/workbench/services/textfile/common/textfiles'; +import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; + +export interface IBackupFilesModel { + resolve(backupRoot: URI): Promise; + + add(resource: URI, versionId?: number, meta?: object): void; + has(resource: URI, versionId?: number, meta?: object): boolean; + get(): URI[]; + remove(resource: URI): void; + count(): number; + clear(): void; +} + +interface IBackupCacheEntry { + versionId?: number; + meta?: object; +} + +export class BackupFilesModel implements IBackupFilesModel { + private cache: ResourceMap = new ResourceMap(); + + constructor(private fileService: IFileService) { } + + async resolve(backupRoot: URI): Promise { + try { + const backupRootStat = await this.fileService.resolve(backupRoot); + if (backupRootStat.children) { + await Promise.all(backupRootStat.children + .filter(child => child.isDirectory) + .map(async backupSchema => { + + // Read backup directory for backups + const backupSchemaStat = await this.fileService.resolve(backupSchema.resource); + + // Remember known backups in our caches + if (backupSchemaStat.children) { + backupSchemaStat.children.forEach(backupHash => this.add(backupHash.resource)); + } + })); + } + } catch (error) { + // ignore any errors + } + + return this; + } + + add(resource: URI, versionId = 0, meta?: object): void { + this.cache.set(resource, { versionId, meta: deepClone(meta) }); // make sure to not store original meta in our cache... + } + + count(): number { + return this.cache.size; + } + + has(resource: URI, versionId?: number, meta?: object): boolean { + const entry = this.cache.get(resource); + if (!entry) { + return false; // unknown resource + } + + if (typeof versionId === 'number' && versionId !== entry.versionId) { + return false; // different versionId + } + + if (meta && !equals(meta, entry.meta)) { + return false; // different metadata + } + + return true; + } + + get(): URI[] { + return this.cache.keys(); + } + + remove(resource: URI): void { + this.cache.delete(resource); + } + + clear(): void { + this.cache.clear(); + } +} + +export class BackupFileService implements IBackupFileService { + + _serviceBrand: ServiceIdentifier; + + private impl: IBackupFileService; + + constructor( + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, + @IFileService fileService: IFileService + ) { + const backupWorkspaceResource = environmentService.configuration.backupWorkspaceResource; + if (backupWorkspaceResource) { + this.impl = new BackupFileServiceImpl(backupWorkspaceResource, this.hashPath, fileService); + } else { + this.impl = new InMemoryBackupFileService(this.hashPath); + } + } + + protected hashPath(resource: URI): string { + const str = resource.scheme === Schemas.file || resource.scheme === Schemas.untitled ? resource.fsPath : resource.toString(); + + return hash(str).toString(16); + } + + initialize(backupWorkspaceResource: URI): void { + if (this.impl instanceof BackupFileServiceImpl) { + this.impl.initialize(backupWorkspaceResource); + } + } + + hasBackups(): Promise { + return this.impl.hasBackups(); + } + + hasBackupSync(resource: URI, versionId?: number): boolean { + return this.impl.hasBackupSync(resource, versionId); + } + + loadBackupResource(resource: URI): Promise { + return this.impl.loadBackupResource(resource); + } + + backupResource(resource: URI, content: ITextSnapshot, versionId?: number, meta?: T): Promise { + return this.impl.backupResource(resource, content, versionId, meta); + } + + discardResourceBackup(resource: URI): Promise { + return this.impl.discardResourceBackup(resource); + } + + discardAllWorkspaceBackups(): Promise { + return this.impl.discardAllWorkspaceBackups(); + } + + getWorkspaceFileBackups(): Promise { + return this.impl.getWorkspaceFileBackups(); + } + + resolveBackupContent(backup: URI): Promise> { + return this.impl.resolveBackupContent(backup); + } + + toBackupResource(resource: URI): URI { + return this.impl.toBackupResource(resource); + } +} + +class BackupFileServiceImpl implements IBackupFileService { + + private static readonly PREAMBLE_END_MARKER = '\n'; + private static readonly PREAMBLE_META_SEPARATOR = ' '; // using a character that is know to be escaped in a URI as separator + private static readonly PREAMBLE_MAX_LENGTH = 10000; + + _serviceBrand: ServiceIdentifier; + + private backupWorkspacePath: URI; + + private isShuttingDown: boolean; + private ioOperationQueues: ResourceQueue; // queue IO operations to ensure write order + + private ready: Promise; + private model: IBackupFilesModel; + + constructor( + backupWorkspaceResource: URI, + private readonly hashPath: (resource: URI) => string, + @IFileService private readonly fileService: IFileService + ) { + this.isShuttingDown = false; + this.ioOperationQueues = new ResourceQueue(); + + this.initialize(backupWorkspaceResource); + } + + initialize(backupWorkspaceResource: URI): void { + this.backupWorkspacePath = backupWorkspaceResource; + + this.ready = this.init(); + } + + private init(): Promise { + this.model = new BackupFilesModel(this.fileService); + + return this.model.resolve(this.backupWorkspacePath); + } + + async hasBackups(): Promise { + const model = await this.ready; + + return model.count() > 0; + } + + hasBackupSync(resource: URI, versionId?: number): boolean { + const backupResource = this.toBackupResource(resource); + + return this.model.has(backupResource, versionId); + } + + async loadBackupResource(resource: URI): Promise { + const model = await this.ready; + + // Return directly if we have a known backup with that resource + const backupResource = this.toBackupResource(resource); + if (model.has(backupResource)) { + return backupResource; + } + + return undefined; + } + + async backupResource(resource: URI, content: ITextSnapshot, versionId?: number, meta?: T): Promise { + if (this.isShuttingDown) { + return; + } + + const model = await this.ready; + + const backupResource = this.toBackupResource(resource); + if (model.has(backupResource, versionId, meta)) { + return; // return early if backup version id matches requested one + } + + return this.ioOperationQueues.queueFor(backupResource).queue(async () => { + let preamble: string | undefined = undefined; + + // With Metadata: URI + META-START + Meta + END + if (meta) { + const preambleWithMeta = `${resource.toString()}${BackupFileServiceImpl.PREAMBLE_META_SEPARATOR}${JSON.stringify(meta)}${BackupFileServiceImpl.PREAMBLE_END_MARKER}`; + if (preambleWithMeta.length < BackupFileServiceImpl.PREAMBLE_MAX_LENGTH) { + preamble = preambleWithMeta; + } + } + + // Without Metadata: URI + END + if (!preamble) { + preamble = `${resource.toString()}${BackupFileServiceImpl.PREAMBLE_END_MARKER}`; + } + + // Update content with value + await this.fileService.writeFile(backupResource, new TextSnapshotReadable(content, preamble)); + + // Update model + model.add(backupResource, versionId, meta); + }); + } + + async discardResourceBackup(resource: URI): Promise { + const model = await this.ready; + const backupResource = this.toBackupResource(resource); + + return this.ioOperationQueues.queueFor(backupResource).queue(async () => { + await this.fileService.del(backupResource, { recursive: true }); + + model.remove(backupResource); + }); + } + + async discardAllWorkspaceBackups(): Promise { + this.isShuttingDown = true; + + const model = await this.ready; + + await this.fileService.del(this.backupWorkspacePath, { recursive: true }); + + model.clear(); + } + + async getWorkspaceFileBackups(): Promise { + const model = await this.ready; + + const backups = await Promise.all(model.get().map(async fileBackup => { + const backupPreamble = await this.readToMatchingString(fileBackup, BackupFileServiceImpl.PREAMBLE_END_MARKER, BackupFileServiceImpl.PREAMBLE_MAX_LENGTH); + if (!backupPreamble) { + return undefined; + } + + // Preamble with metadata: URI + META-START + Meta + END + const metaStartIndex = backupPreamble.indexOf(BackupFileServiceImpl.PREAMBLE_META_SEPARATOR); + if (metaStartIndex > 0) { + return URI.parse(backupPreamble.substring(0, metaStartIndex)); + } + + // Preamble without metadata: URI + END + else { + return URI.parse(backupPreamble); + } + })); + + return coalesce(backups); + } + + private async readToMatchingString(file: URI, matchingString: string, maximumBytesToRead: number): Promise { + const contents = (await this.fileService.readFile(file, { length: maximumBytesToRead })).value.toString(); + + const newLineIndex = contents.indexOf(matchingString); + if (newLineIndex >= 0) { + return contents.substr(0, newLineIndex); + } + + throw new Error(`Could not find ${JSON.stringify(matchingString)} in first ${maximumBytesToRead} bytes of ${file}`); + } + + async resolveBackupContent(backup: URI): Promise> { + + // Metadata extraction + let metaRaw = ''; + let metaEndFound = false; + + // Add a filter method to filter out everything until the meta end marker + const metaPreambleFilter = (chunk: VSBuffer) => { + const chunkString = chunk.toString(); + + if (!metaEndFound) { + const metaEndIndex = chunkString.indexOf(BackupFileServiceImpl.PREAMBLE_END_MARKER); + if (metaEndIndex === -1) { + metaRaw += chunkString; + + return VSBuffer.fromString(''); // meta not yet found, return empty string + } + + metaEndFound = true; + metaRaw += chunkString.substring(0, metaEndIndex); // ensure to get last chunk from metadata + + return VSBuffer.fromString(chunkString.substr(metaEndIndex + 1)); // meta found, return everything after + } + + return chunk; + }; + + // Read backup into factory + const content = await this.fileService.readFileStream(backup); + const factory = await createTextBufferFactoryFromStream(content.value, metaPreambleFilter); + + // Trigger read for meta data extraction from the filter above + factory.getFirstLineText(1); + + let meta: T | undefined; + const metaStartIndex = metaRaw.indexOf(BackupFileServiceImpl.PREAMBLE_META_SEPARATOR); + if (metaStartIndex !== -1) { + try { + meta = JSON.parse(metaRaw.substr(metaStartIndex + 1)); + } catch (error) { + // ignore JSON parse errors + } + } + + return { value: factory, meta }; + } + + toBackupResource(resource: URI): URI { + return joinPath(this.backupWorkspacePath, resource.scheme, this.hashPath(resource)); + } +} + +export class InMemoryBackupFileService implements IBackupFileService { + + _serviceBrand: ServiceIdentifier; + + private backups: Map = new Map(); + + constructor(private readonly hashPath: (resource: URI) => string) { } + + hasBackups(): Promise { + return Promise.resolve(this.backups.size > 0); + } + + hasBackupSync(resource: URI, versionId?: number): boolean { + const backupResource = this.toBackupResource(resource); + + return this.backups.has(backupResource.toString()); + } + + loadBackupResource(resource: URI): Promise { + const backupResource = this.toBackupResource(resource); + if (this.backups.has(backupResource.toString())) { + return Promise.resolve(backupResource); + } + + return Promise.resolve(undefined); + } + + backupResource(resource: URI, content: ITextSnapshot, versionId?: number, meta?: T): Promise { + const backupResource = this.toBackupResource(resource); + this.backups.set(backupResource.toString(), content); + + return Promise.resolve(); + } + + resolveBackupContent(backupResource: URI): Promise> { + const snapshot = this.backups.get(backupResource.toString()); + if (snapshot) { + return Promise.resolve({ value: createTextBufferFactoryFromSnapshot(snapshot) }); + } + + return Promise.reject('Unexpected backup resource to resolve'); + } + + getWorkspaceFileBackups(): Promise { + return Promise.resolve(keys(this.backups).map(key => URI.parse(key))); + } + + discardResourceBackup(resource: URI): Promise { + this.backups.delete(this.toBackupResource(resource).toString()); + + return Promise.resolve(); + } + + discardAllWorkspaceBackups(): Promise { + this.backups.clear(); + + return Promise.resolve(); + } + + toBackupResource(resource: URI): URI { + return URI.file(join(resource.scheme, this.hashPath(resource))); + } +} \ No newline at end of file diff --git a/src/vs/workbench/services/backup/node/backupFileService.ts b/src/vs/workbench/services/backup/node/backupFileService.ts index 21d8187ef..30b5c5acf 100644 --- a/src/vs/workbench/services/backup/node/backupFileService.ts +++ b/src/vs/workbench/services/backup/node/backupFileService.ts @@ -3,345 +3,23 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as path from 'vs/base/common/path'; -import * as crypto from 'crypto'; -import * as pfs from 'vs/base/node/pfs'; -import { URI as Uri } from 'vs/base/common/uri'; -import { ResourceQueue } from 'vs/base/common/async'; -import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; -import { IFileService } from 'vs/platform/files/common/files'; -import { readToMatchingString } from 'vs/base/node/stream'; -import { ITextBufferFactory, ITextSnapshot } from 'vs/editor/common/model'; -import { createTextBufferFactoryFromStream, createTextBufferFactoryFromSnapshot } from 'vs/editor/common/model/textModel'; -import { keys } from 'vs/base/common/map'; +import { BackupFileService as CommonBackupFileService } from 'vs/workbench/services/backup/common/backupFileService'; +import { URI } from 'vs/base/common/uri'; import { Schemas } from 'vs/base/common/network'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { VSBuffer } from 'vs/base/common/buffer'; -import { TextSnapshotReadable } from 'vs/workbench/services/textfile/common/textfiles'; - -export interface IBackupFilesModel { - resolve(backupRoot: string): Promise; - - add(resource: Uri, versionId?: number): void; - has(resource: Uri, versionId?: number): boolean; - get(): Uri[]; - remove(resource: Uri): void; - count(): number; - clear(): void; -} - -export class BackupFilesModel implements IBackupFilesModel { - private cache: { [resource: string]: number /* version ID */ } = Object.create(null); - - resolve(backupRoot: string): Promise { - return pfs.readDirsInDir(backupRoot).then(backupSchemas => { - - // For all supported schemas - return Promise.all(backupSchemas.map(backupSchema => { - - // Read backup directory for backups - const backupSchemaPath = path.join(backupRoot, backupSchema); - return pfs.readdir(backupSchemaPath).then(backupHashes => { - - // Remember known backups in our caches - backupHashes.forEach(backupHash => { - const backupResource = Uri.file(path.join(backupSchemaPath, backupHash)); - this.add(backupResource); - }); - }); - })); - }).then(() => this, error => this); - } - - add(resource: Uri, versionId = 0): void { - this.cache[resource.toString()] = versionId; - } - - count(): number { - return Object.keys(this.cache).length; - } - - has(resource: Uri, versionId?: number): boolean { - const cachedVersionId = this.cache[resource.toString()]; - if (typeof cachedVersionId !== 'number') { - return false; // unknown resource - } - - if (typeof versionId === 'number') { - return versionId === cachedVersionId; // if we are asked with a specific version ID, make sure to test for it - } - - return true; - } - - get(): Uri[] { - return Object.keys(this.cache).map(k => Uri.parse(k)); - } - - remove(resource: Uri): void { - delete this.cache[resource.toString()]; - } - - clear(): void { - this.cache = Object.create(null); - } -} - -export class BackupFileService implements IBackupFileService { - - _serviceBrand: any; - - private impl: IBackupFileService; - - constructor( - @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, - @IFileService fileService: IFileService - ) { - const backupWorkspacePath = environmentService.configuration.backupPath; - if (backupWorkspacePath) { - this.impl = new BackupFileServiceImpl(backupWorkspacePath, fileService); - } else { - this.impl = new InMemoryBackupFileService(); - } - } - - initialize(backupWorkspacePath: string): void { - if (this.impl instanceof BackupFileServiceImpl) { - this.impl.initialize(backupWorkspacePath); - } - } - - hasBackups(): Promise { - return this.impl.hasBackups(); - } - - loadBackupResource(resource: Uri): Promise { - return this.impl.loadBackupResource(resource); - } - - backupResource(resource: Uri, content: ITextSnapshot, versionId?: number): Promise { - return this.impl.backupResource(resource, content, versionId); - } - - discardResourceBackup(resource: Uri): Promise { - return this.impl.discardResourceBackup(resource); - } - - discardAllWorkspaceBackups(): Promise { - return this.impl.discardAllWorkspaceBackups(); - } - - getWorkspaceFileBackups(): Promise { - return this.impl.getWorkspaceFileBackups(); - } - - resolveBackupContent(backup: Uri): Promise { - return this.impl.resolveBackupContent(backup); - } - - toBackupResource(resource: Uri): Uri { - return this.impl.toBackupResource(resource); - } -} - -class BackupFileServiceImpl implements IBackupFileService { - - private static readonly META_MARKER = '\n'; - - _serviceBrand: any; - - private backupWorkspacePath: string; - - private isShuttingDown: boolean; - private ready: Promise; - private ioOperationQueues: ResourceQueue; // queue IO operations to ensure write order - - constructor( - backupWorkspacePath: string, - @IFileService private readonly fileService: IFileService - ) { - this.isShuttingDown = false; - this.ioOperationQueues = new ResourceQueue(); - - this.initialize(backupWorkspacePath); - } - - initialize(backupWorkspacePath: string): void { - this.backupWorkspacePath = backupWorkspacePath; - - this.ready = this.init(); - } - - private init(): Promise { - const model = new BackupFilesModel(); - - return model.resolve(this.backupWorkspacePath); - } - - hasBackups(): Promise { - return this.ready.then(model => { - return model.count() > 0; - }); - } - - loadBackupResource(resource: Uri): Promise { - return this.ready.then(model => { - - // Return directly if we have a known backup with that resource - const backupResource = this.toBackupResource(resource); - if (model.has(backupResource)) { - return backupResource; - } - - return undefined; - }); - } - - backupResource(resource: Uri, content: ITextSnapshot, versionId?: number): Promise { - if (this.isShuttingDown) { - return Promise.resolve(); - } - - return this.ready.then(model => { - const backupResource = this.toBackupResource(resource); - if (model.has(backupResource, versionId)) { - return undefined; // return early if backup version id matches requested one - } - - return this.ioOperationQueues.queueFor(backupResource).queue(() => { - const preamble = `${resource.toString()}${BackupFileServiceImpl.META_MARKER}`; - - // Update content with value - return this.fileService.writeFile(backupResource, new TextSnapshotReadable(content, preamble)).then(() => model.add(backupResource, versionId)); - }); - }); - } - - discardResourceBackup(resource: Uri): Promise { - return this.ready.then(model => { - const backupResource = this.toBackupResource(resource); - - return this.ioOperationQueues.queueFor(backupResource).queue(() => { - return pfs.rimraf(backupResource.fsPath, pfs.RimRafMode.MOVE).then(() => model.remove(backupResource)); - }); - }); - } - - discardAllWorkspaceBackups(): Promise { - this.isShuttingDown = true; - - return this.ready.then(model => { - return pfs.rimraf(this.backupWorkspacePath, pfs.RimRafMode.MOVE).then(() => model.clear()); - }); - } - - getWorkspaceFileBackups(): Promise { - return this.ready.then(model => { - const readPromises: Promise[] = []; - - model.get().forEach(fileBackup => { - readPromises.push( - readToMatchingString(fileBackup.fsPath, BackupFileServiceImpl.META_MARKER, 2000, 10000).then(Uri.parse) - ); - }); - - return Promise.all(readPromises); - }); - } - - resolveBackupContent(backup: Uri): Promise { - return this.fileService.readFileStream(backup).then(content => { - - // Add a filter method to filter out everything until the meta marker - let metaFound = false; - const metaPreambleFilter = (chunk: VSBuffer) => { - const chunkString = chunk.toString(); - - if (!metaFound && chunk) { - const metaIndex = chunkString.indexOf(BackupFileServiceImpl.META_MARKER); - if (metaIndex === -1) { - return VSBuffer.fromString(''); // meta not yet found, return empty string - } - - metaFound = true; - return VSBuffer.fromString(chunkString.substr(metaIndex + 1)); // meta found, return everything after - } - - return chunk; - }; - - return createTextBufferFactoryFromStream(content.value, metaPreambleFilter); - }); - } - - toBackupResource(resource: Uri): Uri { - return Uri.file(path.join(this.backupWorkspacePath, resource.scheme, hashPath(resource))); - } -} - -export class InMemoryBackupFileService implements IBackupFileService { - - _serviceBrand: any; - - private backups: Map = new Map(); - - hasBackups(): Promise { - return Promise.resolve(this.backups.size > 0); - } - - loadBackupResource(resource: Uri): Promise { - const backupResource = this.toBackupResource(resource); - if (this.backups.has(backupResource.toString())) { - return Promise.resolve(backupResource); - } - - return Promise.resolve(undefined); - } - - backupResource(resource: Uri, content: ITextSnapshot, versionId?: number): Promise { - const backupResource = this.toBackupResource(resource); - this.backups.set(backupResource.toString(), content); - - return Promise.resolve(); - } - - resolveBackupContent(backupResource: Uri): Promise { - const snapshot = this.backups.get(backupResource.toString()); - if (snapshot) { - return Promise.resolve(createTextBufferFactoryFromSnapshot(snapshot)); - } - - return Promise.resolve(undefined); - } - - getWorkspaceFileBackups(): Promise { - return Promise.resolve(keys(this.backups).map(key => Uri.parse(key))); - } - - discardResourceBackup(resource: Uri): Promise { - this.backups.delete(this.toBackupResource(resource).toString()); - - return Promise.resolve(); - } +import * as crypto from 'crypto'; - discardAllWorkspaceBackups(): Promise { - this.backups.clear(); +export class BackupFileService extends CommonBackupFileService { - return Promise.resolve(); + protected hashPath(resource: URI): string { + return hashPath(resource); } - toBackupResource(resource: Uri): Uri { - return Uri.file(path.join(resource.scheme, hashPath(resource))); - } } /* * Exported only for testing */ -export function hashPath(resource: Uri): string { +export function hashPath(resource: URI): string { const str = resource.scheme === Schemas.file || resource.scheme === Schemas.untitled ? resource.fsPath : resource.toString(); return crypto.createHash('md5').update(str).digest('hex'); -} - -registerSingleton(IBackupFileService, BackupFileService); \ No newline at end of file +} \ No newline at end of file diff --git a/src/vs/workbench/services/backup/test/electron-browser/backupFileService.test.ts b/src/vs/workbench/services/backup/test/electron-browser/backupFileService.test.ts deleted file mode 100644 index fff74b2b7..000000000 --- a/src/vs/workbench/services/backup/test/electron-browser/backupFileService.test.ts +++ /dev/null @@ -1,402 +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 * as platform from 'vs/base/common/platform'; -import * as crypto from 'crypto'; -import * as os from 'os'; -import * as fs from 'fs'; -import * as path from 'vs/base/common/path'; -import * as pfs from 'vs/base/node/pfs'; -import { URI as Uri } from 'vs/base/common/uri'; -import { BackupFileService, BackupFilesModel, hashPath } from 'vs/workbench/services/backup/node/backupFileService'; -import { TextModel, createTextBufferFactory } from 'vs/editor/common/model/textModel'; -import { getRandomTestPath } from 'vs/base/test/node/testUtils'; -import { DefaultEndOfLine } from 'vs/editor/common/model'; -import { Schemas } from 'vs/base/common/network'; -import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; -import { FileService } from 'vs/workbench/services/files/common/fileService'; -import { NullLogService } from 'vs/platform/log/common/log'; -import { DiskFileSystemProvider } from 'vs/workbench/services/files/node/diskFileSystemProvider'; -import { WorkbenchEnvironmentService } from 'vs/workbench/services/environment/node/environmentService'; -import { parseArgs } from 'vs/platform/environment/node/argv'; -import { snapshotToString } from 'vs/workbench/services/textfile/common/textfiles'; - -const parentDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'backupfileservice'); -const backupHome = path.join(parentDir, 'Backups'); -const workspacesJsonPath = path.join(backupHome, 'workspaces.json'); - -const workspaceResource = Uri.file(platform.isWindows ? 'c:\\workspace' : '/workspace'); -const workspaceBackupPath = path.join(backupHome, hashPath(workspaceResource)); -const fooFile = Uri.file(platform.isWindows ? 'c:\\Foo' : '/Foo'); -const barFile = Uri.file(platform.isWindows ? 'c:\\Bar' : '/Bar'); -const untitledFile = Uri.from({ scheme: Schemas.untitled, path: 'Untitled-1' }); -const fooBackupPath = path.join(workspaceBackupPath, 'file', hashPath(fooFile)); -const barBackupPath = path.join(workspaceBackupPath, 'file', hashPath(barFile)); -const untitledBackupPath = path.join(workspaceBackupPath, 'untitled', hashPath(untitledFile)); - -class TestBackupEnvironmentService extends WorkbenchEnvironmentService { - - private config: IWindowConfiguration; - - constructor(workspaceBackupPath: string) { - super(parseArgs(process.argv) as IWindowConfiguration, process.execPath); - - this.config = Object.create(null); - this.config.backupPath = workspaceBackupPath; - } - - get configuration(): IWindowConfiguration { - return this.config; - } -} - -class TestBackupFileService extends BackupFileService { - constructor(workspace: Uri, backupHome: string, workspacesJsonPath: string) { - const fileService = new FileService(new NullLogService()); - fileService.registerProvider(Schemas.file, new DiskFileSystemProvider(new NullLogService())); - const environmentService = new TestBackupEnvironmentService(workspaceBackupPath); - - super(environmentService, fileService); - } - - public toBackupResource(resource: Uri): Uri { - return super.toBackupResource(resource); - } -} - -suite('BackupFileService', () => { - let service: TestBackupFileService; - - setup(() => { - service = new TestBackupFileService(workspaceResource, backupHome, workspacesJsonPath); - - // Delete any existing backups completely and then re-create it. - return pfs.rimraf(backupHome, pfs.RimRafMode.MOVE).then(() => { - return pfs.mkdirp(backupHome).then(() => { - return pfs.writeFile(workspacesJsonPath, ''); - }); - }); - }); - - teardown(() => { - return pfs.rimraf(backupHome, pfs.RimRafMode.MOVE); - }); - - suite('hashPath', () => { - test('should correctly hash the path for untitled scheme URIs', () => { - const uri = Uri.from({ - scheme: 'untitled', - path: 'Untitled-1' - }); - const actual = hashPath(uri); - // If these hashes change people will lose their backed up files! - assert.equal(actual, '13264068d108c6901b3592ea654fcd57'); - assert.equal(actual, crypto.createHash('md5').update(uri.fsPath).digest('hex')); - }); - - test('should correctly hash the path for file scheme URIs', () => { - const uri = Uri.file('/foo'); - const actual = hashPath(uri); - // If these hashes change people will lose their backed up files! - if (platform.isWindows) { - assert.equal(actual, 'dec1a583f52468a020bd120c3f01d812'); - } else { - assert.equal(actual, '1effb2475fcfba4f9e8b8a1dbc8f3caf'); - } - assert.equal(actual, crypto.createHash('md5').update(uri.fsPath).digest('hex')); - }); - }); - - suite('getBackupResource', () => { - test('should get the correct backup path for text files', () => { - // Format should be: /// - const backupResource = fooFile; - const workspaceHash = hashPath(workspaceResource); - const filePathHash = hashPath(backupResource); - const expectedPath = Uri.file(path.join(backupHome, workspaceHash, 'file', filePathHash)).fsPath; - assert.equal(service.toBackupResource(backupResource).fsPath, expectedPath); - }); - - test('should get the correct backup path for untitled files', () => { - // Format should be: /// - const backupResource = Uri.from({ scheme: Schemas.untitled, path: 'Untitled-1' }); - const workspaceHash = hashPath(workspaceResource); - const filePathHash = hashPath(backupResource); - const expectedPath = Uri.file(path.join(backupHome, workspaceHash, 'untitled', filePathHash)).fsPath; - assert.equal(service.toBackupResource(backupResource).fsPath, expectedPath); - }); - }); - - suite('loadBackupResource', () => { - test('should return whether a backup resource exists', () => { - return pfs.mkdirp(path.dirname(fooBackupPath)).then(() => { - fs.writeFileSync(fooBackupPath, 'foo'); - service = new TestBackupFileService(workspaceResource, backupHome, workspacesJsonPath); - return 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); - }); - }); - }); - }); - }); - - suite('backupResource', () => { - test('text file', function () { - return service.backupResource(fooFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => { - assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 1); - assert.equal(fs.existsSync(fooBackupPath), true); - assert.equal(fs.readFileSync(fooBackupPath), `${fooFile.toString()}\ntest`); - }); - }); - - test('untitled file', function () { - return service.backupResource(untitledFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => { - assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 1); - assert.equal(fs.existsSync(untitledBackupPath), true); - assert.equal(fs.readFileSync(untitledBackupPath), `${untitledFile.toString()}\ntest`); - }); - }); - - test('text file (ITextSnapshot)', function () { - const model = TextModel.createFromString('test'); - - return service.backupResource(fooFile, model.createSnapshot()).then(() => { - assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 1); - assert.equal(fs.existsSync(fooBackupPath), true); - assert.equal(fs.readFileSync(fooBackupPath), `${fooFile.toString()}\ntest`); - model.dispose(); - }); - }); - - test('untitled file (ITextSnapshot)', function () { - const model = TextModel.createFromString('test'); - - return service.backupResource(untitledFile, model.createSnapshot()).then(() => { - assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 1); - assert.equal(fs.existsSync(untitledBackupPath), true); - assert.equal(fs.readFileSync(untitledBackupPath), `${untitledFile.toString()}\ntest`); - model.dispose(); - }); - }); - - test('text file (large file, ITextSnapshot)', function () { - const largeString = (new Array(10 * 1024)).join('Large String\n'); - const model = TextModel.createFromString(largeString); - - return service.backupResource(fooFile, model.createSnapshot()).then(() => { - assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 1); - assert.equal(fs.existsSync(fooBackupPath), true); - assert.equal(fs.readFileSync(fooBackupPath), `${fooFile.toString()}\n${largeString}`); - model.dispose(); - }); - }); - - test('untitled file (large file, ITextSnapshot)', function () { - const largeString = (new Array(10 * 1024)).join('Large String\n'); - const model = TextModel.createFromString(largeString); - - return service.backupResource(untitledFile, model.createSnapshot()).then(() => { - assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 1); - assert.equal(fs.existsSync(untitledBackupPath), true); - assert.equal(fs.readFileSync(untitledBackupPath), `${untitledFile.toString()}\n${largeString}`); - model.dispose(); - }); - }); - }); - - suite('discardResourceBackup', () => { - test('text file', function () { - return service.backupResource(fooFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => { - assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 1); - return service.discardResourceBackup(fooFile).then(() => { - assert.equal(fs.existsSync(fooBackupPath), false); - assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 0); - }); - }); - }); - - test('untitled file', function () { - return service.backupResource(untitledFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => { - assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 1); - return service.discardResourceBackup(untitledFile).then(() => { - assert.equal(fs.existsSync(untitledBackupPath), false); - assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 0); - }); - }); - }); - }); - - suite('discardAllWorkspaceBackups', () => { - test('text file', function () { - return service.backupResource(fooFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => { - assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 1); - return service.backupResource(barFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => { - assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 2); - return service.discardAllWorkspaceBackups().then(() => { - assert.equal(fs.existsSync(fooBackupPath), false); - assert.equal(fs.existsSync(barBackupPath), false); - assert.equal(fs.existsSync(path.join(workspaceBackupPath, 'file')), false); - }); - }); - }); - }); - - test('untitled file', function () { - return service.backupResource(untitledFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => { - assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 1); - return service.discardAllWorkspaceBackups().then(() => { - assert.equal(fs.existsSync(untitledBackupPath), false); - assert.equal(fs.existsSync(path.join(workspaceBackupPath, 'untitled')), false); - }); - }); - }); - - test('should disable further backups', function () { - return service.discardAllWorkspaceBackups().then(() => { - return service.backupResource(untitledFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => { - assert.equal(fs.existsSync(workspaceBackupPath), false); - }); - }); - }); - }); - - suite('getWorkspaceFileBackups', () => { - test('("file") - text file', () => { - return service.backupResource(fooFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => { - return service.getWorkspaceFileBackups().then(textFiles => { - assert.deepEqual(textFiles.map(f => f.fsPath), [fooFile.fsPath]); - return service.backupResource(barFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => { - return service.getWorkspaceFileBackups().then(textFiles => { - assert.deepEqual(textFiles.map(f => f.fsPath), [fooFile.fsPath, barFile.fsPath]); - }); - }); - }); - }); - }); - - test('("file") - untitled file', () => { - return service.backupResource(untitledFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => { - return service.getWorkspaceFileBackups().then(textFiles => { - assert.deepEqual(textFiles.map(f => f.fsPath), [untitledFile.fsPath]); - }); - }); - }); - - test('("untitled") - untitled file', () => { - return service.backupResource(untitledFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => { - return service.getWorkspaceFileBackups().then(textFiles => { - assert.deepEqual(textFiles.map(f => f.fsPath), ['Untitled-1']); - }); - }); - }); - }); - - test('resolveBackupContent', () => { - test('should restore the original contents (untitled file)', () => { - const contents = 'test\nand more stuff'; - service.backupResource(untitledFile, createTextBufferFactory(contents).create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => { - service.resolveBackupContent(service.toBackupResource(untitledFile)).then(factory => { - assert.equal(contents, snapshotToString(factory!.create(platform.isWindows ? DefaultEndOfLine.CRLF : DefaultEndOfLine.LF).createSnapshot(true))); - }); - }); - }); - - test('should restore the original contents (text file)', () => { - const contents = [ - 'Lorem ipsum ', - 'dolor öäü sit amet ', - 'consectetur ', - 'adipiscing ßß elit', - ].join(''); - - service.backupResource(fooFile, createTextBufferFactory(contents).create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => { - service.resolveBackupContent(service.toBackupResource(untitledFile)).then(factory => { - assert.equal(contents, snapshotToString(factory!.create(platform.isWindows ? DefaultEndOfLine.CRLF : DefaultEndOfLine.LF).createSnapshot(true))); - }); - }); - }); - }); -}); - -suite('BackupFilesModel', () => { - test('simple', () => { - const model = new BackupFilesModel(); - - const resource1 = Uri.file('test.html'); - - assert.equal(model.has(resource1), false); - - model.add(resource1); - - assert.equal(model.has(resource1), true); - assert.equal(model.has(resource1, 0), true); - assert.equal(model.has(resource1, 1), false); - - model.remove(resource1); - - assert.equal(model.has(resource1), false); - - model.add(resource1); - - assert.equal(model.has(resource1), true); - assert.equal(model.has(resource1, 0), true); - assert.equal(model.has(resource1, 1), false); - - model.clear(); - - assert.equal(model.has(resource1), false); - - model.add(resource1, 1); - - assert.equal(model.has(resource1), true); - assert.equal(model.has(resource1, 0), false); - assert.equal(model.has(resource1, 1), true); - - const resource2 = Uri.file('test1.html'); - const resource3 = Uri.file('test2.html'); - const resource4 = Uri.file('test3.html'); - - model.add(resource2); - model.add(resource3); - model.add(resource4); - - assert.equal(model.has(resource1), true); - assert.equal(model.has(resource2), true); - assert.equal(model.has(resource3), true); - assert.equal(model.has(resource4), true); - }); - - test('resolve', () => { - return pfs.mkdirp(path.dirname(fooBackupPath)).then(() => { - fs.writeFileSync(fooBackupPath, 'foo'); - - const model = new BackupFilesModel(); - - return model.resolve(workspaceBackupPath).then(model => { - assert.equal(model.has(Uri.file(fooBackupPath)), true); - }); - }); - }); - - test('get', () => { - const model = new BackupFilesModel(); - - assert.deepEqual(model.get(), []); - - const file1 = Uri.file('/root/file/foo.html'); - const file2 = Uri.file('/root/file/bar.html'); - const untitled = Uri.file('/root/untitled/bar.html'); - - model.add(file1); - model.add(file2); - model.add(untitled); - - assert.deepEqual(model.get().map(f => f.fsPath), [file1.fsPath, file2.fsPath, untitled.fsPath]); - }); -}); diff --git a/src/vs/workbench/services/backup/test/node/backupFileService.test.ts b/src/vs/workbench/services/backup/test/node/backupFileService.test.ts new file mode 100644 index 000000000..990d688b3 --- /dev/null +++ b/src/vs/workbench/services/backup/test/node/backupFileService.test.ts @@ -0,0 +1,599 @@ +/*--------------------------------------------------------------------------------------------- + * 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 platform from 'vs/base/common/platform'; +import * as crypto from 'crypto'; +import * as os from 'os'; +import * as fs from 'fs'; +import * as path from 'vs/base/common/path'; +import * as pfs from 'vs/base/node/pfs'; +import { URI } from 'vs/base/common/uri'; +import { BackupFilesModel } from 'vs/workbench/services/backup/common/backupFileService'; +import { TextModel, createTextBufferFactory } from 'vs/editor/common/model/textModel'; +import { getRandomTestPath } from 'vs/base/test/node/testUtils'; +import { DefaultEndOfLine } from 'vs/editor/common/model'; +import { Schemas } from 'vs/base/common/network'; +import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; +import { FileService } from 'vs/platform/files/common/fileService'; +import { NullLogService } from 'vs/platform/log/common/log'; +import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; +import { WorkbenchEnvironmentService } from 'vs/workbench/services/environment/node/environmentService'; +import { parseArgs } from 'vs/platform/environment/node/argv'; +import { snapshotToString } from 'vs/workbench/services/textfile/common/textfiles'; +import { IFileService } from 'vs/platform/files/common/files'; +import { hashPath, BackupFileService } from 'vs/workbench/services/backup/node/backupFileService'; +import { BACKUPS } from 'vs/platform/environment/common/environment'; +import { FileUserDataProvider } from 'vs/workbench/services/userData/common/fileUserDataProvider'; + +const userdataDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'backupfileservice'); +const appSettingsHome = path.join(userdataDir, 'User'); +const backupHome = path.join(userdataDir, 'Backups'); +const workspacesJsonPath = path.join(backupHome, 'workspaces.json'); + +const workspaceResource = URI.file(platform.isWindows ? 'c:\\workspace' : '/workspace'); +const workspaceBackupPath = path.join(backupHome, hashPath(workspaceResource)); +const fooFile = URI.file(platform.isWindows ? 'c:\\Foo' : '/Foo'); +const customFile = URI.parse('customScheme://some/path'); +const customFileWithFragment = URI.parse('customScheme2://some/path#fragment'); +const barFile = URI.file(platform.isWindows ? 'c:\\Bar' : '/Bar'); +const fooBarFile = URI.file(platform.isWindows ? 'c:\\Foo Bar' : '/Foo Bar'); +const untitledFile = URI.from({ scheme: Schemas.untitled, path: 'Untitled-1' }); +const fooBackupPath = path.join(workspaceBackupPath, 'file', hashPath(fooFile)); +const barBackupPath = path.join(workspaceBackupPath, 'file', hashPath(barFile)); +const untitledBackupPath = path.join(workspaceBackupPath, 'untitled', hashPath(untitledFile)); + +class TestBackupEnvironmentService extends WorkbenchEnvironmentService { + + constructor(backupPath: string) { + super({ ...parseArgs(process.argv), ...{ backupPath, 'user-data-dir': userdataDir } } as IWindowConfiguration, process.execPath); + } + +} + +class TestBackupFileService extends BackupFileService { + + readonly fileService: IFileService; + + constructor(workspace: URI, backupHome: string, workspacesJsonPath: string) { + const environmentService = new TestBackupEnvironmentService(workspaceBackupPath); + const fileService = new FileService(new NullLogService()); + const diskFileSystemProvider = new DiskFileSystemProvider(new NullLogService()); + fileService.registerProvider(Schemas.file, diskFileSystemProvider); + fileService.registerProvider(Schemas.userData, new FileUserDataProvider(environmentService.appSettingsHome, environmentService.backupHome, diskFileSystemProvider, environmentService)); + + super(environmentService, fileService); + + this.fileService = fileService; + } + + toBackupResource(resource: URI): URI { + return super.toBackupResource(resource); + } +} + +suite('BackupFileService', () => { + let service: TestBackupFileService; + + setup(async () => { + service = new TestBackupFileService(workspaceResource, backupHome, workspacesJsonPath); + + // Delete any existing backups completely and then re-create it. + await pfs.rimraf(backupHome, pfs.RimRafMode.MOVE); + await pfs.mkdirp(backupHome); + + return pfs.writeFile(workspacesJsonPath, ''); + }); + + teardown(() => { + return pfs.rimraf(backupHome, pfs.RimRafMode.MOVE); + }); + + suite('hashPath', () => { + test('should correctly hash the path for untitled scheme URIs', () => { + const uri = URI.from({ + scheme: 'untitled', + path: 'Untitled-1' + }); + const actual = hashPath(uri); + // If these hashes change people will lose their backed up files! + assert.equal(actual, '13264068d108c6901b3592ea654fcd57'); + assert.equal(actual, crypto.createHash('md5').update(uri.fsPath).digest('hex')); + }); + + test('should correctly hash the path for file scheme URIs', () => { + const uri = URI.file('/foo'); + const actual = hashPath(uri); + // If these hashes change people will lose their backed up files! + if (platform.isWindows) { + assert.equal(actual, 'dec1a583f52468a020bd120c3f01d812'); + } else { + assert.equal(actual, '1effb2475fcfba4f9e8b8a1dbc8f3caf'); + } + assert.equal(actual, crypto.createHash('md5').update(uri.fsPath).digest('hex')); + }); + }); + + suite('getBackupResource', () => { + test('should get the correct backup path for text files', () => { + // Format should be: /// + const backupResource = fooFile; + const workspaceHash = hashPath(workspaceResource); + const filePathHash = hashPath(backupResource); + const expectedPath = URI.file(path.join(appSettingsHome, BACKUPS, workspaceHash, Schemas.file, filePathHash)).with({ scheme: Schemas.userData }).toString(); + assert.equal(service.toBackupResource(backupResource).toString(), expectedPath); + }); + + test('should get the correct backup path for untitled files', () => { + // Format should be: /// + const backupResource = URI.from({ scheme: Schemas.untitled, path: 'Untitled-1' }); + const workspaceHash = hashPath(workspaceResource); + const filePathHash = hashPath(backupResource); + const expectedPath = URI.file(path.join(appSettingsHome, BACKUPS, workspaceHash, Schemas.untitled, filePathHash)).with({ scheme: Schemas.userData }).toString(); + assert.equal(service.toBackupResource(backupResource).toString(), expectedPath); + }); + }); + + suite('loadBackupResource', () => { + test('should return whether a backup resource exists', async () => { + await pfs.mkdirp(path.dirname(fooBackupPath)); + fs.writeFileSync(fooBackupPath, 'foo'); + service = new TestBackupFileService(workspaceResource, backupHome, workspacesJsonPath); + const resource = await service.loadBackupResource(fooFile); + assert.ok(resource); + assert.equal(path.basename(resource!.fsPath), path.basename(fooBackupPath)); + const hasBackups = await service.hasBackups(); + assert.ok(hasBackups); + }); + }); + + suite('backupResource', () => { + test('text file', async () => { + await service.backupResource(fooFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)); + assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 1); + assert.equal(fs.existsSync(fooBackupPath), true); + assert.equal(fs.readFileSync(fooBackupPath), `${fooFile.toString()}\ntest`); + assert.ok(service.hasBackupSync(fooFile)); + }); + + test('text file (with version)', async () => { + await service.backupResource(fooFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false), 666); + assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 1); + assert.equal(fs.existsSync(fooBackupPath), true); + assert.equal(fs.readFileSync(fooBackupPath), `${fooFile.toString()}\ntest`); + assert.ok(!service.hasBackupSync(fooFile, 555)); + assert.ok(service.hasBackupSync(fooFile, 666)); + }); + + test('text file (with meta)', async () => { + await service.backupResource(fooFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false), undefined, { etag: '678', orphaned: true }); + assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 1); + assert.equal(fs.existsSync(fooBackupPath), true); + assert.equal(fs.readFileSync(fooBackupPath).toString(), `${fooFile.toString()} {"etag":"678","orphaned":true}\ntest`); + assert.ok(service.hasBackupSync(fooFile)); + }); + + test('untitled file', async () => { + await service.backupResource(untitledFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)); + assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 1); + assert.equal(fs.existsSync(untitledBackupPath), true); + assert.equal(fs.readFileSync(untitledBackupPath), `${untitledFile.toString()}\ntest`); + assert.ok(service.hasBackupSync(untitledFile)); + }); + + test('text file (ITextSnapshot)', async () => { + const model = TextModel.createFromString('test'); + + await service.backupResource(fooFile, model.createSnapshot()); + assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 1); + assert.equal(fs.existsSync(fooBackupPath), true); + assert.equal(fs.readFileSync(fooBackupPath), `${fooFile.toString()}\ntest`); + assert.ok(service.hasBackupSync(fooFile)); + + model.dispose(); + }); + + test('untitled file (ITextSnapshot)', async () => { + const model = TextModel.createFromString('test'); + + await service.backupResource(untitledFile, model.createSnapshot()); + assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 1); + assert.equal(fs.existsSync(untitledBackupPath), true); + assert.equal(fs.readFileSync(untitledBackupPath), `${untitledFile.toString()}\ntest`); + + model.dispose(); + }); + + test('text file (large file, ITextSnapshot)', async () => { + const largeString = (new Array(10 * 1024)).join('Large String\n'); + const model = TextModel.createFromString(largeString); + + await service.backupResource(fooFile, model.createSnapshot()); + assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 1); + assert.equal(fs.existsSync(fooBackupPath), true); + assert.equal(fs.readFileSync(fooBackupPath), `${fooFile.toString()}\n${largeString}`); + assert.ok(service.hasBackupSync(fooFile)); + + model.dispose(); + }); + + test('untitled file (large file, ITextSnapshot)', async () => { + const largeString = (new Array(10 * 1024)).join('Large String\n'); + const model = TextModel.createFromString(largeString); + + await service.backupResource(untitledFile, model.createSnapshot()); + assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 1); + assert.equal(fs.existsSync(untitledBackupPath), true); + assert.equal(fs.readFileSync(untitledBackupPath), `${untitledFile.toString()}\n${largeString}`); + assert.ok(service.hasBackupSync(untitledFile)); + + model.dispose(); + }); + }); + + suite('discardResourceBackup', () => { + test('text file', async () => { + await service.backupResource(fooFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)); + assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 1); + assert.ok(service.hasBackupSync(fooFile)); + + await service.discardResourceBackup(fooFile); + assert.equal(fs.existsSync(fooBackupPath), false); + assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 0); + assert.ok(!service.hasBackupSync(fooFile)); + }); + + test('untitled file', async () => { + await service.backupResource(untitledFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)); + assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 1); + await service.discardResourceBackup(untitledFile); + assert.equal(fs.existsSync(untitledBackupPath), false); + assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 0); + }); + }); + + suite('discardAllWorkspaceBackups', () => { + test('text file', async () => { + await service.backupResource(fooFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)); + assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 1); + await service.backupResource(barFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)); + assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 2); + await service.discardAllWorkspaceBackups(); + assert.equal(fs.existsSync(fooBackupPath), false); + assert.equal(fs.existsSync(barBackupPath), false); + assert.equal(fs.existsSync(path.join(workspaceBackupPath, 'file')), false); + }); + + test('untitled file', async () => { + await service.backupResource(untitledFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)); + assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 1); + await service.discardAllWorkspaceBackups(); + assert.equal(fs.existsSync(untitledBackupPath), false); + assert.equal(fs.existsSync(path.join(workspaceBackupPath, 'untitled')), false); + }); + + test('should disable further backups', async () => { + await service.discardAllWorkspaceBackups(); + await service.backupResource(untitledFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)); + assert.equal(fs.existsSync(workspaceBackupPath), false); + }); + }); + + suite('getWorkspaceFileBackups', () => { + test('("file") - text file', async () => { + await service.backupResource(fooFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)); + const textFiles = await service.getWorkspaceFileBackups(); + assert.deepEqual(textFiles.map(f => f.fsPath), [fooFile.fsPath]); + await service.backupResource(barFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)); + const textFiles_1 = await service.getWorkspaceFileBackups(); + assert.deepEqual(textFiles_1.map(f => f.fsPath), [fooFile.fsPath, barFile.fsPath]); + }); + + test('("file") - untitled file', async () => { + await service.backupResource(untitledFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)); + const textFiles = await service.getWorkspaceFileBackups(); + assert.deepEqual(textFiles.map(f => f.fsPath), [untitledFile.fsPath]); + }); + + test('("untitled") - untitled file', async () => { + await service.backupResource(untitledFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)); + const textFiles = await service.getWorkspaceFileBackups(); + assert.deepEqual(textFiles.map(f => f.fsPath), ['Untitled-1']); + }); + }); + + suite('resolveBackupContent', () => { + + interface IBackupTestMetaData { + mtime?: number; + size?: number; + etag?: string; + orphaned?: boolean; + } + + test('should restore the original contents (untitled file)', async () => { + const contents = 'test\nand more stuff'; + + await testResolveBackup(untitledFile, contents); + }); + + test('should restore the original contents (untitled file with metadata)', async () => { + const contents = 'test\nand more stuff'; + + const meta = { + etag: 'the Etag', + size: 666, + mtime: Date.now(), + orphaned: true + }; + + await testResolveBackup(untitledFile, contents, meta); + }); + + test('should restore the original contents (text file)', async () => { + const contents = [ + 'Lorem ipsum ', + 'dolor öäü sit amet ', + 'consectetur ', + 'adipiscing ßß elit' + ].join(''); + + await testResolveBackup(fooFile, contents); + }); + + test('should restore the original contents (text file - custom scheme)', async () => { + const contents = [ + 'Lorem ipsum ', + 'dolor öäü sit amet ', + 'consectetur ', + 'adipiscing ßß elit' + ].join(''); + + await testResolveBackup(customFile, contents); + }); + + test('should restore the original contents (text file with metadata)', async () => { + const contents = [ + 'Lorem ipsum ', + 'dolor öäü sit amet ', + 'adipiscing ßß elit', + 'consectetur ' + ].join(''); + + const meta = { + etag: 'theEtag', + size: 888, + mtime: Date.now(), + orphaned: false + }; + + await testResolveBackup(fooFile, contents, meta); + }); + + test('should restore the original contents (text file with metadata changed once)', async () => { + const contents = [ + 'Lorem ipsum ', + 'dolor öäü sit amet ', + 'adipiscing ßß elit', + 'consectetur ' + ].join(''); + + const meta = { + etag: 'theEtag', + size: 888, + mtime: Date.now(), + orphaned: false + }; + + await testResolveBackup(fooFile, contents, meta); + + // Change meta and test again + meta.size = 999; + await testResolveBackup(fooFile, contents, meta); + }); + + test('should restore the original contents (text file with broken metadata)', async () => { + const contents = [ + 'Lorem ipsum ', + 'dolor öäü sit amet ', + 'adipiscing ßß elit', + 'consectetur ' + ].join(''); + + const meta = { + etag: 'theEtag', + size: 888, + mtime: Date.now(), + orphaned: false + }; + + await service.backupResource(fooFile, createTextBufferFactory(contents).create(DefaultEndOfLine.LF).createSnapshot(false), 1, meta); + + assert.ok(await service.loadBackupResource(fooFile)); + + const fileContents = fs.readFileSync(fooBackupPath).toString(); + assert.equal(fileContents.indexOf(fooFile.toString()), 0); + + const metaIndex = fileContents.indexOf('{'); + const newFileContents = fileContents.substring(0, metaIndex) + '{{' + fileContents.substr(metaIndex); + fs.writeFileSync(fooBackupPath, newFileContents); + + const backup = await service.resolveBackupContent(service.toBackupResource(fooFile)); + assert.equal(contents, snapshotToString(backup.value.create(platform.isWindows ? DefaultEndOfLine.CRLF : DefaultEndOfLine.LF).createSnapshot(true))); + assert.ok(!backup.meta); + }); + + test('should restore the original contents (text file with metadata and fragment URI)', async () => { + const contents = [ + 'Lorem ipsum ', + 'dolor öäü sit amet ', + 'adipiscing ßß elit', + 'consectetur ' + ].join(''); + + const meta = { + etag: 'theEtag', + size: 888, + mtime: Date.now(), + orphaned: false + }; + + await testResolveBackup(customFileWithFragment, contents, meta); + }); + + test('should restore the original contents (text file with space in name with metadata)', async () => { + const contents = [ + 'Lorem ipsum ', + 'dolor öäü sit amet ', + 'adipiscing ßß elit', + 'consectetur ' + ].join(''); + + const meta = { + etag: 'theEtag', + size: 888, + mtime: Date.now(), + orphaned: false + }; + + await testResolveBackup(fooBarFile, contents, meta); + }); + + test('should restore the original contents (text file with too large metadata to persist)', async () => { + const contents = [ + 'Lorem ipsum ', + 'dolor öäü sit amet ', + 'adipiscing ßß elit', + 'consectetur ' + ].join(''); + + const meta = { + etag: (new Array(100 * 1024)).join('Large String'), + size: 888, + mtime: Date.now(), + orphaned: false + }; + + await testResolveBackup(fooBarFile, contents, meta, null); + }); + + async function testResolveBackup(resource: URI, contents: string, meta?: IBackupTestMetaData, expectedMeta?: IBackupTestMetaData | null) { + if (typeof expectedMeta === 'undefined') { + expectedMeta = meta; + } + + await service.backupResource(resource, createTextBufferFactory(contents).create(DefaultEndOfLine.LF).createSnapshot(false), 1, meta); + + assert.ok(await service.loadBackupResource(resource)); + + const backup = await service.resolveBackupContent(service.toBackupResource(resource)); + assert.equal(contents, snapshotToString(backup.value.create(platform.isWindows ? DefaultEndOfLine.CRLF : DefaultEndOfLine.LF).createSnapshot(true))); + + if (expectedMeta) { + assert.equal(backup.meta!.etag, expectedMeta.etag); + assert.equal(backup.meta!.size, expectedMeta.size); + assert.equal(backup.meta!.mtime, expectedMeta.mtime); + assert.equal(backup.meta!.orphaned, expectedMeta.orphaned); + } else { + assert.ok(!backup.meta); + } + } + }); +}); + +suite('BackupFilesModel', () => { + + let service: TestBackupFileService; + + setup(async () => { + service = new TestBackupFileService(workspaceResource, backupHome, workspacesJsonPath); + + // Delete any existing backups completely and then re-create it. + await pfs.rimraf(backupHome, pfs.RimRafMode.MOVE); + await pfs.mkdirp(backupHome); + + return pfs.writeFile(workspacesJsonPath, ''); + }); + + teardown(() => { + return pfs.rimraf(backupHome, pfs.RimRafMode.MOVE); + }); + + test('simple', () => { + const model = new BackupFilesModel(service.fileService); + + const resource1 = URI.file('test.html'); + + assert.equal(model.has(resource1), false); + + model.add(resource1); + + assert.equal(model.has(resource1), true); + assert.equal(model.has(resource1, 0), true); + assert.equal(model.has(resource1, 1), false); + assert.equal(model.has(resource1, 1, { foo: 'bar' }), false); + + model.remove(resource1); + + assert.equal(model.has(resource1), false); + + model.add(resource1); + + assert.equal(model.has(resource1), true); + assert.equal(model.has(resource1, 0), true); + assert.equal(model.has(resource1, 1), false); + + model.clear(); + + assert.equal(model.has(resource1), false); + + model.add(resource1, 1); + + assert.equal(model.has(resource1), true); + assert.equal(model.has(resource1, 0), false); + assert.equal(model.has(resource1, 1), true); + + const resource2 = URI.file('test1.html'); + const resource3 = URI.file('test2.html'); + const resource4 = URI.file('test3.html'); + + model.add(resource2); + model.add(resource3); + model.add(resource4, undefined, { foo: 'bar' }); + + assert.equal(model.has(resource1), true); + assert.equal(model.has(resource2), true); + assert.equal(model.has(resource3), true); + + assert.equal(model.has(resource4), true); + assert.equal(model.has(resource4, undefined, { foo: 'bar' }), true); + assert.equal(model.has(resource4, undefined, { bar: 'foo' }), false); + }); + + test('resolve', async () => { + await pfs.mkdirp(path.dirname(fooBackupPath)); + fs.writeFileSync(fooBackupPath, 'foo'); + const model = new BackupFilesModel(service.fileService); + + const resolvedModel = await model.resolve(URI.file(workspaceBackupPath)); + assert.equal(resolvedModel.has(URI.file(fooBackupPath)), true); + }); + + test('get', () => { + const model = new BackupFilesModel(service.fileService); + + assert.deepEqual(model.get(), []); + + const file1 = URI.file('/root/file/foo.html'); + const file2 = URI.file('/root/file/bar.html'); + const untitled = URI.file('/root/untitled/bar.html'); + + model.add(file1); + model.add(file2); + model.add(untitled); + + assert.deepEqual(model.get().map(f => f.fsPath), [file1.fsPath, file2.fsPath, untitled.fsPath]); + }); +}); diff --git a/src/vs/workbench/services/broadcast/common/broadcast.ts b/src/vs/workbench/services/broadcast/common/broadcast.ts deleted file mode 100644 index fc9e13031..000000000 --- a/src/vs/workbench/services/broadcast/common/broadcast.ts +++ /dev/null @@ -1,30 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { Event } from 'vs/base/common/event'; - -export const IBroadcastService = createDecorator('broadcastService'); - -export interface IBroadcast { - channel: string; - payload: any; -} - -export interface IBroadcastService { - _serviceBrand: any; - - onBroadcast: Event; - - broadcast(b: IBroadcast): void; -} - -export class NullBroadcastService implements IBroadcastService { - _serviceBrand: any; - onBroadcast: Event = Event.None; - broadcast(_b: IBroadcast): void { - - } -} diff --git a/src/vs/workbench/services/broadcast/electron-browser/broadcastService.ts b/src/vs/workbench/services/broadcast/electron-browser/broadcastService.ts deleted file mode 100644 index c4a5f3d79..000000000 --- a/src/vs/workbench/services/broadcast/electron-browser/broadcastService.ts +++ /dev/null @@ -1,51 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { Event, Emitter } from 'vs/base/common/event'; -import { ipcRenderer as ipc } from 'electron'; -import { ILogService } from 'vs/platform/log/common/log'; -import { Disposable } from 'vs/base/common/lifecycle'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IWindowService } from 'vs/platform/windows/common/windows'; -import { IBroadcastService, IBroadcast } from 'vs/workbench/services/broadcast/common/broadcast'; - -class BroadcastService extends Disposable implements IBroadcastService { - _serviceBrand: any; - - private readonly _onBroadcast: Emitter = this._register(new Emitter()); - get onBroadcast(): Event { return this._onBroadcast.event; } - - private windowId: number; - - constructor( - @IWindowService readonly windowService: IWindowService, - @ILogService private readonly logService: ILogService - ) { - super(); - - this.windowId = windowService.windowId; - - this.registerListeners(); - } - - private registerListeners(): void { - ipc.on('vscode:broadcast', (event: unknown, b: IBroadcast) => { - this.logService.trace(`Received broadcast from main in window ${this.windowId}: `, b); - - this._onBroadcast.fire(b); - }); - } - - broadcast(b: IBroadcast): void { - this.logService.trace(`Sending broadcast to main from window ${this.windowId}: `, b); - - ipc.send('vscode:broadcast', this.windowId, { - channel: b.channel, - payload: b.payload - }); - } -} - -registerSingleton(IBroadcastService, BroadcastService, true); diff --git a/src/vs/workbench/services/bulkEdit/browser/bulkEditService.ts b/src/vs/workbench/services/bulkEdit/browser/bulkEditService.ts index 079e00df8..f698782a6 100644 --- a/src/vs/workbench/services/bulkEdit/browser/bulkEditService.ts +++ b/src/vs/workbench/services/bulkEdit/browser/bulkEditService.ts @@ -18,7 +18,7 @@ import { localize } from 'vs/nls'; import { IFileService, FileSystemProviderCapabilities } from 'vs/platform/files/common/files'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ILogService } from 'vs/platform/log/common/log'; -import { emptyProgressRunner, IProgress, IProgressRunner } from 'vs/platform/progress/common/progress'; +import { IProgress, IProgressStep, emptyProgress } from 'vs/platform/progress/common/progress'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { ILabelService } from 'vs/platform/label/common/label'; @@ -231,11 +231,11 @@ export class BulkEdit { private _edits: Edit[] = []; private _editor: ICodeEditor | undefined; - private _progress?: IProgressRunner; + private _progress: IProgress; constructor( editor: ICodeEditor | undefined, - progress: IProgressRunner | undefined, + progress: IProgress | undefined, @ILogService private readonly _logService: ILogService, @ITextModelService private readonly _textModelService: ITextModelService, @IFileService private readonly _fileService: IFileService, @@ -244,7 +244,7 @@ export class BulkEdit { @IConfigurationService private readonly _configurationService: IConfigurationService ) { this._editor = editor; - this._progress = progress || emptyProgressRunner; + this._progress = progress || emptyProgress; } add(edits: Edit[] | Edit): void { @@ -294,10 +294,9 @@ export class BulkEdit { // define total work and progress callback // for child operations - if (this._progress) { - this._progress.total(total); - } - let progress: IProgress = { report: _ => this._progress && this._progress.worked(1) }; + this._progress.report({ total }); + + let progress: IProgress = { report: _ => this._progress.report({ increment: 1 }) }; // do it. for (const group of groups) { diff --git a/src/vs/workbench/services/commands/common/commandService.ts b/src/vs/workbench/services/commands/common/commandService.ts index ffb7d1ebd..f1826cd03 100644 --- a/src/vs/workbench/services/commands/common/commandService.ts +++ b/src/vs/workbench/services/commands/common/commandService.ts @@ -22,6 +22,9 @@ export class CommandService extends Disposable implements ICommandService { private readonly _onWillExecuteCommand: Emitter = this._register(new Emitter()); public readonly onWillExecuteCommand: Event = this._onWillExecuteCommand.event; + private readonly _onDidExecuteCommand: Emitter = new Emitter(); + public readonly onDidExecuteCommand: Event = this._onDidExecuteCommand.event; + constructor( @IInstantiationService private readonly _instantiationService: IInstantiationService, @IExtensionService private readonly _extensionService: IExtensionService, @@ -77,8 +80,9 @@ export class CommandService extends Disposable implements ICommandService { return Promise.reject(new Error(`command '${id}' not found`)); } try { - this._onWillExecuteCommand.fire({ commandId: id }); + this._onWillExecuteCommand.fire({ commandId: id, args }); const result = this._instantiationService.invokeFunction.apply(this._instantiationService, [command.handler, ...args]); + this._onDidExecuteCommand.fire({ commandId: id, args }); return Promise.resolve(result); } catch (err) { return Promise.reject(err); diff --git a/src/vs/workbench/services/commands/test/common/commandService.test.ts b/src/vs/workbench/services/commands/test/common/commandService.test.ts index e32440778..1500f8566 100644 --- a/src/vs/workbench/services/commands/test/common/commandService.test.ts +++ b/src/vs/workbench/services/commands/test/common/commandService.test.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { CommandService } from 'vs/workbench/services/commands/common/commandService'; import { NullExtensionService } from 'vs/workbench/services/extensions/common/extensions'; @@ -103,7 +103,7 @@ suite('CommandService', function () { test('Stop waiting for * extensions to activate when trigger is satisfied #62457', function () { let callCounter = 0; - let dispoables: IDisposable[] = []; + const dispoables = new DisposableStore(); let events: string[] = []; let service = new CommandService(new InstantiationService(), new class extends NullExtensionService { @@ -118,7 +118,7 @@ suite('CommandService', function () { let reg = CommandsRegistry.registerCommand(event.substr('onCommand:'.length), () => { callCounter += 1; }); - dispoables.push(reg); + dispoables.add(reg); resolve(); }, 0); }); @@ -131,14 +131,15 @@ suite('CommandService', function () { return service.executeCommand('farboo').then(() => { assert.equal(callCounter, 1); assert.deepEqual(events.sort(), ['*', 'onCommand:farboo'].sort()); - dispose(dispoables); + }).finally(() => { + dispoables.dispose(); }); }); test('issue #71471: wait for onCommand activation even if a command is registered', () => { let expectedOrder: string[] = ['registering command', 'resolving activation event', 'executing command']; let actualOrder: string[] = []; - let disposables: IDisposable[] = []; + const disposables = new DisposableStore(); let service = new CommandService(new InstantiationService(), new class extends NullExtensionService { activateByEvent(event: string): Promise { @@ -153,7 +154,7 @@ suite('CommandService', function () { let reg = CommandsRegistry.registerCommand(event.substr('onCommand:'.length), () => { actualOrder.push('executing command'); }); - disposables.push(reg); + disposables.add(reg); setTimeout(() => { // Resolve the activation event after some more time @@ -170,7 +171,8 @@ suite('CommandService', function () { return service.executeCommand('farboo2').then(() => { assert.deepEqual(actualOrder, expectedOrder); - dispose(disposables); + }).finally(() => { + disposables.dispose(); }); }); }); diff --git a/src/vs/workbench/services/configuration/browser/configuration.ts b/src/vs/workbench/services/configuration/browser/configuration.ts index 1c107e7d7..fe76b1061 100644 --- a/src/vs/workbench/services/configuration/browser/configuration.ts +++ b/src/vs/workbench/services/configuration/browser/configuration.ts @@ -9,10 +9,10 @@ import { Event, Emitter } from 'vs/base/common/event'; import * as errors from 'vs/base/common/errors'; import { Disposable, IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; import { RunOnceScheduler } from 'vs/base/common/async'; -import { FileChangeType, FileChangesEvent } from 'vs/platform/files/common/files'; +import { FileChangeType, FileChangesEvent, IFileService } from 'vs/platform/files/common/files'; import { ConfigurationModel, ConfigurationModelParser } from 'vs/platform/configuration/common/configurationModels'; import { WorkspaceConfigurationModelParser, StandaloneConfigurationModelParser } from 'vs/workbench/services/configuration/common/configurationModels'; -import { FOLDER_SETTINGS_PATH, TASKS_CONFIGURATION_KEY, FOLDER_SETTINGS_NAME, LAUNCH_CONFIGURATION_KEY, IConfigurationCache, ConfigurationKey, IConfigurationFileService, MACHINE_SCOPES, FOLDER_SCOPES, WORKSPACE_SCOPES } from 'vs/workbench/services/configuration/common/configuration'; +import { FOLDER_SETTINGS_PATH, TASKS_CONFIGURATION_KEY, FOLDER_SETTINGS_NAME, LAUNCH_CONFIGURATION_KEY, IConfigurationCache, ConfigurationKey, REMOTE_MACHINE_SCOPES, FOLDER_SCOPES, WORKSPACE_SCOPES } from 'vs/workbench/services/configuration/common/configuration'; import { IStoredWorkspaceFolder, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { JSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditingService'; import { WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; @@ -20,15 +20,69 @@ import { ConfigurationScope } from 'vs/platform/configuration/common/configurati import { extname, join } from 'vs/base/common/path'; import { equals } from 'vs/base/common/objects'; import { Schemas } from 'vs/base/common/network'; -import { IConfigurationModel, compare } from 'vs/platform/configuration/common/configuration'; -import { createSHA1 } from 'vs/base/browser/hash'; +import { IConfigurationModel } from 'vs/platform/configuration/common/configuration'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; +import { hash } from 'vs/base/common/hash'; + +function whenProviderRegistered(scheme: string, fileService: IFileService): Promise { + if (fileService.canHandleResource(URI.from({ scheme }))) { + return Promise.resolve(); + } + return new Promise((c, e) => { + const disposable = fileService.onDidChangeFileSystemProviderRegistrations(e => { + if (e.scheme === scheme && e.added) { + disposable.dispose(); + c(); + } + }); + }); +} + +export class UserConfiguration extends Disposable { + + private readonly parser: ConfigurationModelParser; + private readonly reloadConfigurationScheduler: RunOnceScheduler; + protected readonly _onDidChangeConfiguration: Emitter = this._register(new Emitter()); + readonly onDidChangeConfiguration: Event = this._onDidChangeConfiguration.event; + + constructor( + private readonly userSettingsResource: URI, + private readonly scopes: ConfigurationScope[] | undefined, + private readonly fileService: IFileService + ) { + super(); + + this.parser = new ConfigurationModelParser(this.userSettingsResource.toString(), this.scopes); + this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this.reload().then(configurationModel => this._onDidChangeConfiguration.fire(configurationModel)), 50)); + this._register(Event.filter(this.fileService.onFileChanges, e => e.contains(this.userSettingsResource))(() => this.reloadConfigurationScheduler.schedule())); + } + + async initialize(): Promise { + return this.reload(); + } + + async reload(): Promise { + try { + const content = await this.fileService.readFile(this.userSettingsResource); + this.parser.parseContent(content.value.toString() || '{}'); + return this.parser.configurationModel; + } catch (e) { + return new ConfigurationModel(); + } + } + + reprocess(): ConfigurationModel { + this.parser.parse(); + return this.parser.configurationModel; + } +} export class RemoteUserConfiguration extends Disposable { - private readonly _cachedConfiguration: CachedUserConfiguration; - private readonly _configurationFileService: IConfigurationFileService; - private _userConfiguration: UserConfiguration | CachedUserConfiguration; + private readonly _cachedConfiguration: CachedRemoteUserConfiguration; + private readonly _fileService: IFileService; + private _userConfiguration: FileServiceBasedRemoteUserConfiguration | CachedRemoteUserConfiguration; + private _userConfigurationInitializationPromise: Promise | null = null; private readonly _onDidChangeConfiguration: Emitter = this._register(new Emitter()); public readonly onDidChangeConfiguration: Event = this._onDidChangeConfiguration.event; @@ -36,17 +90,18 @@ export class RemoteUserConfiguration extends Disposable { constructor( remoteAuthority: string, configurationCache: IConfigurationCache, - configurationFileService: IConfigurationFileService, + fileService: IFileService, remoteAgentService: IRemoteAgentService ) { super(); - this._configurationFileService = configurationFileService; - this._userConfiguration = this._cachedConfiguration = new CachedUserConfiguration(remoteAuthority, configurationCache); + this._fileService = fileService; + this._userConfiguration = this._cachedConfiguration = new CachedRemoteUserConfiguration(remoteAuthority, configurationCache); remoteAgentService.getEnvironment().then(async environment => { if (environment) { - const userConfiguration = this._register(new UserConfiguration(environment.settingsPath, MACHINE_SCOPES, this._configurationFileService)); + const userConfiguration = this._register(new FileServiceBasedRemoteUserConfiguration(environment.settingsPath, REMOTE_MACHINE_SCOPES, this._fileService)); this._register(userConfiguration.onDidChangeConfiguration(configurationModel => this.onDidUserConfigurationChange(configurationModel))); - const configurationModel = await userConfiguration.initialize(); + this._userConfigurationInitializationPromise = userConfiguration.initialize(); + const configurationModel = await this._userConfigurationInitializationPromise; this._userConfiguration.dispose(); this._userConfiguration = userConfiguration; this.onDidUserConfigurationChange(configurationModel); @@ -54,8 +109,20 @@ export class RemoteUserConfiguration extends Disposable { }); } - initialize(): Promise { - return this._userConfiguration.initialize(); + async initialize(): Promise { + if (this._userConfiguration instanceof FileServiceBasedRemoteUserConfiguration) { + return this._userConfiguration.initialize(); + } + + // Initialize cached configuration + let configurationModel = await this._userConfiguration.initialize(); + if (this._userConfigurationInitializationPromise) { + // Use user configuration + configurationModel = await this._userConfigurationInitializationPromise; + this._userConfigurationInitializationPromise = null; + } + + return configurationModel; } reload(): Promise { @@ -76,7 +143,7 @@ export class RemoteUserConfiguration extends Disposable { } } -export class UserConfiguration extends Disposable { +class FileServiceBasedRemoteUserConfiguration extends Disposable { private readonly parser: ConfigurationModelParser; private readonly reloadConfigurationScheduler: RunOnceScheduler; @@ -89,12 +156,12 @@ export class UserConfiguration extends Disposable { constructor( private readonly configurationResource: URI, private readonly scopes: ConfigurationScope[] | undefined, - private readonly configurationFileService: IConfigurationFileService + private readonly fileService: IFileService ) { super(); this.parser = new ConfigurationModelParser(this.configurationResource.toString(), this.scopes); - this._register(configurationFileService.onFileChanges(e => this.handleFileEvents(e))); + this._register(fileService.onFileChanges(e => this.handleFileEvents(e))); this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this.reload().then(configurationModel => this._onDidChangeConfiguration.fire(configurationModel)), 50)); this._register(toDisposable(() => { this.stopWatchingResource(); @@ -103,7 +170,7 @@ export class UserConfiguration extends Disposable { } private watchResource(): void { - this.fileWatcherDisposable = this.configurationFileService.watch(this.configurationResource); + this.fileWatcherDisposable = this.fileService.watch(this.configurationResource); } private stopWatchingResource(): void { @@ -113,7 +180,7 @@ export class UserConfiguration extends Disposable { private watchDirectory(): void { const directory = resources.dirname(this.configurationResource); - this.directoryWatcherDisposable = this.configurationFileService.watch(directory); + this.directoryWatcherDisposable = this.fileService.watch(directory); } private stopWatchingDirectory(): void { @@ -122,19 +189,15 @@ export class UserConfiguration extends Disposable { } async initialize(): Promise { - const exists = await this.configurationFileService.exists(this.configurationResource); + const exists = await this.fileService.exists(this.configurationResource); this.onResourceExists(exists); - const configuraitonModel = await this.reload(); - if (!this.configurationFileService.isWatching) { - this.configurationFileService.whenWatchingStarted.then(() => this.onWatchStarted(configuraitonModel)); - } - return configuraitonModel; + return this.reload(); } async reload(): Promise { try { - const content = await this.configurationFileService.readFile(this.configurationResource); - this.parser.parseContent(content); + const content = await this.fileService.readFile(this.configurationResource); + this.parser.parseContent(content.value.toString()); return this.parser.configurationModel; } catch (e) { return new ConfigurationModel(); @@ -146,14 +209,6 @@ export class UserConfiguration extends Disposable { return this.parser.configurationModel; } - private async onWatchStarted(currentModel: ConfigurationModel): Promise { - const configuraitonModel = await this.reload(); - const { added, removed, updated } = compare(currentModel, configuraitonModel); - if (added.length || removed.length || updated.length) { - this._onDidChangeConfiguration.fire(configuraitonModel); - } - } - private async handleFileEvents(event: FileChangesEvent): Promise { const events = event.changes; @@ -188,7 +243,7 @@ export class UserConfiguration extends Disposable { } } -class CachedUserConfiguration extends Disposable { +class CachedRemoteUserConfiguration extends Disposable { private readonly _onDidChange: Emitter = this._register(new Emitter()); readonly onDidChange: Event = this._onDidChange.event; @@ -238,7 +293,7 @@ class CachedUserConfiguration extends Disposable { export class WorkspaceConfiguration extends Disposable { - private readonly _configurationFileService: IConfigurationFileService; + private readonly _fileService: IFileService; private readonly _cachedConfiguration: CachedWorkspaceConfiguration; private _workspaceConfiguration: IWorkspaceConfiguration; private _workspaceConfigurationChangeDisposable: IDisposable = Disposable.None; @@ -252,10 +307,10 @@ export class WorkspaceConfiguration extends Disposable { constructor( configurationCache: IConfigurationCache, - configurationFileService: IConfigurationFileService + fileService: IFileService ) { super(); - this._configurationFileService = configurationFileService; + this._fileService = fileService; this._workspaceConfiguration = this._cachedConfiguration = new CachedWorkspaceConfiguration(configurationCache); } @@ -263,7 +318,7 @@ export class WorkspaceConfiguration extends Disposable { this._workspaceIdentifier = workspaceIdentifier; if (!(this._workspaceConfiguration instanceof FileServiceBasedWorkspaceConfiguration)) { if (this._workspaceIdentifier.configPath.scheme === Schemas.file) { - this.switch(new FileServiceBasedWorkspaceConfiguration(this._configurationFileService)); + this.switch(new FileServiceBasedWorkspaceConfiguration(this._fileService)); } else { this.waitAndSwitch(this._workspaceIdentifier); } @@ -298,9 +353,9 @@ export class WorkspaceConfiguration extends Disposable { } private async waitAndSwitch(workspaceIdentifier: IWorkspaceIdentifier): Promise { - await this._configurationFileService.whenProviderRegistered(workspaceIdentifier.configPath.scheme); + await whenProviderRegistered(workspaceIdentifier.configPath.scheme, this._fileService); if (!(this._workspaceConfiguration instanceof FileServiceBasedWorkspaceConfiguration)) { - const fileServiceBasedWorkspaceConfiguration = this._register(new FileServiceBasedWorkspaceConfiguration(this._configurationFileService)); + const fileServiceBasedWorkspaceConfiguration = this._register(new FileServiceBasedWorkspaceConfiguration(this._fileService)); await fileServiceBasedWorkspaceConfiguration.load(workspaceIdentifier); this.switch(fileServiceBasedWorkspaceConfiguration); this._loaded = true; @@ -355,19 +410,15 @@ class FileServiceBasedWorkspaceConfiguration extends Disposable implements IWork protected readonly _onDidChange: Emitter = this._register(new Emitter()); readonly onDidChange: Event = this._onDidChange.event; - constructor(private configurationFileService: IConfigurationFileService) { + constructor(private fileService: IFileService) { super(); this.workspaceConfigurationModelParser = new WorkspaceConfigurationModelParser(''); this.workspaceSettings = new ConfigurationModel(); - this._register(configurationFileService.onFileChanges(e => this.handleWorkspaceFileEvents(e))); + this._register(fileService.onFileChanges(e => this.handleWorkspaceFileEvents(e))); this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this._onDidChange.fire(), 50)); this.workspaceConfigWatcher = this._register(this.watchWorkspaceConfigurationFile()); - - if (!this.configurationFileService.isWatching) { - this.configurationFileService.whenWatchingStarted.then(() => this.onWatchStarted()); - } } get workspaceIdentifier(): IWorkspaceIdentifier | null { @@ -383,9 +434,10 @@ class FileServiceBasedWorkspaceConfiguration extends Disposable implements IWork } let contents = ''; try { - contents = await this.configurationFileService.readFile(this._workspaceIdentifier.configPath); + const content = await this.fileService.readFile(this._workspaceIdentifier.configPath); + contents = content.value.toString(); } catch (error) { - const exists = await this.configurationFileService.exists(this._workspaceIdentifier.configPath); + const exists = await this.fileService.exists(this._workspaceIdentifier.configPath); if (exists) { errors.onUnexpectedError(error); } @@ -412,24 +464,12 @@ class FileServiceBasedWorkspaceConfiguration extends Disposable implements IWork return this.getWorkspaceSettings(); } - private async onWatchStarted(): Promise { - if (this.workspaceIdentifier) { - const currentModel = this.getConfigurationModel(); - await this.load(this.workspaceIdentifier); - const newModel = this.getConfigurationModel(); - const { added, removed, updated } = compare(currentModel, newModel); - if (added.length || removed.length || updated.length) { - this._onDidChange.fire(); - } - } - } - private consolidate(): void { this.workspaceSettings = this.workspaceConfigurationModelParser.settingsModel.merge(this.workspaceConfigurationModelParser.launchModel); } private watchWorkspaceConfigurationFile(): IDisposable { - return this._workspaceIdentifier ? this.configurationFileService.watch(this._workspaceIdentifier.configPath) : Disposable.None; + return this._workspaceIdentifier ? this.fileService.watch(this._workspaceIdentifier.configPath) : Disposable.None; } private handleWorkspaceFileEvents(event: FileChangesEvent): void { @@ -532,7 +572,7 @@ class FileServiceBasedFolderConfiguration extends Disposable implements IFolderC protected readonly _onDidChange: Emitter = this._register(new Emitter()); readonly onDidChange: Event = this._onDidChange.event; - constructor(protected readonly configurationFolder: URI, workbenchState: WorkbenchState, private configurationFileService: IConfigurationFileService) { + constructor(protected readonly configurationFolder: URI, workbenchState: WorkbenchState, private fileService: IFileService) { super(); this.configurationNames = [FOLDER_SETTINGS_NAME /*First one should be settings */, TASKS_CONFIGURATION_KEY, LAUNCH_CONFIGURATION_KEY]; @@ -542,18 +582,16 @@ class FileServiceBasedFolderConfiguration extends Disposable implements IFolderC this._cache = new ConfigurationModel(); this.changeEventTriggerScheduler = this._register(new RunOnceScheduler(() => this._onDidChange.fire(), 50)); - this._register(configurationFileService.onFileChanges(e => this.handleWorkspaceFileEvents(e))); - if (!this.configurationFileService.isWatching) { - this.configurationFileService.whenWatchingStarted.then(() => this.onWatchStarted()); - } + this._register(fileService.onFileChanges(e => this.handleWorkspaceFileEvents(e))); } async loadConfiguration(): Promise { const configurationContents = await Promise.all(this.configurationResources.map(async resource => { try { - return await this.configurationFileService.readFile(resource); + const content = await this.fileService.readFile(resource); + return content.value.toString(); } catch (error) { - const exists = await this.configurationFileService.exists(resource); + const exists = await this.fileService.exists(resource); if (exists) { errors.onUnexpectedError(error); } @@ -597,15 +635,6 @@ class FileServiceBasedFolderConfiguration extends Disposable implements IFolderC this._cache = this._folderSettingsModelParser.configurationModel.merge(...this._standAloneConfigurations); } - private async onWatchStarted(): Promise { - const currentModel = this._cache; - const newModel = await this.loadConfiguration(); - const { added, removed, updated } = compare(currentModel, newModel); - if (added.length || removed.length || updated.length) { - this._onDidChange.fire(); - } - } - private handleWorkspaceFileEvents(event: FileChangesEvent): void { const events = event.changes; let affectedByChanges = false; @@ -658,7 +687,7 @@ class CachedFolderConfiguration extends Disposable implements IFolderConfigurati readonly onDidChange: Event = this._onDidChange.event; private configurationModel: ConfigurationModel; - private readonly key: Thenable; + private readonly key: ConfigurationKey; constructor( folder: URI, @@ -666,14 +695,13 @@ class CachedFolderConfiguration extends Disposable implements IFolderConfigurati private readonly configurationCache: IConfigurationCache ) { super(); - this.key = createSHA1(join(folder.path, configFolderRelativePath)).then(key => ({ type: 'folder', key })); + this.key = { type: 'folder', key: hash(join(folder.path, configFolderRelativePath)).toString(16) }; this.configurationModel = new ConfigurationModel(); } async loadConfiguration(): Promise { try { - const key = await this.key; - const contents = await this.configurationCache.read(key); + const contents = await this.configurationCache.read(this.key); const parsed: IConfigurationModel = JSON.parse(contents.toString()); this.configurationModel = new ConfigurationModel(parsed.contents, parsed.keys, parsed.overrides); } catch (e) { @@ -682,11 +710,10 @@ class CachedFolderConfiguration extends Disposable implements IFolderConfigurati } async updateConfiguration(configurationModel: ConfigurationModel): Promise { - const key = await this.key; if (configurationModel.keys.length) { - await this.configurationCache.write(key, JSON.stringify(configurationModel.toJSON())); + await this.configurationCache.write(this.key, JSON.stringify(configurationModel.toJSON())); } else { - await this.configurationCache.remove(key); + await this.configurationCache.remove(this.key); } } @@ -713,7 +740,7 @@ export class FolderConfiguration extends Disposable implements IFolderConfigurat readonly workspaceFolder: IWorkspaceFolder, configFolderRelativePath: string, private readonly workbenchState: WorkbenchState, - configurationFileService: IConfigurationFileService, + fileService: IFileService, configurationCache: IConfigurationCache ) { super(); @@ -721,13 +748,13 @@ export class FolderConfiguration extends Disposable implements IFolderConfigurat this.configurationFolder = resources.joinPath(workspaceFolder.uri, configFolderRelativePath); this.folderConfiguration = this.cachedFolderConfiguration = new CachedFolderConfiguration(workspaceFolder.uri, configFolderRelativePath, configurationCache); if (workspaceFolder.uri.scheme === Schemas.file) { - this.folderConfiguration = new FileServiceBasedFolderConfiguration(this.configurationFolder, this.workbenchState, configurationFileService); + this.folderConfiguration = new FileServiceBasedFolderConfiguration(this.configurationFolder, this.workbenchState, fileService); } else { - configurationFileService.whenProviderRegistered(workspaceFolder.uri.scheme) + whenProviderRegistered(workspaceFolder.uri.scheme, fileService) .then(() => { this.folderConfiguration.dispose(); this.folderConfigurationDisposable.dispose(); - this.folderConfiguration = new FileServiceBasedFolderConfiguration(this.configurationFolder, this.workbenchState, configurationFileService); + this.folderConfiguration = new FileServiceBasedFolderConfiguration(this.configurationFolder, this.workbenchState, fileService); this._register(this.folderConfiguration.onDidChange(e => this.onDidFolderConfigurationChange())); this.onDidFolderConfigurationChange(); }); diff --git a/src/vs/workbench/services/configuration/browser/configurationCache.ts b/src/vs/workbench/services/configuration/browser/configurationCache.ts new file mode 100644 index 000000000..f3e8375e9 --- /dev/null +++ b/src/vs/workbench/services/configuration/browser/configurationCache.ts @@ -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. + *--------------------------------------------------------------------------------------------*/ + +import { IConfigurationCache, ConfigurationKey } from 'vs/workbench/services/configuration/common/configuration'; + +export class ConfigurationCache implements IConfigurationCache { + + constructor() { + } + + async read(key: ConfigurationKey): Promise { + return ''; + } + + async write(key: ConfigurationKey, content: string): Promise { + } + + async remove(key: ConfigurationKey): Promise { + } +} \ No newline at end of file diff --git a/src/vs/workbench/services/configuration/browser/configurationService.ts b/src/vs/workbench/services/configuration/browser/configurationService.ts index 547484bfb..50ffb6be2 100644 --- a/src/vs/workbench/services/configuration/browser/configurationService.ts +++ b/src/vs/workbench/services/configuration/browser/configurationService.ts @@ -11,11 +11,10 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { Queue, Barrier } from 'vs/base/common/async'; import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; import { IWorkspaceContextService, Workspace, WorkbenchState, IWorkspaceFolder, toWorkspaceFolders, IWorkspaceFoldersChangeEvent, WorkspaceFolder, toWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; -import { isLinux } from 'vs/base/common/platform'; import { ConfigurationChangeEvent, ConfigurationModel, DefaultConfigurationModel } from 'vs/platform/configuration/common/configurationModels'; import { IConfigurationChangeEvent, ConfigurationTarget, IConfigurationOverrides, keyFromOverrideIdentifier, isConfigurationOverrides, IConfigurationData, IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { Configuration, WorkspaceConfigurationChangeEvent, AllKeysConfigurationChangeEvent } from 'vs/workbench/services/configuration/common/configurationModels'; -import { FOLDER_CONFIG_FOLDER_NAME, defaultSettingsSchemaId, userSettingsSchemaId, workspaceSettingsSchemaId, folderSettingsSchemaId, IConfigurationCache, IConfigurationFileService, machineSettingsSchemaId } from 'vs/workbench/services/configuration/common/configuration'; +import { FOLDER_CONFIG_FOLDER_NAME, defaultSettingsSchemaId, userSettingsSchemaId, workspaceSettingsSchemaId, folderSettingsSchemaId, IConfigurationCache, machineSettingsSchemaId, LOCAL_MACHINE_SCOPES } from 'vs/workbench/services/configuration/common/configuration'; import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, Extensions, allSettings, windowSettings, resourceSettings, applicationSettings, machineSettings } from 'vs/platform/configuration/common/configurationRegistry'; import { IWorkspaceIdentifier, isWorkspaceIdentifier, IStoredWorkspaceFolder, isStoredWorkspaceFolder, IWorkspaceFolderCreationData, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, IWorkspaceInitializationPayload, isSingleFolderWorkspaceInitializationPayload, ISingleFolderWorkspaceInitializationPayload, IEmptyWorkspaceInitializationPayload, useSlashForPath, getStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; @@ -24,10 +23,11 @@ import { ConfigurationEditingService, EditableConfigurationTarget } from 'vs/wor import { WorkspaceConfiguration, FolderConfiguration, RemoteUserConfiguration, UserConfiguration } from 'vs/workbench/services/configuration/browser/configuration'; import { JSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditingService'; import { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema'; -import { localize } from 'vs/nls'; import { isEqual, dirname } from 'vs/base/common/resources'; import { mark } from 'vs/base/common/performance'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; +import { IFileService } from 'vs/platform/files/common/files'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; export class WorkspaceService extends Disposable implements IConfigurationService, IWorkspaceContextService { @@ -37,14 +37,16 @@ export class WorkspaceService extends Disposable implements IConfigurationServic private completeWorkspaceBarrier: Barrier; private readonly configurationCache: IConfigurationCache; private _configuration: Configuration; + private initialized: boolean = false; private defaultConfiguration: DefaultConfigurationModel; - private localUserConfiguration: UserConfiguration | null = null; + private localUserConfiguration: UserConfiguration; private remoteUserConfiguration: RemoteUserConfiguration | null = null; private workspaceConfiguration: WorkspaceConfiguration; private cachedFolderConfigs: ResourceMap; - private workspaceEditingQueue: Queue; + private readonly fileService: IFileService; + protected readonly _onDidChangeConfiguration: Emitter = this._register(new Emitter()); public readonly onDidChangeConfiguration: Event = this._onDidChangeConfiguration.event; @@ -64,24 +66,26 @@ export class WorkspaceService extends Disposable implements IConfigurationServic private cyclicDependency = new Promise(resolve => this.cyclicDependencyReady = resolve); constructor( - { userSettingsResource, remoteAuthority, configurationCache }: { userSettingsResource?: URI, remoteAuthority?: string, configurationCache: IConfigurationCache }, - private readonly configurationFileService: IConfigurationFileService, - remoteAgentService: IRemoteAgentService, + { remoteAuthority, configurationCache }: { remoteAuthority?: string, configurationCache: IConfigurationCache }, + environmentService: IWorkbenchEnvironmentService, + fileService: IFileService, + remoteAgentService: IRemoteAgentService ) { super(); this.completeWorkspaceBarrier = new Barrier(); this.defaultConfiguration = new DefaultConfigurationModel(); this.configurationCache = configurationCache; - if (userSettingsResource) { - this.localUserConfiguration = this._register(new UserConfiguration(userSettingsResource, undefined, configurationFileService)); - this._register(this.localUserConfiguration.onDidChangeConfiguration(userConfiguration => this.onLocalUserConfigurationChanged(userConfiguration))); - } + this.fileService = fileService; + this._configuration = new Configuration(this.defaultConfiguration, new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ResourceMap(), new ConfigurationModel(), new ResourceMap(), this.workspace); + this.cachedFolderConfigs = new ResourceMap(); + this.localUserConfiguration = this._register(new UserConfiguration(environmentService.settingsResource, remoteAuthority ? LOCAL_MACHINE_SCOPES : undefined, fileService)); + this._register(this.localUserConfiguration.onDidChangeConfiguration(userConfiguration => this.onLocalUserConfigurationChanged(userConfiguration))); if (remoteAuthority) { - this.remoteUserConfiguration = this._register(new RemoteUserConfiguration(remoteAuthority, configurationCache, configurationFileService, remoteAgentService)); + this.remoteUserConfiguration = this._register(new RemoteUserConfiguration(remoteAuthority, configurationCache, fileService, remoteAgentService)); this._register(this.remoteUserConfiguration.onDidChangeConfiguration(userConfiguration => this.onRemoteUserConfigurationChanged(userConfiguration))); } - this.workspaceConfiguration = this._register(new WorkspaceConfiguration(configurationCache, this.configurationFileService)); + this.workspaceConfiguration = this._register(new WorkspaceConfiguration(configurationCache, fileService)); this._register(this.workspaceConfiguration.onDidUpdateConfiguration(() => { this.onWorkspaceConfigurationChanged(); if (this.workspaceConfiguration.loaded) { @@ -225,13 +229,7 @@ export class WorkspaceService extends Disposable implements IConfigurationServic } private contains(resources: URI[], toCheck: URI): boolean { - return resources.some(resource => { - if (isLinux) { - return resource.toString() === toCheck.toString(); - } - - return resource.toString().toLowerCase() === toCheck.toString().toLowerCase(); - }); + return resources.some(resource => isEqual(resource, toCheck)); } // Workspace Configuration Service Impl @@ -396,7 +394,7 @@ export class WorkspaceService extends Disposable implements IConfigurationServic } private compareFolders(currentFolders: IWorkspaceFolder[], newFolders: IWorkspaceFolder[]): IWorkspaceFoldersChangeEvent { - const result = { added: [], removed: [], changed: [] } as IWorkspaceFoldersChangeEvent; + const result: IWorkspaceFoldersChangeEvent = { 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]; @@ -420,7 +418,7 @@ export class WorkspaceService extends Disposable implements IConfigurationServic } private initializeUserConfiguration(): Promise<{ local: ConfigurationModel, remote: ConfigurationModel }> { - return Promise.all([this.localUserConfiguration ? this.localUserConfiguration.initialize() : Promise.resolve(new ConfigurationModel()), this.remoteUserConfiguration ? this.remoteUserConfiguration.initialize() : Promise.resolve(new ConfigurationModel())]) + return Promise.all([this.localUserConfiguration.initialize(), this.remoteUserConfiguration ? this.remoteUserConfiguration.initialize() : Promise.resolve(new ConfigurationModel())]) .then(([local, remote]) => ({ local, remote })); } @@ -429,7 +427,7 @@ export class WorkspaceService extends Disposable implements IConfigurationServic } private reloadLocalUserConfiguration(key?: string): Promise { - return this.localUserConfiguration ? this.localUserConfiguration.reload() : Promise.resolve(new ConfigurationModel()); + return this.localUserConfiguration.reload(); } private reloadRemoeUserConfiguration(key?: string): Promise { @@ -466,11 +464,12 @@ export class WorkspaceService extends Disposable implements IConfigurationServic const currentConfiguration = this._configuration; this._configuration = new Configuration(this.defaultConfiguration, userConfigurationModel, remoteUserConfigurationModel, workspaceConfiguration, folderConfigurationModels, new ConfigurationModel(), new ResourceMap(), this.workspace); - if (currentConfiguration) { + if (this.initialized) { const changedKeys = this._configuration.compare(currentConfiguration); this.triggerConfigurationChange(new ConfigurationChangeEvent().change(changedKeys), ConfigurationTarget.WORKSPACE); } else { this._onDidChangeConfiguration.fire(new AllKeysConfigurationChangeEvent(this._configuration, ConfigurationTarget.WORKSPACE, this.getTargetConfiguration(ConfigurationTarget.WORKSPACE))); + this.initialized = true; } }); } @@ -489,7 +488,7 @@ export class WorkspaceService extends Disposable implements IConfigurationServic private onDefaultConfigurationChanged(keys: string[]): void { this.defaultConfiguration = new DefaultConfigurationModel(); this.registerConfigurationSchemas(); - if (this.workspace && this._configuration) { + if (this.workspace) { this._configuration.updateDefaultConfiguration(this.defaultConfiguration); if (this.remoteUserConfiguration) { this._configuration.updateRemoteUserConfiguration(this.remoteUserConfiguration.reprocess()); @@ -507,27 +506,29 @@ export class WorkspaceService extends Disposable implements IConfigurationServic private registerConfigurationSchemas(): void { if (this.workspace) { const jsonRegistry = Registry.as(JSONExtensions.JSONContribution); - const convertToNotSuggestedProperties = (properties: IJSONSchemaMap, errorMessage: string): IJSONSchemaMap => { + const convertToNotSuggestedProperties = (properties: IJSONSchemaMap): IJSONSchemaMap => { return Object.keys(properties).reduce((result: IJSONSchemaMap, property) => { result[property] = deepClone(properties[property]); - result[property].deprecationMessage = errorMessage; + result[property].doNotSuggest = true; return result; }, {}); }; - const allSettingsSchema: IJSONSchema = { properties: allSettings.properties, patternProperties: allSettings.patternProperties, additionalProperties: false, errorMessage: 'Unknown configuration setting' }; - const unsupportedApplicationSettings = convertToNotSuggestedProperties(applicationSettings.properties, localize('unsupportedApplicationSetting', "This setting can be applied only in application user Settings")); - const unsupportedMachineSettings = convertToNotSuggestedProperties(machineSettings.properties, localize('unsupportedMachineSetting', "This setting can be applied only in user Settings")); - const machineSettingsSchema: IJSONSchema = { properties: { ...unsupportedApplicationSettings, ...windowSettings.properties, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: false, errorMessage: 'Unknown configuration setting' }; - const workspaceSettingsSchema: IJSONSchema = { properties: { ...unsupportedApplicationSettings, ...unsupportedMachineSettings, ...windowSettings.properties, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: false, errorMessage: 'Unknown configuration setting' }; + const unsupportedApplicationSettings = convertToNotSuggestedProperties(applicationSettings.properties); + const unsupportedMachineSettings = convertToNotSuggestedProperties(machineSettings.properties); + const unsupportedRemoteMachineSettings = convertToNotSuggestedProperties(machineSettings.properties); + const allSettingsSchema: IJSONSchema = { properties: allSettings.properties, patternProperties: allSettings.patternProperties, additionalProperties: true }; + const userSettingsSchema: IJSONSchema = this.remoteUserConfiguration ? { properties: { ...applicationSettings.properties, ...unsupportedRemoteMachineSettings, ...windowSettings.properties, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: true } : allSettingsSchema; + const machineSettingsSchema: IJSONSchema = { properties: { ...unsupportedApplicationSettings, ...windowSettings.properties, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: true }; + const workspaceSettingsSchema: IJSONSchema = { properties: { ...unsupportedApplicationSettings, ...unsupportedMachineSettings, ...windowSettings.properties, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: true }; jsonRegistry.registerSchema(defaultSettingsSchemaId, allSettingsSchema); - jsonRegistry.registerSchema(userSettingsSchemaId, allSettingsSchema); + jsonRegistry.registerSchema(userSettingsSchemaId, userSettingsSchema); jsonRegistry.registerSchema(machineSettingsSchemaId, machineSettingsSchema); if (WorkbenchState.WORKSPACE === this.getWorkbenchState()) { - const unsupportedWindowSettings = convertToNotSuggestedProperties(windowSettings.properties, localize('unsupportedWindowSetting', "This setting cannot be applied now. It will be applied when you open this folder directly.")); - const folderSettingsSchema: IJSONSchema = { properties: { ...unsupportedApplicationSettings, ...unsupportedMachineSettings, ...unsupportedWindowSettings, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: false, errorMessage: 'Unknown configuration setting' }; + const unsupportedWindowSettings = convertToNotSuggestedProperties(windowSettings.properties); + const folderSettingsSchema: IJSONSchema = { properties: { ...unsupportedApplicationSettings, ...unsupportedMachineSettings, ...unsupportedWindowSettings, ...resourceSettings.properties }, patternProperties: allSettings.patternProperties, additionalProperties: true }; jsonRegistry.registerSchema(workspaceSettingsSchemaId, workspaceSettingsSchema); jsonRegistry.registerSchema(folderSettingsSchemaId, folderSettingsSchema); } else { @@ -548,7 +549,7 @@ export class WorkspaceService extends Disposable implements IConfigurationServic } private onWorkspaceConfigurationChanged(): Promise { - if (this.workspace && this.workspace.configuration && this._configuration) { + if (this.workspace && this.workspace.configuration) { const workspaceConfigurationChangeEvent = this._configuration.compareAndUpdateWorkspaceConfiguration(this.workspaceConfiguration.getConfiguration()); let configuredFolders = toWorkspaceFolders(this.workspaceConfiguration.getFolders(), this.workspace.configuration); const changes = this.compareFolders(this.workspace.folders, configuredFolders); @@ -609,7 +610,7 @@ export class WorkspaceService extends Disposable implements IConfigurationServic return Promise.all([...folders.map(folder => { let folderConfiguration = this.cachedFolderConfigs.get(folder.uri); if (!folderConfiguration) { - folderConfiguration = new FolderConfiguration(folder, FOLDER_CONFIG_FOLDER_NAME, this.getWorkbenchState(), this.configurationFileService, this.configurationCache); + folderConfiguration = new FolderConfiguration(folder, FOLDER_CONFIG_FOLDER_NAME, this.getWorkbenchState(), this.fileService, this.configurationCache); this._register(folderConfiguration.onDidChange(() => this.onWorkspaceFolderConfigurationChanged(folder))); this.cachedFolderConfigs.set(folder.uri, this._register(folderConfiguration)); } diff --git a/src/vs/workbench/services/configuration/common/configuration.ts b/src/vs/workbench/services/configuration/common/configuration.ts index 02192c4c8..170e3f136 100644 --- a/src/vs/workbench/services/configuration/common/configuration.ts +++ b/src/vs/workbench/services/configuration/common/configuration.ts @@ -3,10 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { URI } from 'vs/base/common/uri'; -import { IDisposable } from 'vs/base/common/lifecycle'; -import { Event } from 'vs/base/common/event'; -import { FileChangesEvent, IFileService } from 'vs/platform/files/common/files'; import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; export const FOLDER_CONFIG_FOLDER_NAME = '.vscode'; @@ -20,7 +16,8 @@ export const workspaceSettingsSchemaId = 'vscode://schemas/settings/workspace'; export const folderSettingsSchemaId = 'vscode://schemas/settings/folder'; export const launchSchemaId = 'vscode://schemas/launch'; -export const MACHINE_SCOPES = [ConfigurationScope.MACHINE, ConfigurationScope.WINDOW, ConfigurationScope.RESOURCE]; +export const LOCAL_MACHINE_SCOPES = [ConfigurationScope.APPLICATION, ConfigurationScope.WINDOW, ConfigurationScope.RESOURCE]; +export const REMOTE_MACHINE_SCOPES = [ConfigurationScope.MACHINE, ConfigurationScope.WINDOW, ConfigurationScope.RESOURCE]; export const WORKSPACE_SCOPES = [ConfigurationScope.WINDOW, ConfigurationScope.RESOURCE]; export const FOLDER_SCOPES = [ConfigurationScope.RESOURCE]; @@ -39,51 +36,4 @@ export interface IConfigurationCache { write(key: ConfigurationKey, content: string): Promise; remove(key: ConfigurationKey): Promise; -} - -export interface IConfigurationFileService { - fileService: IFileService | null; - readonly onFileChanges: Event; - readonly isWatching: boolean; - readonly whenWatchingStarted: Promise; - whenProviderRegistered(scheme: string): Promise; - watch(resource: URI): IDisposable; - exists(resource: URI): Promise; - readFile(resource: URI): Promise; -} - -export class ConfigurationFileService implements IConfigurationFileService { - - constructor(public fileService: IFileService) { } - - get onFileChanges() { return this.fileService.onFileChanges; } - readonly whenWatchingStarted: Promise = Promise.resolve(); - readonly isWatching: boolean = true; - - whenProviderRegistered(scheme: string): Promise { - if (this.fileService.canHandleResource(URI.from({ scheme }))) { - return Promise.resolve(); - } - return new Promise((c, e) => { - const disposable = this.fileService.onDidChangeFileSystemProviderRegistrations(e => { - if (e.scheme === scheme && e.added) { - disposable.dispose(); - c(); - } - }); - }); - } - - watch(resource: URI): IDisposable { - return this.fileService.watch(resource); - } - - exists(resource: URI): Promise { - return this.fileService.exists(resource); - } - - readFile(resource: URI): Promise { - return this.fileService.readFile(resource).then(content => content.value.toString()); - } - -} +} \ No newline at end of file diff --git a/src/vs/workbench/services/configuration/common/configurationEditingService.ts b/src/vs/workbench/services/configuration/common/configurationEditingService.ts index 7f4147d64..ffef24c55 100644 --- a/src/vs/workbench/services/configuration/common/configurationEditingService.ts +++ b/src/vs/workbench/services/configuration/common/configurationEditingService.ts @@ -528,7 +528,7 @@ export class ConfigurationEditingService { private getConfigurationFileResource(target: EditableConfigurationTarget, config: IConfigurationValue, relativePath: string, resource: URI | null | undefined): URI | null { if (target === EditableConfigurationTarget.USER_LOCAL) { - return URI.file(this.environmentService.appSettingsPath); + return this.environmentService.settingsResource; } if (target === EditableConfigurationTarget.USER_REMOTE) { return this.remoteSettingsResource; diff --git a/src/vs/workbench/services/configuration/common/jsonEditingService.ts b/src/vs/workbench/services/configuration/common/jsonEditingService.ts index baeccb314..9313c53cc 100644 --- a/src/vs/workbench/services/configuration/common/jsonEditingService.ts +++ b/src/vs/workbench/services/configuration/common/jsonEditingService.ts @@ -39,10 +39,11 @@ export class JSONEditingService implements IJSONEditingService { return Promise.resolve(this.queue.queue(() => this.doWriteConfiguration(resource, value, save))); // queue up writes to prevent race conditions } - private doWriteConfiguration(resource: URI, value: IJSONValue, save: boolean): Promise { - return this.resolveAndValidate(resource, save) - .then(reference => this.writeToBuffer(reference.object.textEditorModel, value) - .then(() => reference.dispose())); + private async doWriteConfiguration(resource: URI, value: IJSONValue, save: boolean): Promise { + const reference = await this.resolveAndValidate(resource, save); + await this.writeToBuffer(reference.object.textEditorModel, value); + + reference.dispose(); } private async writeToBuffer(model: ITextModel, value: IJSONValue): Promise { @@ -97,21 +98,21 @@ export class JSONEditingService implements IJSONEditingService { return parseErrors.length > 0; } - private resolveAndValidate(resource: URI, checkDirty: boolean): Promise> { - return this.resolveModelReference(resource) - .then(reference => { - const model = reference.object.textEditorModel; - - if (this.hasParseErrors(model)) { - return this.reject>(JSONEditingErrorCode.ERROR_INVALID_FILE); - } - - // Target cannot be dirty if not writing into buffer - if (checkDirty && this.textFileService.isDirty(resource)) { - return this.reject>(JSONEditingErrorCode.ERROR_FILE_DIRTY); - } - return reference; - }); + private async resolveAndValidate(resource: URI, checkDirty: boolean): Promise> { + const reference = await this.resolveModelReference(resource); + + const model = reference.object.textEditorModel; + + if (this.hasParseErrors(model)) { + return this.reject>(JSONEditingErrorCode.ERROR_INVALID_FILE); + } + + // Target cannot be dirty if not writing into buffer + if (checkDirty && this.textFileService.isDirty(resource)) { + return this.reject>(JSONEditingErrorCode.ERROR_FILE_DIRTY); + } + + return reference; } private reject(code: JSONEditingErrorCode): Promise { diff --git a/src/vs/workbench/services/configuration/node/configurationCache.ts b/src/vs/workbench/services/configuration/node/configurationCache.ts index 67b46a14c..432c8ada9 100644 --- a/src/vs/workbench/services/configuration/node/configurationCache.ts +++ b/src/vs/workbench/services/configuration/node/configurationCache.ts @@ -7,12 +7,13 @@ import * as pfs from 'vs/base/node/pfs'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { join } from 'vs/base/common/path'; import { IConfigurationCache, ConfigurationKey } from 'vs/workbench/services/configuration/common/configuration'; +import { IWorkbenchEnvironmentService } from '../../environment/common/environmentService'; export class ConfigurationCache implements IConfigurationCache { private readonly cachedConfigurations: Map = new Map(); - constructor(private readonly environmentService: IEnvironmentService) { + constructor(private readonly environmentService: IWorkbenchEnvironmentService) { } read(key: ConfigurationKey): Promise { diff --git a/src/vs/workbench/services/configuration/node/configurationFileService.ts b/src/vs/workbench/services/configuration/node/configurationFileService.ts deleted file mode 100644 index 18690c440..000000000 --- a/src/vs/workbench/services/configuration/node/configurationFileService.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. - *--------------------------------------------------------------------------------------------*/ - -import * as pfs from 'vs/base/node/pfs'; -import { IConfigurationFileService, ConfigurationFileService as FileServiceBasedConfigurationFileService } from 'vs/workbench/services/configuration/common/configuration'; -import { URI } from 'vs/base/common/uri'; -import { Event, Emitter } from 'vs/base/common/event'; -import { FileChangesEvent, IFileService } from 'vs/platform/files/common/files'; -import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; -import { Schemas } from 'vs/base/common/network'; - -export class ConfigurationFileService extends Disposable implements IConfigurationFileService { - - private _fileServiceBasedConfigurationFileService: FileServiceBasedConfigurationFileService | null = null; - private _fileServiceBasedConfigurationFileServiceCallback: (fileServiceBasedConfigurationFileService: FileServiceBasedConfigurationFileService) => void; - private _whenFileServiceBasedConfigurationFileServiceAvailable: Promise = new Promise((c) => this._fileServiceBasedConfigurationFileServiceCallback = c); - private _watchResources: { resource: URI, disposable: { disposable: IDisposable | null } }[] = []; - readonly whenWatchingStarted: Promise = this._whenFileServiceBasedConfigurationFileServiceAvailable.then(() => undefined); - - private readonly _onFileChanges: Emitter = this._register(new Emitter()); - readonly onFileChanges: Event = this._onFileChanges.event; - - get isWatching(): boolean { - return this._fileServiceBasedConfigurationFileService ? this._fileServiceBasedConfigurationFileService.isWatching : false; - } - - watch(resource: URI): IDisposable { - if (this._fileServiceBasedConfigurationFileService) { - return this._fileServiceBasedConfigurationFileService.watch(resource); - } - const disposable: { disposable: IDisposable | null } = { disposable: null }; - this._watchResources.push({ resource, disposable }); - return toDisposable(() => { - if (disposable.disposable) { - disposable.disposable.dispose(); - } - }); - } - - whenProviderRegistered(scheme: string): Promise { - if (scheme === Schemas.file) { - return Promise.resolve(); - } - return this._whenFileServiceBasedConfigurationFileServiceAvailable - .then(fileServiceBasedConfigurationFileService => fileServiceBasedConfigurationFileService.whenProviderRegistered(scheme)); - } - - exists(resource: URI): Promise { - return this._fileServiceBasedConfigurationFileService ? this._fileServiceBasedConfigurationFileService.exists(resource) : pfs.exists(resource.fsPath); - } - - async readFile(resource: URI): Promise { - if (this._fileServiceBasedConfigurationFileService) { - return this._fileServiceBasedConfigurationFileService.readFile(resource); - } else { - const contents = await pfs.readFile(resource.fsPath); - return contents.toString(); - } - } - - private _fileService: IFileService | null; - get fileService(): IFileService | null { - return this._fileService; - } - - set fileService(fileService: IFileService | null) { - if (fileService && !this._fileServiceBasedConfigurationFileService) { - this._fileServiceBasedConfigurationFileService = new FileServiceBasedConfigurationFileService(fileService); - this._fileService = fileService; - this._register(this._fileServiceBasedConfigurationFileService.onFileChanges(e => this._onFileChanges.fire(e))); - for (const { resource, disposable } of this._watchResources) { - disposable.disposable = this._fileServiceBasedConfigurationFileService.watch(resource); - } - this._fileServiceBasedConfigurationFileServiceCallback(this._fileServiceBasedConfigurationFileService); - } - } -} diff --git a/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts b/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts index b3c90ce98..2a75dca34 100644 --- a/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts +++ b/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts @@ -10,10 +10,9 @@ import * as path from 'vs/base/common/path'; import * as fs from 'fs'; import * as json from 'vs/base/common/json'; import { Registry } from 'vs/platform/registry/common/platform'; -import { ParsedArgs, IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; 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 { TestTextFileService, workbenchInstantiationService } from 'vs/workbench/test/workbenchTestServices'; import * as uuid from 'vs/base/common/uuid'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; @@ -33,21 +32,25 @@ import { URI } from 'vs/base/common/uri'; import { createHash } from 'crypto'; import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; -import { FileService } from 'vs/workbench/services/files/common/fileService'; +import { FileService } from 'vs/platform/files/common/fileService'; import { NullLogService } from 'vs/platform/log/common/log'; import { Schemas } from 'vs/base/common/network'; -import { DiskFileSystemProvider } from 'vs/workbench/services/files/node/diskFileSystemProvider'; +import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; import { IFileService } from 'vs/platform/files/common/files'; import { ConfigurationCache } from 'vs/workbench/services/configuration/node/configurationCache'; -import { ConfigurationFileService } from 'vs/workbench/services/configuration/node/configurationFileService'; +import { KeybindingsEditingService, IKeybindingEditingService } from 'vs/workbench/services/keybinding/common/keybindingEditing'; +import { WorkbenchEnvironmentService } from 'vs/workbench/services/environment/node/environmentService'; +import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; +import { FileUserDataProvider } from 'vs/workbench/services/userData/common/fileUserDataProvider'; -class SettingsTestEnvironmentService extends EnvironmentService { +class TestEnvironmentService extends WorkbenchEnvironmentService { - constructor(args: ParsedArgs, _execPath: string, private customAppSettingsHome: string) { - super(args, _execPath); + constructor(private _appSettingsHome: URI) { + super(parseArgs(process.argv) as IWindowConfiguration, process.execPath); } - get appSettingsPath(): string { return this.customAppSettingsHome; } + get appSettingsHome() { return this._appSettingsHome; } + } suite('ConfigurationEditingService', () => { @@ -90,7 +93,7 @@ suite('ConfigurationEditingService', () => { const id = uuid.generateUuid(); parentDir = path.join(os.tmpdir(), 'vsctests', id); workspaceDir = path.join(parentDir, 'workspaceconfig', id); - globalSettingsFile = path.join(workspaceDir, 'config.json'); + globalSettingsFile = path.join(workspaceDir, 'settings.json'); workspaceSettingsDir = path.join(workspaceDir, '.vscode'); return await mkdirp(workspaceSettingsDir, 493); @@ -101,17 +104,20 @@ suite('ConfigurationEditingService', () => { clearServices(); instantiationService = workbenchInstantiationService(); - const environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, globalSettingsFile); + const environmentService = new TestEnvironmentService(URI.file(workspaceDir)); instantiationService.stub(IEnvironmentService, environmentService); const remoteAgentService = instantiationService.createInstance(RemoteAgentService, {}); + const fileService = new FileService(new NullLogService()); + const diskFileSystemProvider = new DiskFileSystemProvider(new NullLogService()); + fileService.registerProvider(Schemas.file, diskFileSystemProvider); + fileService.registerProvider(Schemas.userData, new FileUserDataProvider(environmentService.appSettingsHome, environmentService.backupHome, diskFileSystemProvider, environmentService)); + instantiationService.stub(IFileService, fileService); instantiationService.stub(IRemoteAgentService, remoteAgentService); - const workspaceService = new WorkspaceService({ userSettingsResource: URI.file(environmentService.appSettingsPath), configurationCache: new ConfigurationCache(environmentService) }, new ConfigurationFileService(), remoteAgentService); + const workspaceService = new WorkspaceService({ configurationCache: new ConfigurationCache(environmentService) }, environmentService, fileService, remoteAgentService); instantiationService.stub(IWorkspaceContextService, workspaceService); return workspaceService.initialize(noWorkspace ? { id: '' } : { folder: URI.file(workspaceDir), id: createHash('md5').update(URI.file(workspaceDir).toString()).digest('hex') }).then(() => { instantiationService.stub(IConfigurationService, workspaceService); - const fileService = new FileService(new NullLogService()); - fileService.registerProvider(Schemas.file, new DiskFileSystemProvider(new NullLogService())); - instantiationService.stub(IFileService, fileService); + instantiationService.stub(IKeybindingEditingService, instantiationService.createInstance(KeybindingsEditingService)); instantiationService.stub(ITextFileService, instantiationService.createInstance(TestTextFileService)); instantiationService.stub(ITextModelService, instantiationService.createInstance(TextModelResolverService)); instantiationService.stub(ICommandService, CommandService); @@ -121,7 +127,10 @@ suite('ConfigurationEditingService', () => { teardown(() => { clearServices(); - return clearWorkspace(); + if (workspaceDir) { + return rimraf(workspaceDir, RimRafMode.MOVE); + } + return undefined; }); function clearServices(): void { @@ -134,16 +143,6 @@ suite('ConfigurationEditingService', () => { } } - function clearWorkspace(): Promise { - return new Promise((c, e) => { - if (parentDir) { - rimraf(parentDir, RimRafMode.MOVE).then(c, c); - } else { - c(undefined); - } - }).then(() => parentDir = null!); - } - test('errors cases - invalid key', () => { return testObject.writeConfiguration(EditableConfigurationTarget.WORKSPACE, { key: 'unknown.key', value: 'value' }) .then(() => assert.fail('Should fail with ERROR_UNKNOWN_KEY'), @@ -186,7 +185,7 @@ suite('ConfigurationEditingService', () => { test('do not notify error', () => { instantiationService.stub(ITextFileService, 'isDirty', true); const target = sinon.stub(); - instantiationService.stub(INotificationService, { prompt: target, _serviceBrand: null, notify: null!, error: null!, info: null!, warn: null! }); + instantiationService.stub(INotificationService, { prompt: target, _serviceBrand: null!, notify: null!, error: null!, info: null!, warn: null!, status: null! }); return testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'configurationEditing.service.testSetting', value: 'value' }, { donotNotifyError: true }) .then(() => assert.fail('Should fail with ERROR_CONFIGURATION_FILE_DIRTY error.'), (error: ConfigurationEditingError) => { diff --git a/src/vs/workbench/services/configuration/test/electron-browser/configurationService.test.ts b/src/vs/workbench/services/configuration/test/electron-browser/configurationService.test.ts index e35f5b0de..e59d6ad40 100644 --- a/src/vs/workbench/services/configuration/test/electron-browser/configurationService.test.ts +++ b/src/vs/workbench/services/configuration/test/electron-browser/configurationService.test.ts @@ -10,8 +10,7 @@ import * as path from 'vs/base/common/path'; import * as os from 'os'; import { URI } from 'vs/base/common/uri'; 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 { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { parseArgs } from 'vs/platform/environment/node/argv'; import * as pfs from 'vs/base/node/pfs'; import * as uuid from 'vs/base/common/uuid'; @@ -22,7 +21,7 @@ import { ConfigurationEditingErrorCode } from 'vs/workbench/services/configurati import { IFileService } from 'vs/platform/files/common/files'; import { IWorkspaceContextService, WorkbenchState, IWorkspaceFoldersChangeEvent } from 'vs/platform/workspace/common/workspace'; import { ConfigurationTarget, IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; -import { workbenchInstantiationService, TestTextFileService } from 'vs/workbench/test/workbenchTestServices'; +import { workbenchInstantiationService, TestTextFileService, RemoteFileSystemProvider } from 'vs/workbench/test/workbenchTestServices'; 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'; @@ -37,19 +36,26 @@ import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; import { RemoteAgentService } from 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl'; import { RemoteAuthorityResolverService } from 'vs/platform/remote/electron-browser/remoteAuthorityResolverService'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; -import { FileService } from 'vs/workbench/services/files/common/fileService'; +import { FileService } from 'vs/platform/files/common/fileService'; import { NullLogService } from 'vs/platform/log/common/log'; -import { DiskFileSystemProvider } from 'vs/workbench/services/files/node/diskFileSystemProvider'; +import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; import { ConfigurationCache } from 'vs/workbench/services/configuration/node/configurationCache'; -import { ConfigurationFileService } from 'vs/workbench/services/configuration/node/configurationFileService'; - -class SettingsTestEnvironmentService extends EnvironmentService { - - constructor(args: ParsedArgs, _execPath: string, private customAppSettingsHome: string) { - super(args, _execPath); +import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment'; +import { IConfigurationCache } from 'vs/workbench/services/configuration/common/configuration'; +import { SignService } from 'vs/platform/sign/browser/signService'; +import { FileUserDataProvider } from 'vs/workbench/services/userData/common/fileUserDataProvider'; +import { IKeybindingEditingService, KeybindingsEditingService } from 'vs/workbench/services/keybinding/common/keybindingEditing'; +import { WorkbenchEnvironmentService } from 'vs/workbench/services/environment/node/environmentService'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; + +class TestEnvironmentService extends WorkbenchEnvironmentService { + + constructor(private _appSettingsHome: URI) { + super(parseArgs(process.argv) as IWindowConfiguration, process.execPath); } - get appSettingsPath(): string { return this.customAppSettingsHome; } + get appSettingsHome() { return this._appSettingsHome; } + } function setUpFolderWorkspace(folderName: string): Promise<{ parentDir: string, folderDir: string }> { @@ -98,9 +104,10 @@ suite('WorkspaceContextService - Folder', () => { .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({ userSettingsResource: URI.file(environmentService.appSettingsPath), configurationCache: new ConfigurationCache(environmentService) }, new ConfigurationFileService(), new RemoteAgentService({}, environmentService, new RemoteAuthorityResolverService())); + const environmentService = new TestEnvironmentService(URI.file(parentDir)); + const fileService = new FileService(new NullLogService()); + fileService.registerProvider(Schemas.userData, new FileUserDataProvider(environmentService.appSettingsHome, environmentService.backupHome, new DiskFileSystemProvider(new NullLogService()), environmentService)); + workspaceContextService = new WorkspaceService({ configurationCache: new ConfigurationCache(environmentService) }, environmentService, fileService, new RemoteAgentService({}, environmentService, new RemoteAuthorityResolverService(), new SignService(undefined))); return (workspaceContextService).initialize(convertToWorkspacePayload(URI.file(folderDir))); }); }); @@ -159,10 +166,14 @@ suite('WorkspaceContextService - Workspace', () => { parentResource = parentDir; instantiationService = workbenchInstantiationService(); - const environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, path.join(parentDir, 'settings.json')); + const environmentService = new TestEnvironmentService(URI.file(parentDir)); const remoteAgentService = instantiationService.createInstance(RemoteAgentService, {}); instantiationService.stub(IRemoteAgentService, remoteAgentService); - const workspaceService = new WorkspaceService({ userSettingsResource: URI.file(environmentService.appSettingsPath), configurationCache: new ConfigurationCache(environmentService) }, new ConfigurationFileService(), remoteAgentService); + const fileService = new FileService(new NullLogService()); + const diskFileSystemProvider = new DiskFileSystemProvider(new NullLogService()); + fileService.registerProvider(Schemas.file, diskFileSystemProvider); + fileService.registerProvider(Schemas.userData, new FileUserDataProvider(environmentService.appSettingsHome, environmentService.backupHome, diskFileSystemProvider, environmentService)); + const workspaceService = new WorkspaceService({ configurationCache: new ConfigurationCache(environmentService) }, environmentService, fileService, remoteAgentService); instantiationService.stub(IWorkspaceContextService, workspaceService); instantiationService.stub(IConfigurationService, workspaceService); @@ -215,14 +226,14 @@ suite('WorkspaceContextService - Workspace Editing', () => { parentResource = parentDir; instantiationService = workbenchInstantiationService(); - const environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, path.join(parentDir, 'settings.json')); + const environmentService = new TestEnvironmentService(URI.file(parentDir)); const remoteAgentService = instantiationService.createInstance(RemoteAgentService, {}); instantiationService.stub(IRemoteAgentService, remoteAgentService); const fileService = new FileService(new NullLogService()); - fileService.registerProvider(Schemas.file, new DiskFileSystemProvider(new NullLogService())); - const configurationFileService = new ConfigurationFileService(); - configurationFileService.fileService = fileService; - const workspaceService = new WorkspaceService({ userSettingsResource: URI.file(environmentService.appSettingsPath), configurationCache: new ConfigurationCache(environmentService) }, configurationFileService, remoteAgentService); + const diskFileSystemProvider = new DiskFileSystemProvider(new NullLogService()); + fileService.registerProvider(Schemas.file, diskFileSystemProvider); + fileService.registerProvider(Schemas.userData, new FileUserDataProvider(environmentService.appSettingsHome, environmentService.backupHome, diskFileSystemProvider, environmentService)); + const workspaceService = new WorkspaceService({ configurationCache: new ConfigurationCache(environmentService) }, environmentService, fileService, remoteAgentService); instantiationService.stub(IWorkspaceContextService, workspaceService); instantiationService.stub(IConfigurationService, workspaceService); @@ -476,14 +487,14 @@ suite('WorkspaceService - Initialization', () => { globalSettingsFile = path.join(parentDir, 'settings.json'); const instantiationService = workbenchInstantiationService(); - const environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, globalSettingsFile); + const environmentService = new TestEnvironmentService(URI.file(parentDir)); const remoteAgentService = instantiationService.createInstance(RemoteAgentService, {}); instantiationService.stub(IRemoteAgentService, remoteAgentService); const fileService = new FileService(new NullLogService()); - fileService.registerProvider(Schemas.file, new DiskFileSystemProvider(new NullLogService())); - const configurationFileService = new ConfigurationFileService(); - configurationFileService.fileService = fileService; - const workspaceService = new WorkspaceService({ userSettingsResource: URI.file(environmentService.appSettingsPath), configurationCache: new ConfigurationCache(environmentService) }, configurationFileService, remoteAgentService); + const diskFileSystemProvider = new DiskFileSystemProvider(new NullLogService()); + fileService.registerProvider(Schemas.file, diskFileSystemProvider); + fileService.registerProvider(Schemas.userData, new FileUserDataProvider(environmentService.appSettingsHome, environmentService.backupHome, diskFileSystemProvider, environmentService)); + const workspaceService = new WorkspaceService({ configurationCache: new ConfigurationCache(environmentService) }, environmentService, fileService, remoteAgentService); instantiationService.stub(IWorkspaceContextService, workspaceService); instantiationService.stub(IConfigurationService, workspaceService); instantiationService.stub(IEnvironmentService, environmentService); @@ -740,20 +751,21 @@ suite('WorkspaceConfigurationService - Folder', () => { globalSettingsFile = path.join(parentDir, 'settings.json'); const instantiationService = workbenchInstantiationService(); - const environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, globalSettingsFile); + const environmentService = new TestEnvironmentService(URI.file(parentDir)); const remoteAgentService = instantiationService.createInstance(RemoteAgentService, {}); instantiationService.stub(IRemoteAgentService, remoteAgentService); const fileService = new FileService(new NullLogService()); - fileService.registerProvider(Schemas.file, new DiskFileSystemProvider(new NullLogService())); - const configurationFileService = new ConfigurationFileService(); - configurationFileService.fileService = fileService; - const workspaceService = new WorkspaceService({ userSettingsResource: URI.file(environmentService.appSettingsPath), configurationCache: new ConfigurationCache(environmentService) }, configurationFileService, remoteAgentService); + const diskFileSystemProvider = new DiskFileSystemProvider(new NullLogService()); + fileService.registerProvider(Schemas.file, diskFileSystemProvider); + fileService.registerProvider(Schemas.userData, new FileUserDataProvider(environmentService.appSettingsHome, environmentService.backupHome, diskFileSystemProvider, environmentService)); + const workspaceService = new WorkspaceService({ configurationCache: new ConfigurationCache(environmentService) }, environmentService, fileService, remoteAgentService); instantiationService.stub(IWorkspaceContextService, workspaceService); instantiationService.stub(IConfigurationService, workspaceService); instantiationService.stub(IEnvironmentService, environmentService); return workspaceService.initialize(convertToWorkspacePayload(URI.file(folderDir))).then(() => { instantiationService.stub(IFileService, fileService); + instantiationService.stub(IKeybindingEditingService, instantiationService.createInstance(KeybindingsEditingService)); instantiationService.stub(ITextFileService, instantiationService.createInstance(TestTextFileService)); instantiationService.stub(ITextModelService, instantiationService.createInstance(TextModelResolverService)); workspaceService.acquireInstantiationService(instantiationService); @@ -1030,7 +1042,7 @@ suite('WorkspaceConfigurationService - Folder', () => { suite('WorkspaceConfigurationService-Multiroot', () => { - let parentResource: string, workspaceContextService: IWorkspaceContextService, environmentService: IEnvironmentService, jsonEditingServce: IJSONEditingService, testObject: IConfigurationService; + let parentResource: string, workspaceContextService: IWorkspaceContextService, jsonEditingServce: IJSONEditingService, testObject: IConfigurationService, globalSettingsFile: string; const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); suiteSetup(() => { @@ -1066,23 +1078,25 @@ suite('WorkspaceConfigurationService-Multiroot', () => { .then(({ parentDir, configPath }) => { parentResource = parentDir; + globalSettingsFile = path.join(parentDir, 'settings.json'); const instantiationService = workbenchInstantiationService(); - environmentService = new SettingsTestEnvironmentService(parseArgs(process.argv), process.execPath, path.join(parentDir, 'settings.json')); + const environmentService = new TestEnvironmentService(URI.file(parentDir)); const remoteAgentService = instantiationService.createInstance(RemoteAgentService, {}); instantiationService.stub(IRemoteAgentService, remoteAgentService); const fileService = new FileService(new NullLogService()); - fileService.registerProvider(Schemas.file, new DiskFileSystemProvider(new NullLogService())); - const configurationFileService = new ConfigurationFileService(); - configurationFileService.fileService = fileService; - const workspaceService = new WorkspaceService({ userSettingsResource: URI.file(environmentService.appSettingsPath), configurationCache: new ConfigurationCache(environmentService) }, configurationFileService, remoteAgentService); + const diskFileSystemProvider = new DiskFileSystemProvider(new NullLogService()); + fileService.registerProvider(Schemas.file, diskFileSystemProvider); + fileService.registerProvider(Schemas.userData, new FileUserDataProvider(environmentService.appSettingsHome, environmentService.backupHome, diskFileSystemProvider, environmentService)); + const workspaceService = new WorkspaceService({ configurationCache: new ConfigurationCache(environmentService) }, environmentService, fileService, remoteAgentService); instantiationService.stub(IWorkspaceContextService, workspaceService); instantiationService.stub(IConfigurationService, workspaceService); - instantiationService.stub(IEnvironmentService, environmentService); + instantiationService.stub(IWorkbenchEnvironmentService, environmentService); return workspaceService.initialize(getWorkspaceIdentifier(configPath)).then(() => { instantiationService.stub(IFileService, fileService); + instantiationService.stub(IKeybindingEditingService, instantiationService.createInstance(KeybindingsEditingService)); instantiationService.stub(ITextFileService, instantiationService.createInstance(TestTextFileService)); instantiationService.stub(ITextModelService, instantiationService.createInstance(TextModelResolverService)); workspaceService.acquireInstantiationService(instantiationService); @@ -1105,21 +1119,21 @@ suite('WorkspaceConfigurationService-Multiroot', () => { }); test('application settings are not read from workspace', () => { - fs.writeFileSync(environmentService.appSettingsPath, '{ "configurationService.workspace.applicationSetting": "userValue" }'); + fs.writeFileSync(globalSettingsFile, '{ "configurationService.workspace.applicationSetting": "userValue" }'); return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, { key: 'settings', value: { 'configurationService.workspace.applicationSetting': 'workspaceValue' } }, true) .then(() => testObject.reloadConfiguration()) .then(() => assert.equal(testObject.getValue('configurationService.workspace.applicationSetting'), 'userValue')); }); test('machine settings are not read from workspace', () => { - fs.writeFileSync(environmentService.appSettingsPath, '{ "configurationService.workspace.machineSetting": "userValue" }'); + fs.writeFileSync(globalSettingsFile, '{ "configurationService.workspace.machineSetting": "userValue" }'); return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, { key: 'settings', value: { 'configurationService.workspace.machineSetting': 'workspaceValue' } }, true) .then(() => testObject.reloadConfiguration()) .then(() => assert.equal(testObject.getValue('configurationService.workspace.machineSetting'), 'userValue')); }); test('workspace settings override user settings after defaults are registered ', () => { - fs.writeFileSync(environmentService.appSettingsPath, '{ "configurationService.workspace.newSetting": "userValue" }'); + fs.writeFileSync(globalSettingsFile, '{ "configurationService.workspace.newSetting": "userValue" }'); return jsonEditingServce.write(workspaceContextService.getWorkspace().configuration!, { key: 'settings', value: { 'configurationService.workspace.newSetting': 'workspaceValue' } }, true) .then(() => testObject.reloadConfiguration()) .then(() => { @@ -1138,21 +1152,21 @@ suite('WorkspaceConfigurationService-Multiroot', () => { }); test('application settings are not read from workspace folder', () => { - fs.writeFileSync(environmentService.appSettingsPath, '{ "configurationService.workspace.applicationSetting": "userValue" }'); + fs.writeFileSync(globalSettingsFile, '{ "configurationService.workspace.applicationSetting": "userValue" }'); fs.writeFileSync(workspaceContextService.getWorkspace().folders[0].toResource('.vscode/settings.json').fsPath, '{ "configurationService.workspace.applicationSetting": "workspaceFolderValue" }'); return testObject.reloadConfiguration() .then(() => assert.equal(testObject.getValue('configurationService.workspace.applicationSetting'), 'userValue')); }); test('machine settings are not read from workspace folder', () => { - fs.writeFileSync(environmentService.appSettingsPath, '{ "configurationService.workspace.machineSetting": "userValue" }'); + fs.writeFileSync(globalSettingsFile, '{ "configurationService.workspace.machineSetting": "userValue" }'); fs.writeFileSync(workspaceContextService.getWorkspace().folders[0].toResource('.vscode/settings.json').fsPath, '{ "configurationService.workspace.machineSetting": "workspaceFolderValue" }'); return testObject.reloadConfiguration() .then(() => assert.equal(testObject.getValue('configurationService.workspace.machineSetting'), 'userValue')); }); test('application settings are not read from workspace folder after defaults are registered', () => { - fs.writeFileSync(environmentService.appSettingsPath, '{ "configurationService.workspace.testNewApplicationSetting": "userValue" }'); + fs.writeFileSync(globalSettingsFile, '{ "configurationService.workspace.testNewApplicationSetting": "userValue" }'); fs.writeFileSync(workspaceContextService.getWorkspace().folders[0].toResource('.vscode/settings.json').fsPath, '{ "configurationService.workspace.testNewApplicationSetting": "workspaceFolderValue" }'); return testObject.reloadConfiguration() .then(() => { @@ -1172,7 +1186,7 @@ suite('WorkspaceConfigurationService-Multiroot', () => { }); test('application settings are not read from workspace folder after defaults are registered', () => { - fs.writeFileSync(environmentService.appSettingsPath, '{ "configurationService.workspace.testNewMachineSetting": "userValue" }'); + fs.writeFileSync(globalSettingsFile, '{ "configurationService.workspace.testNewMachineSetting": "userValue" }'); fs.writeFileSync(workspaceContextService.getWorkspace().folders[0].toResource('.vscode/settings.json').fsPath, '{ "configurationService.workspace.testNewMachineSetting": "workspaceFolderValue" }'); return testObject.reloadConfiguration() .then(() => { @@ -1226,7 +1240,7 @@ suite('WorkspaceConfigurationService-Multiroot', () => { assert.equal(actual.workspaceFolder, undefined); assert.equal(actual.value, 'isSet'); - fs.writeFileSync(environmentService.appSettingsPath, '{ "configurationService.workspace.testResourceSetting": "userValue" }'); + fs.writeFileSync(globalSettingsFile, '{ "configurationService.workspace.testResourceSetting": "userValue" }'); return testObject.reloadConfiguration() .then(() => { actual = testObject.inspect('configurationService.workspace.testResourceSetting'); @@ -1408,6 +1422,198 @@ suite('WorkspaceConfigurationService-Multiroot', () => { assert.equal(actual.workspace, undefined); }); }); + + test('configuration of newly added folder is available on configuration change event', async () => { + const workspaceService = testObject; + const uri = workspaceService.getWorkspace().folders[1].uri; + await workspaceService.removeFolders([uri]); + fs.writeFileSync(path.join(uri.fsPath, '.vscode', 'settings.json'), '{ "configurationService.workspace.testResourceSetting": "workspaceFolderValue" }'); + + return new Promise((c, e) => { + testObject.onDidChangeConfiguration(() => { + try { + assert.equal(testObject.getValue('configurationService.workspace.testResourceSetting', { resource: uri }), 'workspaceFolderValue'); + c(); + } catch (error) { + e(error); + } + }); + workspaceService.addFolders([{ uri }]); + }); + }); +}); + +suite('WorkspaceConfigurationService - Remote Folder', () => { + + let workspaceName = `testWorkspace${uuid.generateUuid()}`, parentResource: string, workspaceDir: string, testObject: WorkspaceService, globalSettingsFile: string, remoteSettingsFile: string, instantiationService: TestInstantiationService, resolveRemoteEnvironment: () => void; + const remoteAuthority = 'configuraiton-tests'; + const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); + const diskFileSystemProvider = new DiskFileSystemProvider(new NullLogService()); + + suiteSetup(() => { + configurationRegistry.registerConfiguration({ + 'id': '_test', + 'type': 'object', + 'properties': { + 'configurationService.remote.applicationSetting': { + 'type': 'string', + 'default': 'isSet', + scope: ConfigurationScope.APPLICATION + }, + 'configurationService.remote.machineSetting': { + 'type': 'string', + 'default': 'isSet', + scope: ConfigurationScope.MACHINE + }, + 'configurationService.remote.testSetting': { + 'type': 'string', + 'default': 'isSet', + scope: ConfigurationScope.RESOURCE + } + } + }); + }); + + setup(() => { + return setUpFolderWorkspace(workspaceName) + .then(({ parentDir, folderDir }) => { + + parentResource = parentDir; + workspaceDir = folderDir; + globalSettingsFile = path.join(parentDir, 'settings.json'); + remoteSettingsFile = path.join(parentDir, 'remote-settings.json'); + + instantiationService = workbenchInstantiationService(); + const environmentService = new TestEnvironmentService(URI.file(parentDir)); + const remoteEnvironmentPromise = new Promise>(c => resolveRemoteEnvironment = () => c({ settingsPath: URI.file(remoteSettingsFile).with({ scheme: Schemas.vscodeRemote, authority: remoteAuthority }) })); + const remoteAgentService = instantiationService.stub(IRemoteAgentService, >{ getEnvironment: () => remoteEnvironmentPromise }); + const fileService = new FileService(new NullLogService()); + fileService.registerProvider(Schemas.file, diskFileSystemProvider); + fileService.registerProvider(Schemas.userData, new FileUserDataProvider(environmentService.appSettingsHome, environmentService.backupHome, diskFileSystemProvider, environmentService)); + const configurationCache: IConfigurationCache = { read: () => Promise.resolve(''), write: () => Promise.resolve(), remove: () => Promise.resolve() }; + testObject = new WorkspaceService({ configurationCache, remoteAuthority }, environmentService, fileService, remoteAgentService); + instantiationService.stub(IWorkspaceContextService, testObject); + instantiationService.stub(IConfigurationService, testObject); + instantiationService.stub(IEnvironmentService, environmentService); + instantiationService.stub(IFileService, fileService); + }); + }); + + async function initialize(): Promise { + await testObject.initialize(convertToWorkspacePayload(URI.file(workspaceDir))); + instantiationService.stub(ITextFileService, instantiationService.createInstance(TestTextFileService)); + instantiationService.stub(ITextModelService, instantiationService.createInstance(TextModelResolverService)); + testObject.acquireInstantiationService(instantiationService); + } + + function registerRemoteFileSystemProvider(): void { + instantiationService.get(IFileService).registerProvider(Schemas.vscodeRemote, new RemoteFileSystemProvider(diskFileSystemProvider, remoteAuthority)); + } + + function registerRemoteFileSystemProviderOnActivation(): void { + const disposable = instantiationService.get(IFileService).onWillActivateFileSystemProvider(e => { + if (e.scheme === Schemas.vscodeRemote) { + disposable.dispose(); + e.join(Promise.resolve().then(() => registerRemoteFileSystemProvider())); + } + }); + } + + teardown(() => { + if (testObject) { + (testObject).dispose(); + } + if (parentResource) { + return pfs.rimraf(parentResource, pfs.RimRafMode.MOVE); + } + return undefined; + }); + + test('remote settings override globals', async () => { + fs.writeFileSync(remoteSettingsFile, '{ "configurationService.remote.machineSetting": "remoteValue" }'); + registerRemoteFileSystemProvider(); + resolveRemoteEnvironment(); + await initialize(); + assert.equal(testObject.getValue('configurationService.remote.machineSetting'), 'remoteValue'); + }); + + test('remote settings override globals after remote provider is registered on activation', async () => { + fs.writeFileSync(remoteSettingsFile, '{ "configurationService.remote.machineSetting": "remoteValue" }'); + resolveRemoteEnvironment(); + registerRemoteFileSystemProviderOnActivation(); + await initialize(); + assert.equal(testObject.getValue('configurationService.remote.machineSetting'), 'remoteValue'); + }); + + test('remote settings override globals after remote environment is resolved', async () => { + fs.writeFileSync(remoteSettingsFile, '{ "configurationService.remote.machineSetting": "remoteValue" }'); + registerRemoteFileSystemProvider(); + await initialize(); + const promise = new Promise((c, e) => { + testObject.onDidChangeConfiguration(event => { + try { + assert.equal(event.source, ConfigurationTarget.USER); + assert.deepEqual(event.affectedKeys, ['configurationService.remote.machineSetting']); + assert.equal(testObject.getValue('configurationService.remote.machineSetting'), 'remoteValue'); + c(); + } catch (error) { + e(error); + } + }); + }); + resolveRemoteEnvironment(); + return promise; + }); + + test('remote settings override globals after remote provider is registered on activation and remote environment is resolved', async () => { + fs.writeFileSync(remoteSettingsFile, '{ "configurationService.remote.machineSetting": "remoteValue" }'); + registerRemoteFileSystemProviderOnActivation(); + await initialize(); + const promise = new Promise((c, e) => { + testObject.onDidChangeConfiguration(event => { + try { + assert.equal(event.source, ConfigurationTarget.USER); + assert.deepEqual(event.affectedKeys, ['configurationService.remote.machineSetting']); + assert.equal(testObject.getValue('configurationService.remote.machineSetting'), 'remoteValue'); + c(); + } catch (error) { + e(error); + } + }); + }); + resolveRemoteEnvironment(); + return promise; + }); + + // test('update remote settings', async () => { + // registerRemoteFileSystemProvider(); + // resolveRemoteEnvironment(); + // await initialize(); + // assert.equal(testObject.getValue('configurationService.remote.machineSetting'), 'isSet'); + // const promise = new Promise((c, e) => { + // testObject.onDidChangeConfiguration(event => { + // try { + // assert.equal(event.source, ConfigurationTarget.USER); + // assert.deepEqual(event.affectedKeys, ['configurationService.remote.machineSetting']); + // assert.equal(testObject.getValue('configurationService.remote.machineSetting'), 'remoteValue'); + // c(); + // } catch (error) { + // e(error); + // } + // }); + // }); + // fs.writeFileSync(remoteSettingsFile, '{ "configurationService.remote.machineSetting": "remoteValue" }'); + // return promise; + // }); + + test('machine settings in local user settings does not override defaults', async () => { + fs.writeFileSync(globalSettingsFile, '{ "configurationService.remote.machineSetting": "globalValue" }'); + registerRemoteFileSystemProvider(); + resolveRemoteEnvironment(); + await initialize(); + assert.equal(testObject.getValue('configurationService.remote.machineSetting'), 'isSet'); + }); + }); function getWorkspaceId(configPath: URI): string { @@ -1424,4 +1630,4 @@ export function getWorkspaceIdentifier(configPath: URI): IWorkspaceIdentifier { configPath, id: getWorkspaceId(configPath) }; -} \ No newline at end of file +} diff --git a/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts b/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts index c9a8760aa..f406a3e0d 100644 --- a/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts +++ b/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts @@ -19,8 +19,9 @@ import { AbstractVariableResolverService } from 'vs/workbench/services/configura import { isCodeEditor } from 'vs/editor/browser/editorBrowser'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { IQuickInputService, IInputOptions, IQuickPickItem, IPickOptions } from 'vs/platform/quickinput/common/quickInput'; -import { ConfiguredInput } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; +import { ConfiguredInput, IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; import { IProcessEnvironment } from 'vs/base/common/platform'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; export abstract class BaseConfigurationResolverService extends AbstractVariableResolverService { @@ -226,6 +227,10 @@ export abstract class BaseConfigurationResolverService extends AbstractVariableR */ private showUserInput(variable: string, inputInfos: ConfiguredInput[]): Promise { + if (!inputInfos) { + return Promise.reject(new Error(nls.localize('inputVariable.noInputSection', "Variable '{0}' must be defined in an '{1}' section of the debug or task configuration.", variable, 'input'))); + } + // find info for the given input variable const info = inputInfos.filter(item => item.id === variable).pop(); if (info) { @@ -304,4 +309,6 @@ export class ConfigurationResolverService extends BaseConfigurationResolverServi ) { super(environmentService.configuration.userEnv, editorService, environmentService, configurationService, commandService, workspaceContextService, quickInputService); } -} \ No newline at end of file +} + +registerSingleton(IConfigurationResolverService, ConfigurationResolverService, true); diff --git a/src/vs/workbench/services/configurationResolver/common/variableResolver.ts b/src/vs/workbench/services/configurationResolver/common/variableResolver.ts index 3d1e2a813..a07fb3a26 100644 --- a/src/vs/workbench/services/configurationResolver/common/variableResolver.ts +++ b/src/vs/workbench/services/configurationResolver/common/variableResolver.ts @@ -35,7 +35,7 @@ export class AbstractVariableResolverService implements IConfigurationResolverSe private _context: IVariableResolveContext, private _envVariables: IProcessEnvironment ) { - if (isWindows) { + if (isWindows && _envVariables) { this._envVariables = Object.create(null); Object.keys(_envVariables).forEach(key => { this._envVariables[key.toLowerCase()] = _envVariables[key]; @@ -237,6 +237,13 @@ export class AbstractVariableResolverService implements IConfigurationResolverSe } return getFilePath(); + case 'relativeFileDirname': + let dirname = paths.dirname(getFilePath()); + if (folderUri) { + return paths.normalize(paths.relative(getFolderUri().fsPath, dirname)); + } + return dirname; + case 'fileDirname': return paths.dirname(getFilePath()); diff --git a/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts b/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts index cefee9701..5b9f44514 100644 --- a/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts +++ b/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts @@ -523,6 +523,7 @@ class MockCommandService implements ICommandService { public callCount = 0; onWillExecuteCommand = () => Disposable.None; + onDidExecuteCommand = () => Disposable.None; public executeCommand(commandId: string, ...args: any[]): Promise { this.callCount++; diff --git a/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts b/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts index f4dae2a33..37d10c4d8 100644 --- a/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts +++ b/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts @@ -3,7 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IAction, IActionRunner, ActionRunner } from 'vs/base/common/actions'; +import { IAction, IActionRunner, ActionRunner, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions'; import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import * as dom from 'vs/base/browser/dom'; import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView'; @@ -66,7 +66,7 @@ class NativeContextMenuService extends Disposable implements IContextMenuService _serviceBrand: any; private _onDidContextMenu = this._register(new Emitter()); - get onDidContextMenu(): Event { return this._onDidContextMenu.event; } + readonly onDidContextMenu: Event = this._onDidContextMenu.event; constructor( @INotificationService private readonly notificationService: INotificationService, @@ -97,7 +97,7 @@ class NativeContextMenuService extends Disposable implements IContextMenuService x = elementPosition.left; y = elementPosition.top + elementPosition.height; } else { - const pos = <{ x: number; y: number; }>anchor; + const pos: { x: number; y: number; } = anchor; x = pos.x + 1; /* prevent first item from being selected automatically under mouse */ y = pos.y; } @@ -115,7 +115,7 @@ class NativeContextMenuService extends Disposable implements IContextMenuService } } - private createMenu(delegate: IContextMenuDelegate, entries: Array, onHide: () => void): IContextMenuItem[] { + private createMenu(delegate: IContextMenuDelegate, entries: ReadonlyArray, onHide: () => void): IContextMenuItem[] { const actionRunner = delegate.actionRunner || new ActionRunner(); return entries.map(entry => this.createMenuItem(delegate, entry, actionRunner, onHide)); @@ -172,19 +172,19 @@ class NativeContextMenuService extends Disposable implements IContextMenuService } } - private runAction(actionRunner: IActionRunner, actionToRun: IAction, delegate: IContextMenuDelegate, event: IContextMenuEvent): void { - /* __GDPR__ - "workbenchActionExecuted" : { - "id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "from": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } - } - */ - this.telemetryService.publicLog('workbenchActionExecuted', { id: actionToRun.id, from: 'contextMenu' }); + private async runAction(actionRunner: IActionRunner, actionToRun: IAction, delegate: IContextMenuDelegate, event: IContextMenuEvent): Promise { + this.telemetryService.publicLog2('workbenchActionExecuted', { id: actionToRun.id, from: 'contextMenu' }); const context = delegate.getActionsContext ? delegate.getActionsContext(event) : event; - const res = actionRunner.run(actionToRun, context) || Promise.resolve(null); - res.then(undefined, e => this.notificationService.error(e)); + const runnable = actionRunner.run(actionToRun, context); + if (runnable) { + try { + await runnable; + } catch (error) { + this.notificationService.error(error); + } + } } } diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index 28e5a9f5f..b183a2629 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -7,7 +7,7 @@ import { URI } from 'vs/base/common/uri'; import { Event, Emitter } from 'vs/base/common/event'; import { IDecorationsService, IDecoration, IResourceDecorationChangeEvent, IDecorationsProvider, IDecorationData } from './decorations'; import { TernarySearchTree } from 'vs/base/common/map'; -import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, toDisposable, dispose } from 'vs/base/common/lifecycle'; import { isThenable } from 'vs/base/common/async'; import { LinkedList } from 'vs/base/common/linkedList'; import { createStyleSheet, createCSSRule, removeCSSRulesContainingSelector } from 'vs/base/browser/dom'; @@ -95,20 +95,20 @@ class DecorationRule { } } -class DecorationStyles { +class DecorationStyles extends Disposable { - 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)]; + super(); + this._register(this._themeService.onThemeChange(this._onThemeChange, this)); } dispose(): void { - dispose(this._disposables); + super.dispose(); const parent = this._styleElement.parentElement; if (parent) { diff --git a/src/vs/workbench/services/dialogs/browser/fileDialogService.ts b/src/vs/workbench/services/dialogs/browser/fileDialogService.ts index 4d50a0b8f..f7d1e6069 100644 --- a/src/vs/workbench/services/dialogs/browser/fileDialogService.ts +++ b/src/vs/workbench/services/dialogs/browser/fileDialogService.ts @@ -85,15 +85,17 @@ export class FileDialogService implements IFileDialogService { } private shouldUseSimplified(schema: string): boolean { - const setting = this.configurationService.getValue('workbench.dialogs.useSimplified'); - return (schema !== Schemas.file) || ((setting === 'true') || (setting === true)); + const setting = this.configurationService.getValue('files.simpleDialog.enable'); + + return (schema !== Schemas.file) || (setting === true); } private ensureFileSchema(schema: string): string[] { - return schema !== Schemas.file ? [schema, Schemas.file] : [schema]; + // Don't allow untitled schema through. + return schema === Schemas.untitled ? [Schemas.file] : (schema !== Schemas.file ? [schema, Schemas.file] : [schema]); } - pickFileFolderAndOpen(options: IPickAndOpenOptions): Promise { + async pickFileFolderAndOpen(options: IPickAndOpenOptions): Promise { const schema = this.getFileSystemSchema(options); if (!options.defaultUri) { @@ -103,21 +105,23 @@ export class FileDialogService implements IFileDialogService { if (this.shouldUseSimplified(schema)) { const title = nls.localize('openFileOrFolder.title', 'Open File Or Folder'); const availableFileSystems = this.ensureFileSchema(schema); // always allow file as well - return this.pickRemoteResource({ canSelectFiles: true, canSelectFolders: true, canSelectMany: false, defaultUri: options.defaultUri, title, availableFileSystems }).then(uri => { - if (uri) { - return (this.fileService.resolve(uri)).then(stat => { - const toOpen: IURIToOpen = stat.isDirectory ? { folderUri: uri } : { fileUri: uri }; - return this.windowService.openWindow([toOpen], { forceNewWindow: options.forceNewWindow }); - }); - } - return undefined; - }); + + const uri = await this.pickRemoteResource({ canSelectFiles: true, canSelectFolders: true, canSelectMany: false, defaultUri: options.defaultUri, title, availableFileSystems }); + + if (uri) { + const stat = await this.fileService.resolve(uri); + + const toOpen: IURIToOpen = stat.isDirectory ? { folderUri: uri } : { fileUri: uri }; + return this.windowService.openWindow([toOpen], { forceNewWindow: options.forceNewWindow }); + } + + return; } return this.windowService.pickFileFolderAndOpen(this.toNativeOpenDialogOptions(options)); } - pickFileAndOpen(options: IPickAndOpenOptions): Promise { + async pickFileAndOpen(options: IPickAndOpenOptions): Promise { const schema = this.getFileSystemSchema(options); if (!options.defaultUri) { @@ -127,18 +131,19 @@ export class FileDialogService implements IFileDialogService { if (this.shouldUseSimplified(schema)) { const title = nls.localize('openFile.title', 'Open File'); const availableFileSystems = this.ensureFileSchema(schema); // always allow file as well - return this.pickRemoteResource({ canSelectFiles: true, canSelectFolders: false, canSelectMany: false, defaultUri: options.defaultUri, title, availableFileSystems }).then(uri => { - if (uri) { - return this.windowService.openWindow([{ fileUri: uri }], { forceNewWindow: options.forceNewWindow }); - } - return undefined; - }); + + const uri = await this.pickRemoteResource({ canSelectFiles: true, canSelectFolders: false, canSelectMany: false, defaultUri: options.defaultUri, title, availableFileSystems }); + if (uri) { + return this.windowService.openWindow([{ fileUri: uri }], { forceNewWindow: options.forceNewWindow }); + } + + return; } return this.windowService.pickFileAndOpen(this.toNativeOpenDialogOptions(options)); } - pickFolderAndOpen(options: IPickAndOpenOptions): Promise { + async pickFolderAndOpen(options: IPickAndOpenOptions): Promise { const schema = this.getFileSystemSchema(options); if (!options.defaultUri) { @@ -148,18 +153,19 @@ export class FileDialogService implements IFileDialogService { if (this.shouldUseSimplified(schema)) { const title = nls.localize('openFolder.title', 'Open Folder'); const availableFileSystems = this.ensureFileSchema(schema); // always allow file as well - return this.pickRemoteResource({ canSelectFiles: false, canSelectFolders: true, canSelectMany: false, defaultUri: options.defaultUri, title, availableFileSystems }).then(uri => { - if (uri) { - return this.windowService.openWindow([{ folderUri: uri }], { forceNewWindow: options.forceNewWindow }); - } - return undefined; - }); + + const uri = await this.pickRemoteResource({ canSelectFiles: false, canSelectFolders: true, canSelectMany: false, defaultUri: options.defaultUri, title, availableFileSystems }); + if (uri) { + return this.windowService.openWindow([{ folderUri: uri }], { forceNewWindow: options.forceNewWindow }); + } + + return; } return this.windowService.pickFolderAndOpen(this.toNativeOpenDialogOptions(options)); } - pickWorkspaceAndOpen(options: IPickAndOpenOptions): Promise { + async pickWorkspaceAndOpen(options: IPickAndOpenOptions): Promise { const schema = this.getFileSystemSchema(options); if (!options.defaultUri) { @@ -170,18 +176,39 @@ export class FileDialogService implements IFileDialogService { const title = nls.localize('openWorkspace.title', 'Open Workspace'); const filters: FileFilter[] = [{ name: nls.localize('filterName.workspace', 'Workspace'), extensions: [WORKSPACE_EXTENSION] }]; const availableFileSystems = this.ensureFileSchema(schema); // always allow file as well - return this.pickRemoteResource({ canSelectFiles: true, canSelectFolders: false, canSelectMany: false, defaultUri: options.defaultUri, title, filters, availableFileSystems }).then(uri => { - if (uri) { - return this.windowService.openWindow([{ workspaceUri: uri }], { forceNewWindow: options.forceNewWindow }); - } - return undefined; - }); + + const uri = await this.pickRemoteResource({ canSelectFiles: true, canSelectFolders: false, canSelectMany: false, defaultUri: options.defaultUri, title, filters, availableFileSystems }); + if (uri) { + return this.windowService.openWindow([{ workspaceUri: uri }], { forceNewWindow: options.forceNewWindow }); + } + + return; } return this.windowService.pickWorkspaceAndOpen(this.toNativeOpenDialogOptions(options)); } + async pickFileToSave(options: ISaveDialogOptions): Promise { + const schema = this.getFileSystemSchema(options); + if (this.shouldUseSimplified(schema)) { + if (!options.availableFileSystems) { + options.availableFileSystems = this.ensureFileSchema(schema); // always allow file as well + } + + options.title = nls.localize('saveFileAs.title', 'Save As'); + return this.saveRemoteResource(options); + } + + const result = await this.windowService.showSaveDialog(this.toNativeSaveDialogOptions(options)); + if (result) { + return URI.file(result); + } + + return; + } + private toNativeSaveDialogOptions(options: ISaveDialogOptions): Electron.SaveDialogOptions { + options.defaultUri = options.defaultUri ? URI.file(options.defaultUri.path) : undefined; return { defaultPath: options.defaultUri && options.defaultUri.fsPath, buttonLabel: options.saveLabel, @@ -190,33 +217,34 @@ export class FileDialogService implements IFileDialogService { }; } - showSaveDialog(options: ISaveDialogOptions): Promise { + async showSaveDialog(options: ISaveDialogOptions): Promise { const schema = this.getFileSystemSchema(options); if (this.shouldUseSimplified(schema)) { if (!options.availableFileSystems) { - options.availableFileSystems = [schema]; // by default only allow saving in the own file system + options.availableFileSystems = this.ensureFileSchema(schema); // always allow file as well } + return this.saveRemoteResource(options); } - return this.windowService.showSaveDialog(this.toNativeSaveDialogOptions(options)).then(result => { - if (result) { - return URI.file(result); - } + const result = await this.windowService.showSaveDialog(this.toNativeSaveDialogOptions(options)); + if (result) { + return URI.file(result); + } - return undefined; - }); + return; } - showOpenDialog(options: IOpenDialogOptions): Promise { + async showOpenDialog(options: IOpenDialogOptions): Promise { const schema = this.getFileSystemSchema(options); if (this.shouldUseSimplified(schema)) { if (!options.availableFileSystems) { - options.availableFileSystems = [schema]; // by default only allow loading in the own file system + options.availableFileSystems = this.ensureFileSchema(schema); // always allow file as well } - return this.pickRemoteResource(options).then(uri => { - return uri ? [uri] : undefined; - }); + + const uri = await this.pickRemoteResource(options); + + return uri ? [uri] : undefined; } const defaultUri = options.defaultUri; @@ -243,27 +271,30 @@ export class FileDialogService implements IFileDialogService { newOptions.properties!.push('multiSelections'); } - return this.windowService.showOpenDialog(newOptions).then(result => result ? result.map(URI.file) : undefined); + const result = await this.windowService.showOpenDialog(newOptions); + + return result ? result.map(URI.file) : undefined; } private pickRemoteResource(options: IOpenDialogOptions): Promise { const remoteFileDialog = this.instantiationService.createInstance(RemoteFileDialog); + return remoteFileDialog.showOpenDialog(options); } private saveRemoteResource(options: ISaveDialogOptions): Promise { const remoteFileDialog = this.instantiationService.createInstance(RemoteFileDialog); + return remoteFileDialog.showSaveDialog(options); } - private getSchemeFilterForWindow() { + private getSchemeFilterForWindow(): string { return !this.environmentService.configuration.remoteAuthority ? Schemas.file : REMOTE_HOST_SCHEME; } private getFileSystemSchema(options: { availableFileSystems?: string[], defaultUri?: URI }): string { - return options.availableFileSystems && options.availableFileSystems[0] || options.defaultUri && options.defaultUri.scheme || this.getSchemeFilterForWindow(); + return options.availableFileSystems && options.availableFileSystems[0] || this.getSchemeFilterForWindow(); } - } function isUntitledWorkspace(path: URI, environmentService: IWorkbenchEnvironmentService): boolean { diff --git a/src/vs/workbench/services/dialogs/browser/remoteFileDialog.ts b/src/vs/workbench/services/dialogs/browser/remoteFileDialog.ts index 2a5d47b85..7c70bf3fe 100644 --- a/src/vs/workbench/services/dialogs/browser/remoteFileDialog.ts +++ b/src/vs/workbench/services/dialogs/browser/remoteFileDialog.ts @@ -22,11 +22,16 @@ import { Schemas } from 'vs/base/common/network'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; -import { RemoteFileDialogContext } from 'vs/workbench/common/contextkeys'; -import { equalsIgnoreCase, format } from 'vs/base/common/strings'; -import { OpenLocalFileAction, OpenLocalFileFolderAction, OpenLocalFolderAction } from 'vs/workbench/browser/actions/workspaceActions'; +import { equalsIgnoreCase, format, startsWithIgnoreCase } from 'vs/base/common/strings'; +import { OpenLocalFileCommand, OpenLocalFileFolderCommand, OpenLocalFolderCommand, SaveLocalFileCommand } from 'vs/workbench/browser/actions/workspaceActions'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment'; +import { isValidBasename } from 'vs/base/common/extpath'; +import { RemoteFileDialogContext } from 'vs/workbench/browser/contextkeys'; +import { Emitter } from 'vs/base/common/event'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { createCancelablePromise, CancelablePromise } from 'vs/base/common/async'; +import { CancellationToken } from 'vs/base/common/cancellation'; interface FileQuickPickItem extends IQuickPickItem { uri: URI; @@ -40,11 +45,6 @@ enum UpdateResult { InvalidPath } -// Reference: https://en.wikipedia.org/wiki/Filename -const WINDOWS_INVALID_FILE_CHARS = /[\\/:\*\?"<>\|]/g; -const UNIX_INVALID_FILE_CHARS = /[\\/]/g; -const WINDOWS_FORBIDDEN_NAMES = /^(con|prn|aux|clock\$|nul|lpt[0-9]|com[0-9])$/i; - export class RemoteFileDialog { private options: IOpenDialogOptions; private currentFolder: URI; @@ -63,6 +63,13 @@ export class RemoteFileDialog { private userHome: URI; private badPath: string | undefined; private remoteAgentEnvironment: IRemoteAgentEnvironment | null; + private separator: string; + private onBusyChangeEmitter = new Emitter(); + private updatingPromise: CancelablePromise | undefined; + + protected disposables: IDisposable[] = [ + this.onBusyChangeEmitter + ]; constructor( @IFileService private readonly fileService: IFileService, @@ -82,8 +89,19 @@ export class RemoteFileDialog { this.contextKey = RemoteFileDialogContext.bindTo(contextKeyService); } + set busy(busy: boolean) { + if (this.filePickBox.busy !== busy) { + this.filePickBox.busy = busy; + this.onBusyChangeEmitter.fire(busy); + } + } + + get busy(): boolean { + return this.filePickBox.busy; + } + public async showOpenDialog(options: IOpenDialogOptions = {}): Promise { - this.scheme = this.getScheme(options.defaultUri, options.availableFileSystems); + this.scheme = this.getScheme(options.availableFileSystems); this.userHome = await this.getUserHome(); const newOptions = await this.getOptions(options); if (!newOptions) { @@ -94,7 +112,7 @@ export class RemoteFileDialog { } public async showSaveDialog(options: ISaveDialogOptions): Promise { - this.scheme = this.getScheme(options.defaultUri, options.availableFileSystems); + this.scheme = this.getScheme(options.availableFileSystems); this.userHome = await this.getUserHome(); this.requiresTrailing = true; const newOptions = await this.getOptions(options, true); @@ -113,9 +131,13 @@ export class RemoteFileDialog { } private getOptions(options: ISaveDialogOptions | IOpenDialogOptions, isSave: boolean = false): IOpenDialogOptions | undefined { - let defaultUri = options.defaultUri; - const filename = (defaultUri && isSave && (resources.dirname(defaultUri).path === '/')) ? resources.basename(defaultUri) : undefined; - if (!defaultUri || filename) { + let defaultUri: URI | undefined = undefined; + let filename: string | undefined = undefined; + if (options.defaultUri) { + defaultUri = (this.scheme === options.defaultUri.scheme) ? options.defaultUri : undefined; + filename = isSave ? resources.basename(options.defaultUri) : undefined; + } + if (!defaultUri) { defaultUri = this.userHome; if (filename) { defaultUri = resources.joinPath(defaultUri, filename); @@ -135,8 +157,8 @@ export class RemoteFileDialog { return resources.toLocalResource(URI.from({ scheme: this.scheme, path }), this.scheme === Schemas.file ? undefined : this.remoteAuthority); } - private getScheme(defaultUri: URI | undefined, available: string[] | undefined): string { - return defaultUri ? defaultUri.scheme : (available ? available[0] : Schemas.file); + private getScheme(available: string[] | undefined): string { + return available ? available[0] : Schemas.file; } private async getRemoteAgentEnvironment(): Promise { @@ -159,6 +181,7 @@ export class RemoteFileDialog { private async pickResource(isSave: boolean = false): Promise { this.allowFolderSelection = !!this.options.canSelectFolders; this.allowFileSelection = !!this.options.canSelectFiles; + this.separator = this.labelService.getSeparator(this.scheme, this.remoteAuthority); this.hidden = false; let homedir: URI = this.options.defaultUri ? this.options.defaultUri : this.workspaceContextService.getWorkspace().folders[0].uri; let stat: IFileStat | undefined; @@ -187,15 +210,20 @@ export class RemoteFileDialog { return new Promise(async (resolve) => { this.filePickBox = this.quickInputService.createQuickPick(); - this.filePickBox.busy = true; + this.busy = true; this.filePickBox.matchOnLabel = false; this.filePickBox.autoFocusOnList = false; this.filePickBox.ignoreFocusOut = true; this.filePickBox.ok = true; - if (this.options && this.options.availableFileSystems && (this.options.availableFileSystems.length > 1)) { + if (this.options && this.options.availableFileSystems && (this.options.availableFileSystems.length > 1) && (this.options.availableFileSystems.indexOf(Schemas.file) > -1)) { this.filePickBox.customButton = true; this.filePickBox.customLabel = nls.localize('remoteFileDialog.local', 'Show Local'); - const action = this.allowFileSelection ? (this.allowFolderSelection ? OpenLocalFileFolderAction : OpenLocalFileAction) : OpenLocalFolderAction; + let action; + if (isSave) { + action = SaveLocalFileCommand; + } else { + action = this.allowFileSelection ? (this.allowFolderSelection ? OpenLocalFileFolderCommand : OpenLocalFileCommand) : OpenLocalFolderCommand; + } const keybinding = this.keybindingService.lookupKeybinding(action.ID); if (keybinding) { const label = keybinding.getLabel(); @@ -205,9 +233,9 @@ export class RemoteFileDialog { } } - let isResolving = false; + let isResolving: number = 0; let isAcceptHandled = false; - this.currentFolder = homedir; + this.currentFolder = resources.dirname(homedir); this.userEnteredPathSegment = ''; this.autoCompletePathSegment = ''; @@ -217,24 +245,27 @@ export class RemoteFileDialog { this.filePickBox.items = []; function doResolve(dialog: RemoteFileDialog, uri: URI | undefined) { + if (uri) { + uri = resources.removeTrailingPathSeparator(uri); + } resolve(uri); dialog.contextKey.set(false); dialog.filePickBox.dispose(); + dispose(dialog.disposables); } this.filePickBox.onDidCustom(() => { - if (isAcceptHandled || this.filePickBox.busy) { + if (isAcceptHandled || this.busy) { return; } isAcceptHandled = true; - isResolving = true; + isResolving++; if (this.options.availableFileSystems && (this.options.availableFileSystems.length > 1)) { this.options.availableFileSystems.shift(); } - this.options.defaultUri = undefined; this.filePickBox.hide(); - if (this.requiresTrailing) { + if (isSave) { return this.fileDialogService.showSaveDialog(this.options).then(result => { doResolve(this, result); }); @@ -245,51 +276,70 @@ export class RemoteFileDialog { } }); - this.filePickBox.onDidAccept(_ => { - if (isAcceptHandled || this.filePickBox.busy) { + function handleAccept(dialog: RemoteFileDialog) { + if (dialog.busy) { + // Save the accept until the file picker is not busy. + dialog.onBusyChangeEmitter.event((busy: boolean) => { + if (!busy) { + handleAccept(dialog); + } + }); + return; + } else if (isAcceptHandled) { return; } isAcceptHandled = true; - isResolving = true; - this.onDidAccept().then(resolveValue => { + isResolving++; + dialog.onDidAccept().then(resolveValue => { if (resolveValue) { - this.filePickBox.hide(); - doResolve(this, resolveValue); - } else if (this.hidden) { - doResolve(this, undefined); + dialog.filePickBox.hide(); + doResolve(dialog, resolveValue); + } else if (dialog.hidden) { + doResolve(dialog, undefined); } else { - isResolving = false; + isResolving--; isAcceptHandled = false; } }); + } + + this.filePickBox.onDidAccept(_ => { + handleAccept(this); }); + this.filePickBox.onDidChangeActive(i => { isAcceptHandled = false; // update input box to match the first selected item - if ((i.length === 1) && this.isChangeFromUser()) { + if ((i.length === 1) && this.isSelectionChangeFromUser()) { this.filePickBox.validationMessage = undefined; - this.setAutoComplete(this.constructFullUserPath(), this.userEnteredPathSegment, i[0], true); + const userPath = this.constructFullUserPath(); + if (!equalsIgnoreCase(this.filePickBox.value.substring(0, userPath.length), userPath)) { + this.filePickBox.valueSelection = [0, this.filePickBox.value.length]; + this.insertText(userPath, userPath); + } + this.setAutoComplete(userPath, this.userEnteredPathSegment, i[0], true); } }); this.filePickBox.onDidChangeValue(async value => { try { // onDidChangeValue can also be triggered by the auto complete, so if it looks like the auto complete, don't do anything - if (this.isChangeFromUser()) { + if (this.isValueChangeFromUser()) { // If the user has just entered more bad path, don't change anything if (!equalsIgnoreCase(value, this.constructFullUserPath()) && !this.isBadSubpath(value)) { this.filePickBox.validationMessage = undefined; - const valueUri = this.remoteUriFrom(this.trimTrailingSlash(this.filePickBox.value)); + const filePickBoxUri = this.filePickBoxValue(); let updated: UpdateResult = UpdateResult.NotUpdated; - if (!resources.isEqual(this.remoteUriFrom(this.trimTrailingSlash(this.pathFromUri(this.currentFolder))), valueUri, true)) { - updated = await this.tryUpdateItems(value, this.remoteUriFrom(this.filePickBox.value)); + if (!resources.isEqual(this.currentFolder, filePickBoxUri, true)) { + updated = await this.tryUpdateItems(value, filePickBoxUri); } if (updated === UpdateResult.NotUpdated) { this.setActiveItems(value); } } else { this.filePickBox.activeItems = []; + this.userEnteredPathSegment = ''; } } } catch { @@ -298,20 +348,20 @@ export class RemoteFileDialog { }); this.filePickBox.onDidHide(() => { this.hidden = true; - if (!isResolving) { + if (isResolving === 0) { doResolve(this, undefined); } }); this.filePickBox.show(); this.contextKey.set(true); - await this.updateItems(homedir, false, this.trailing); + await this.updateItems(homedir, true, this.trailing); if (this.trailing) { this.filePickBox.valueSelection = [this.filePickBox.value.length - this.trailing.length, this.filePickBox.value.length - ext.length]; } else { this.filePickBox.valueSelection = [this.filePickBox.value.length, this.filePickBox.value.length]; } - this.filePickBox.busy = false; + this.busy = false; }); } @@ -319,84 +369,110 @@ export class RemoteFileDialog { return this.badPath && (value.length > this.badPath.length) && equalsIgnoreCase(value.substring(0, this.badPath.length), this.badPath); } - private isChangeFromUser(): boolean { - if (equalsIgnoreCase(this.filePickBox.value, this.pathAppend(this.currentFolder, this.userEnteredPathSegment + this.autoCompletePathSegment)) - && (this.activeItem === (this.filePickBox.activeItems ? this.filePickBox.activeItems[0] : undefined))) { + private isValueChangeFromUser(): boolean { + if (equalsIgnoreCase(this.filePickBox.value, this.pathAppend(this.currentFolder, this.userEnteredPathSegment + this.autoCompletePathSegment))) { return false; } return true; } - private constructFullUserPath(): string { - return this.pathAppend(this.currentFolder, this.userEnteredPathSegment); + private isSelectionChangeFromUser(): boolean { + if (this.activeItem === (this.filePickBox.activeItems ? this.filePickBox.activeItems[0] : undefined)) { + return false; + } + return true; } - private async onDidAccept(): Promise { - this.filePickBox.busy = true; - let resolveValue: URI | undefined; - let navigateValue: URI | undefined; - let inputUri: URI | undefined; - let inputUriDirname: URI | undefined; - let stat: IFileStat | undefined; - let statDirname: IFileStat | undefined; - try { - inputUri = resources.removeTrailingPathSeparator(this.remoteUriFrom(this.filePickBox.value)); - inputUriDirname = resources.dirname(inputUri); - statDirname = await this.fileService.resolve(inputUriDirname); - stat = await this.fileService.resolve(inputUri); - } catch (e) { - // do nothing + private constructFullUserPath(): string { + const currentFolderPath = this.pathFromUri(this.currentFolder); + if (equalsIgnoreCase(this.filePickBox.value.substr(0, this.userEnteredPathSegment.length), this.userEnteredPathSegment) && equalsIgnoreCase(this.filePickBox.value.substr(0, currentFolderPath.length), currentFolderPath)) { + return currentFolderPath; + } else { + return this.pathAppend(this.currentFolder, this.userEnteredPathSegment); } + } - // Find resolve value - if (this.filePickBox.activeItems.length === 0) { - if (!this.requiresTrailing && resources.isEqual(this.currentFolder, inputUri, true)) { - resolveValue = inputUri; - } else if (statDirname && statDirname.isDirectory) { - resolveValue = inputUri; - } else if (stat && stat.isDirectory) { - navigateValue = inputUri; + private filePickBoxValue(): URI { + // The file pick box can't render everything, so we use the current folder to create the uri so that it is an existing path. + const directUri = this.remoteUriFrom(this.filePickBox.value); + const currentPath = this.pathFromUri(this.currentFolder); + if (equalsIgnoreCase(this.filePickBox.value, currentPath)) { + return this.currentFolder; + } + const currentDisplayUri = this.remoteUriFrom(currentPath); + const relativePath = resources.relativePath(currentDisplayUri, directUri); + const isSameRoot = (this.filePickBox.value.length > 1 && currentPath.length > 1) ? equalsIgnoreCase(this.filePickBox.value.substr(0, 2), currentPath.substr(0, 2)) : false; + if (relativePath && isSameRoot) { + let path = resources.joinPath(this.currentFolder, relativePath); + const directBasename = resources.basename(directUri); + if ((directBasename === '.') || (directBasename === '..')) { + path = this.remoteUriFrom(this.pathAppend(path, directBasename)); } - } else if (this.filePickBox.activeItems.length === 1) { + return resources.hasTrailingPathSeparator(directUri) ? resources.addTrailingPathSeparator(path) : path; + } else { + return directUri; + } + } + + private async onDidAccept(): Promise { + this.busy = true; + if (this.filePickBox.activeItems.length === 1) { const item = this.filePickBox.selectedItems[0]; - if (item) { - if (!item.isFolder) { - resolveValue = item.uri; + if (item.isFolder) { + if (this.trailing) { + await this.updateItems(item.uri, true, this.trailing); } else { - navigateValue = item.uri; + // When possible, cause the update to happen by modifying the input box. + // This allows all input box updates to happen first, and uses the same code path as the user typing. + const newPath = this.pathFromUri(item.uri); + if (startsWithIgnoreCase(newPath, this.filePickBox.value) && (equalsIgnoreCase(item.label, resources.basename(item.uri)))) { + this.filePickBox.valueSelection = [this.pathFromUri(this.currentFolder).length, this.filePickBox.value.length]; + this.insertText(newPath, item.label); + } else if ((item.label === '..') && startsWithIgnoreCase(this.filePickBox.value, newPath)) { + this.filePickBox.valueSelection = [newPath.length, this.filePickBox.value.length]; + this.insertText(newPath, ''); + } else { + await this.updateItems(item.uri, true); + } } + this.filePickBox.busy = false; + return; } - } - - - if (navigateValue) { - // Try to navigate into the folder. - await this.updateItems(navigateValue, true, this.trailing); } else { - if (resolveValue) { - resolveValue = this.addPostfix(resolveValue); - } - if (await this.validate(resolveValue)) { + // If the items have updated, don't try to resolve + if ((await this.tryUpdateItems(this.filePickBox.value, this.filePickBoxValue())) !== UpdateResult.NotUpdated) { this.filePickBox.busy = false; - return resolveValue; + return; } } - this.filePickBox.busy = false; + + let resolveValue: URI | undefined; + // Find resolve value + if (this.filePickBox.activeItems.length === 0) { + resolveValue = this.filePickBoxValue(); + } else if (this.filePickBox.activeItems.length === 1) { + resolveValue = this.filePickBox.selectedItems[0].uri; + } + if (resolveValue) { + resolveValue = this.addPostfix(resolveValue); + } + if (await this.validate(resolveValue)) { + this.busy = false; + return resolveValue; + } + this.busy = false; return undefined; } private async tryUpdateItems(value: string, valueUri: URI): Promise { - if (this.filePickBox.busy) { - this.badPath = undefined; - return UpdateResult.Updating; - } else if ((value.length > 0) && ((value[value.length - 1] === '~') || (value[0] === '~'))) { + if ((value.length > 0) && ((value[value.length - 1] === '~') || (value[0] === '~'))) { let newDir = this.userHome; if ((value[0] === '~') && (value.length > 1)) { newDir = resources.joinPath(newDir, value.substring(1)); } await this.updateItems(newDir, true); return UpdateResult.Updated; - } else if (this.endsWithSlash(value) || (!resources.isEqual(this.currentFolder, resources.dirname(valueUri), true) && resources.isEqualOrParent(this.currentFolder, resources.dirname(valueUri), true))) { + } else if (!resources.isEqual(this.currentFolder, valueUri, true) && (this.endsWithSlash(value) || (!resources.isEqual(this.currentFolder, resources.dirname(valueUri), true) && resources.isEqualOrParent(this.currentFolder, resources.dirname(valueUri), true)))) { let stat: IFileStat | undefined; try { stat = await this.fileService.resolve(valueUri); @@ -415,14 +491,14 @@ export class RemoteFileDialog { return UpdateResult.InvalidPath; } else { const inputUriDirname = resources.dirname(valueUri); - if (!resources.isEqual(this.remoteUriFrom(this.trimTrailingSlash(this.pathFromUri(this.currentFolder))), inputUriDirname, true)) { + if (!resources.isEqual(resources.removeTrailingPathSeparator(this.currentFolder), inputUriDirname, true)) { let statWithoutTrailing: IFileStat | undefined; try { statWithoutTrailing = await this.fileService.resolve(inputUriDirname); } catch (e) { // do nothing } - if (statWithoutTrailing && statWithoutTrailing.isDirectory && (resources.basename(valueUri) !== '.')) { + if (statWithoutTrailing && statWithoutTrailing.isDirectory) { await this.updateItems(inputUriDirname, false, resources.basename(valueUri)); this.badPath = undefined; return UpdateResult.Updated; @@ -440,11 +516,13 @@ export class RemoteFileDialog { const userPath = this.constructFullUserPath(); if (equalsIgnoreCase(userPath, value.substring(0, userPath.length))) { let hasMatch = false; - for (let i = 0; i < this.filePickBox.items.length; i++) { - const item = this.filePickBox.items[i]; - if (this.setAutoComplete(value, inputBasename, item)) { - hasMatch = true; - break; + if (inputBasename.length > this.userEnteredPathSegment.length) { + for (let i = 0; i < this.filePickBox.items.length; i++) { + const item = this.filePickBox.items[i]; + if (this.setAutoComplete(value, inputBasename, item)) { + hasMatch = true; + break; + } } } if (!hasMatch) { @@ -453,17 +531,13 @@ export class RemoteFileDialog { this.filePickBox.activeItems = []; } } else { - if (!equalsIgnoreCase(inputBasename, resources.basename(this.currentFolder))) { - this.userEnteredPathSegment = inputBasename; - } else { - this.userEnteredPathSegment = ''; - } + this.userEnteredPathSegment = inputBasename; this.autoCompletePathSegment = ''; } } private setAutoComplete(startingValue: string, startingBasename: string, quickPickItem: FileQuickPickItem, force: boolean = false): boolean { - if (this.filePickBox.busy) { + if (this.busy) { // We're in the middle of something else. Doing an auto complete now can result jumbled or incorrect autocompletes. this.userEnteredPathSegment = startingBasename; this.autoCompletePathSegment = ''; @@ -473,7 +547,7 @@ export class RemoteFileDialog { // Either force the autocomplete, or the old value should be one smaller than the new value and match the new value. if (itemBasename === '..') { // Don't match on the up directory item ever. - this.userEnteredPathSegment = startingValue; + this.userEnteredPathSegment = ''; this.autoCompletePathSegment = ''; this.activeItem = quickPickItem; if (force) { @@ -487,9 +561,6 @@ export class RemoteFileDialog { // Changing the active items will trigger the onDidActiveItemsChanged. Clear the autocomplete first, then set it after. this.autoCompletePathSegment = ''; this.filePickBox.activeItems = [quickPickItem]; - this.autoCompletePathSegment = this.trimTrailingSlash(itemBasename.substr(startingBasename.length)); - this.insertText(startingValue + this.autoCompletePathSegment, this.autoCompletePathSegment); - this.filePickBox.valueSelection = [startingValue.length, this.filePickBox.value.length]; return true; } else if (force && (!equalsIgnoreCase(quickPickItem.label, (this.userEnteredPathSegment + this.autoCompletePathSegment)))) { this.userEnteredPathSegment = ''; @@ -606,7 +677,7 @@ export class RemoteFileDialog { // Show a yes/no prompt const message = nls.localize('remoteFileDialog.validateExisting', '{0} already exists. Are you sure you want to overwrite it?', resources.basename(uri)); return this.yesNoPrompt(uri, message); - } else if (!(await this.isValidBaseName(resources.basename(uri)))) { + } else if (!(isValidBasename(resources.basename(uri), await this.isWindowsOS()))) { // Filename not allowed this.filePickBox.validationMessage = nls.localize('remoteFileDialog.validateBadFilename', 'Please enter a valid file name.'); return Promise.resolve(false); @@ -634,49 +705,57 @@ export class RemoteFileDialog { } private async updateItems(newFolder: URI, force: boolean = false, trailing?: string) { - this.filePickBox.busy = true; + this.busy = true; this.userEnteredPathSegment = trailing ? trailing : ''; this.autoCompletePathSegment = ''; - const newValue = trailing ? this.pathFromUri(resources.joinPath(newFolder, trailing)) : this.pathFromUri(newFolder, true); - const oldFolder = this.currentFolder; - const newFolderPath = this.pathFromUri(newFolder, true); - this.currentFolder = this.remoteUriFrom(newFolderPath); - return this.createItems(this.currentFolder).then(items => { - this.filePickBox.items = items; - if (this.allowFolderSelection) { - this.filePickBox.activeItems = []; - } - if (!equalsIgnoreCase(this.filePickBox.value, newValue)) { - // the user might have continued typing while we were updating. Only update the input box if it doesn't match the directory. - if (!equalsIgnoreCase(this.filePickBox.value.substring(0, newValue.length), newValue)) { + const newValue = trailing ? this.pathAppend(newFolder, trailing) : this.pathFromUri(newFolder, true); + this.currentFolder = resources.addTrailingPathSeparator(newFolder, this.separator); + + const updatingPromise = createCancelablePromise(async token => { + return this.createItems(this.currentFolder, token).then(items => { + if (token.isCancellationRequested) { + this.busy = false; + return; + } + + this.filePickBox.items = items; + if (this.allowFolderSelection) { + this.filePickBox.activeItems = []; + } + // the user might have continued typing while we were updating. Only update the input box if it doesn't matche directory. + if (!equalsIgnoreCase(this.filePickBox.value, newValue) && force) { this.filePickBox.valueSelection = [0, this.filePickBox.value.length]; this.insertText(newValue, newValue); - } else if (force || equalsIgnoreCase(this.pathFromUri(resources.dirname(oldFolder), true), newFolderPath)) { - // This is the case where the user went up one dir or is clicking on dirs. We need to make sure that we remove the final dir. - this.filePickBox.valueSelection = [newFolderPath.length, this.filePickBox.value.length]; - this.insertText(newValue, ''); } - } - if (force && trailing) { - // Keep the cursor position in front of the save as name. - this.filePickBox.valueSelection = [this.filePickBox.value.length - trailing.length, this.filePickBox.value.length - trailing.length]; - } else { - this.filePickBox.valueSelection = [this.filePickBox.value.length, this.filePickBox.value.length]; - } - this.filePickBox.busy = false; + if (force && trailing) { + // Keep the cursor position in front of the save as name. + this.filePickBox.valueSelection = [this.filePickBox.value.length - trailing.length, this.filePickBox.value.length - trailing.length]; + } else if (!trailing) { + // If there is trailing, we don't move the cursor. If there is no trailing, cursor goes at the end. + this.filePickBox.valueSelection = [this.filePickBox.value.length, this.filePickBox.value.length]; + } + this.busy = false; + this.updatingPromise = undefined; + }); }); + + if (this.updatingPromise !== undefined) { + this.updatingPromise.cancel(); + } + this.updatingPromise = updatingPromise; + + return updatingPromise; } private pathFromUri(uri: URI, endWithSeparator: boolean = false): string { - const sep = this.labelService.getSeparator(uri.scheme, uri.authority); - let result: string; - if (sep === '/') { - result = uri.fsPath.replace(/\\/g, sep); + let result: string = uri.fsPath.replace(/\n/g, ''); + if (this.separator === '/') { + result = result.replace(/\\/g, this.separator); } else { - result = uri.fsPath.replace(/\//g, sep); + result = result.replace(/\//g, this.separator); } if (endWithSeparator && !this.endsWithSlash(result)) { - result = result + sep; + result = result + this.separator; } return result; } @@ -684,7 +763,7 @@ export class RemoteFileDialog { private pathAppend(uri: URI, additional: string): string { if ((additional === '..') || (additional === '.')) { const basePath = this.pathFromUri(uri); - return basePath + (this.endsWithSlash(basePath) ? '' : this.labelService.getSeparator(uri.scheme, uri.authority)) + additional; + return basePath + this.separator + additional; } else { return this.pathFromUri(resources.joinPath(uri, additional)); } @@ -699,37 +778,6 @@ export class RemoteFileDialog { return isWindowsOS; } - private async isValidBaseName(name: string): Promise { - if (!name || name.length === 0 || /^\s+$/.test(name)) { - return false; // require a name that is not just whitespace - } - - const isWindowsOS = await this.isWindowsOS(); - const INVALID_FILE_CHARS = isWindowsOS ? WINDOWS_INVALID_FILE_CHARS : UNIX_INVALID_FILE_CHARS; - INVALID_FILE_CHARS.lastIndex = 0; // the holy grail of software development - if (INVALID_FILE_CHARS.test(name)) { - return false; // check for certain invalid file characters - } - - if (isWindowsOS && WINDOWS_FORBIDDEN_NAMES.test(name)) { - return false; // check for certain invalid file names - } - - if (name === '.' || name === '..') { - return false; // check for reserved values - } - - if (isWindowsOS && name[name.length - 1] === '.') { - return false; // Windows: file cannot end with a "." - } - - if (isWindowsOS && name.length !== name.trim().length) { - return false; // Windows: file cannot end with a whitespace - } - - return true; - } - private endsWithSlash(s: string) { return /[\/\\]$/.test(s); } @@ -743,19 +791,19 @@ export class RemoteFileDialog { private createBackItem(currFolder: URI): FileQuickPickItem | null { const parentFolder = resources.dirname(currFolder)!; if (!resources.isEqual(currFolder, parentFolder, true)) { - return { label: '..', uri: resources.dirname(currFolder), isFolder: true }; + return { label: '..', uri: resources.addTrailingPathSeparator(parentFolder, this.separator), isFolder: true }; } return null; } - private async createItems(currentFolder: URI): Promise { + private async createItems(currentFolder: URI, token: CancellationToken): Promise { const result: FileQuickPickItem[] = []; const backDir = this.createBackItem(currentFolder); try { const folder = await this.fileService.resolve(currentFolder); const fileNames = folder.children ? folder.children.map(child => child.name) : []; - const items = await Promise.all(fileNames.map(fileName => this.createItem(fileName, currentFolder))); + const items = await Promise.all(fileNames.map(fileName => this.createItem(fileName, currentFolder, token))); for (let item of items) { if (item) { result.push(item); @@ -765,6 +813,9 @@ export class RemoteFileDialog { // ignore console.log(e); } + if (token.isCancellationRequested) { + return []; + } const sorted = result.sort((i1, i2) => { if (i1.isFolder !== i2.isFolder) { return i1.isFolder ? -1 : 1; @@ -795,12 +846,16 @@ export class RemoteFileDialog { return true; } - private async createItem(filename: string, parent: URI): Promise { + private async createItem(filename: string, parent: URI, token: CancellationToken): Promise { + if (token.isCancellationRequested) { + return undefined; + } let fullPath = resources.joinPath(parent, filename); try { const stat = await this.fileService.resolve(fullPath); if (stat.isDirectory) { filename = this.basenameWithTrailingSlash(fullPath); + fullPath = resources.addTrailingPathSeparator(fullPath, this.separator); return { label: filename, uri: fullPath, isFolder: true, iconClasses: getIconClasses(this.modelService, this.modeService, fullPath || undefined, FileKind.FOLDER) }; } else if (!stat.isDirectory && this.allowFileSelection && this.filterFile(fullPath)) { return { label: filename, uri: fullPath, isFolder: false, iconClasses: getIconClasses(this.modelService, this.modeService, fullPath || undefined) }; diff --git a/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts b/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts index 3a79b9146..02c36b66e 100644 --- a/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts +++ b/src/vs/workbench/services/dialogs/electron-browser/dialogService.ts @@ -78,17 +78,16 @@ class NativeDialogService implements IDialogService { sharedProcessService.registerChannel('dialog', new DialogChannel(this)); } - confirm(confirmation: IConfirmation): Promise { + async confirm(confirmation: IConfirmation): Promise { this.logService.trace('DialogService#confirm', confirmation.message); const { options, buttonIndexMap } = this.massageMessageBoxOptions(this.getConfirmOptions(confirmation)); - return this.windowService.showMessageBox(options).then(result => { - return { - confirmed: buttonIndexMap[result.button] === 0 ? true : false, - checkboxChecked: result.checkboxChecked - }; - }); + const result = await this.windowService.showMessageBox(options); + return { + confirmed: buttonIndexMap[result.button] === 0 ? true : false, + checkboxChecked: result.checkboxChecked + }; } private getConfirmOptions(confirmation: IConfirmation): Electron.MessageBoxOptions { @@ -128,7 +127,7 @@ class NativeDialogService implements IDialogService { return opts; } - show(severity: Severity, message: string, buttons: string[], dialogOptions?: IDialogOptions): Promise { + async show(severity: Severity, message: string, buttons: string[], dialogOptions?: IDialogOptions): Promise { this.logService.trace('DialogService#show', message); const { options, buttonIndexMap } = this.massageMessageBoxOptions({ @@ -139,7 +138,8 @@ class NativeDialogService implements IDialogService { detail: dialogOptions ? dialogOptions.detail : undefined }); - return this.windowService.showMessageBox(options).then(result => buttonIndexMap[result.button]); + const result = await this.windowService.showMessageBox(options); + return buttonIndexMap[result.button]; } private massageMessageBoxOptions(options: Electron.MessageBoxOptions): IMassagedMessageBoxOptions { diff --git a/src/vs/workbench/services/editor/browser/codeEditorService.ts b/src/vs/workbench/services/editor/browser/codeEditorService.ts index fe5bb0a53..86a5d8bcf 100644 --- a/src/vs/workbench/services/editor/browser/codeEditorService.ts +++ b/src/vs/workbench/services/editor/browser/codeEditorService.ts @@ -62,17 +62,16 @@ export class CodeEditorService extends CodeEditorServiceImpl { return this.doOpenCodeEditor(input, source, sideBySide); } - private doOpenCodeEditor(input: IResourceInput, source: ICodeEditor | null, sideBySide?: boolean): Promise { - return this.editorService.openEditor(input, sideBySide ? SIDE_GROUP : ACTIVE_GROUP).then(control => { - if (control) { - const widget = control.getControl(); - if (isCodeEditor(widget)) { - return widget; - } + private async doOpenCodeEditor(input: IResourceInput, source: ICodeEditor | null, sideBySide?: boolean): Promise { + const control = await this.editorService.openEditor(input, sideBySide ? SIDE_GROUP : ACTIVE_GROUP); + if (control) { + const widget = control.getControl(); + if (isCodeEditor(widget)) { + return widget; } + } - return null; - }); + return null; } } diff --git a/src/vs/workbench/services/editor/browser/editorService.ts b/src/vs/workbench/services/editor/browser/editorService.ts index 6969fe759..444045e88 100644 --- a/src/vs/workbench/services/editor/browser/editorService.ts +++ b/src/vs/workbench/services/editor/browser/editorService.ts @@ -21,13 +21,13 @@ import { localize } from 'vs/nls'; import { IEditorGroupsService, IEditorGroup, GroupsOrder, IEditorReplacement, GroupChangeKind, preferredSideBySideGroupDirection } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IResourceEditor, ACTIVE_GROUP_TYPE, SIDE_GROUP_TYPE, SIDE_GROUP, IResourceEditorReplacement, IOpenEditorOverrideHandler, IVisibleEditor, IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { Disposable, IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { coalesce } from 'vs/base/common/arrays'; import { isCodeEditor, isDiffEditor, ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser'; import { IEditorGroupView, IEditorOpeningEvent, EditorServiceImpl } from 'vs/workbench/browser/parts/editor/editor'; import { ILabelService } from 'vs/platform/label/common/label'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types'; +import { withNullAsUndefined } from 'vs/base/common/types'; type ICachedEditorInput = ResourceEditorInput | IFileEditorInput | DataUriEditorInput; @@ -40,16 +40,16 @@ export class EditorService extends Disposable implements EditorServiceImpl { //#region events private readonly _onDidActiveEditorChange: Emitter = this._register(new Emitter()); - get onDidActiveEditorChange(): Event { return this._onDidActiveEditorChange.event; } + readonly onDidActiveEditorChange: Event = this._onDidActiveEditorChange.event; private readonly _onDidVisibleEditorsChange: Emitter = this._register(new Emitter()); - get onDidVisibleEditorsChange(): Event { return this._onDidVisibleEditorsChange.event; } + readonly onDidVisibleEditorsChange: Event = this._onDidVisibleEditorsChange.event; private readonly _onDidCloseEditor: Emitter = this._register(new Emitter()); - get onDidCloseEditor(): Event { return this._onDidCloseEditor.event; } + readonly onDidCloseEditor: Event = this._onDidCloseEditor.event; private readonly _onDidOpenEditorFail: Emitter = this._register(new Emitter()); - get onDidOpenEditorFail(): Event { return this._onDidOpenEditorFail.event; } + readonly onDidOpenEditorFail: Event = this._onDidOpenEditorFail.event; //#endregion @@ -118,29 +118,29 @@ export class EditorService extends Disposable implements EditorServiceImpl { } private registerGroupListeners(group: IEditorGroupView): void { - const groupDisposeables: IDisposable[] = []; + const groupDisposables = new DisposableStore(); - groupDisposeables.push(group.onDidGroupChange(e => { + groupDisposables.add(group.onDidGroupChange(e => { if (e.kind === GroupChangeKind.EDITOR_ACTIVE) { this.handleActiveEditorChange(group); this._onDidVisibleEditorsChange.fire(); } })); - groupDisposeables.push(group.onDidCloseEditor(event => { + groupDisposables.add(group.onDidCloseEditor(event => { this._onDidCloseEditor.fire(event); })); - groupDisposeables.push(group.onWillOpenEditor(event => { + groupDisposables.add(group.onWillOpenEditor(event => { this.onGroupWillOpenEditor(group, event); })); - groupDisposeables.push(group.onDidOpenEditorFail(editor => { + groupDisposables.add(group.onDidOpenEditorFail(editor => { this._onDidOpenEditorFail.fire({ editor, groupId: group.id }); })); Event.once(group.onWillDispose)(() => { - dispose(groupDisposeables); + dispose(groupDisposables); }); } @@ -328,7 +328,7 @@ export class EditorService extends Disposable implements EditorServiceImpl { openEditors(editors: IEditorInputWithOptions[], group?: IEditorGroup | GroupIdentifier | SIDE_GROUP_TYPE | ACTIVE_GROUP_TYPE): Promise; openEditors(editors: IResourceEditor[], group?: IEditorGroup | GroupIdentifier | SIDE_GROUP_TYPE | ACTIVE_GROUP_TYPE): Promise; - openEditors(editors: Array, group?: IEditorGroup | GroupIdentifier | SIDE_GROUP_TYPE | ACTIVE_GROUP_TYPE): Promise { + async openEditors(editors: Array, group?: IEditorGroup | GroupIdentifier | SIDE_GROUP_TYPE | ACTIVE_GROUP_TYPE): Promise { // Convert to typed editors and options const typedEditors: IEditorInputWithOptions[] = []; @@ -364,7 +364,9 @@ export class EditorService extends Disposable implements EditorServiceImpl { result.push(group.openEditors(editorsWithOptions)); }); - return Promise.all(result).then(editors => coalesce(editors)); + const openedEditors = await Promise.all(result); + + return coalesce(openedEditors); } //#endregion @@ -501,7 +503,7 @@ export class EditorService extends Disposable implements EditorServiceImpl { } // Side by Side Support - const resourceSideBySideInput = input; + const resourceSideBySideInput = input as IResourceSideBySideInput; if (resourceSideBySideInput.masterResource && resourceSideBySideInput.detailResource) { const masterInput = this.createInput({ resource: resourceSideBySideInput.masterResource, forceFile: resourceSideBySideInput.forceFile }); const detailInput = this.createInput({ resource: resourceSideBySideInput.detailResource, forceFile: resourceSideBySideInput.forceFile }); @@ -516,36 +518,36 @@ export class EditorService extends Disposable implements EditorServiceImpl { } // Diff Editor Support - const resourceDiffInput = input; + const resourceDiffInput = input as IResourceDiffInput; if (resourceDiffInput.leftResource && resourceDiffInput.rightResource) { const leftInput = this.createInput({ resource: resourceDiffInput.leftResource, forceFile: resourceDiffInput.forceFile }); const rightInput = this.createInput({ resource: resourceDiffInput.rightResource, forceFile: resourceDiffInput.forceFile }); const label = resourceDiffInput.label || localize('compareLabels', "{0} ↔ {1}", this.toDiffLabel(leftInput), this.toDiffLabel(rightInput)); - return new DiffEditorInput(label, withUndefinedAsNull(resourceDiffInput.description), leftInput, rightInput); + return new DiffEditorInput(label, resourceDiffInput.description, leftInput, rightInput); } // Untitled file support - const untitledInput = input; + const untitledInput = input as IUntitledResourceInput; if (untitledInput.forceUntitled || !untitledInput.resource || (untitledInput.resource && untitledInput.resource.scheme === Schemas.untitled)) { - return this.untitledEditorService.createOrGet(untitledInput.resource, untitledInput.language, untitledInput.contents, untitledInput.encoding); + return this.untitledEditorService.createOrGet(untitledInput.resource, untitledInput.mode, untitledInput.contents, untitledInput.encoding); } // Resource Editor Support - const resourceInput = input; + const resourceInput = input as IResourceInput; if (resourceInput.resource instanceof URI) { let label = resourceInput.label; if (!label && resourceInput.resource.scheme !== Schemas.data) { label = basename(resourceInput.resource); // derive the label from the path (but not for data URIs) } - return this.createOrGet(resourceInput.resource, this.instantiationService, label, resourceInput.description, resourceInput.encoding, resourceInput.forceFile) as EditorInput; + return this.createOrGet(resourceInput.resource, this.instantiationService, label, resourceInput.description, resourceInput.encoding, resourceInput.mode, resourceInput.forceFile) as EditorInput; } throw new Error('Unknown input type'); } - private createOrGet(resource: URI, instantiationService: IInstantiationService, label: string | undefined, description: string | undefined, encoding: string | undefined, forceFile: boolean | undefined): ICachedEditorInput { + private createOrGet(resource: URI, instantiationService: IInstantiationService, label: string | undefined, description: string | undefined, encoding: string | undefined, mode: string | undefined, forceFile: boolean | undefined): ICachedEditorInput { if (EditorService.CACHE.has(resource)) { const input = EditorService.CACHE.get(resource)!; if (input instanceof ResourceEditorInput) { @@ -556,10 +558,18 @@ export class EditorService extends Disposable implements EditorServiceImpl { if (description) { input.setDescription(description); } + + if (mode) { + input.setPreferredMode(mode); + } } else if (!(input instanceof DataUriEditorInput)) { if (encoding) { input.setPreferredEncoding(encoding); } + + if (mode) { + input.setPreferredMode(mode); + } } return input; @@ -569,7 +579,7 @@ export class EditorService extends Disposable implements EditorServiceImpl { // File if (forceFile /* fix for https://github.com/Microsoft/vscode/issues/48275 */ || this.fileService.canHandleResource(resource)) { - input = this.fileInputFactory.createFileInput(resource, encoding, instantiationService); + input = this.fileInputFactory.createFileInput(resource, encoding, mode, instantiationService); } // Data URI @@ -579,13 +589,12 @@ export class EditorService extends Disposable implements EditorServiceImpl { // Resource else { - input = instantiationService.createInstance(ResourceEditorInput, label, description, resource); + input = instantiationService.createInstance(ResourceEditorInput, label, description, resource, mode); } + // Add to cache and remove when input gets disposed EditorService.CACHE.set(resource, input); - Event.once(input.onDispose)(() => { - EditorService.CACHE.delete(resource); - }); + Event.once(input.onDispose)(() => EditorService.CACHE.delete(resource)); return input; } @@ -641,18 +650,17 @@ export class DelegatingEditorService extends EditorService { this.editorOpenHandler = handler; } - protected doOpenEditor(group: IEditorGroup, editor: IEditorInput, options?: IEditorOptions): Promise { + protected async doOpenEditor(group: IEditorGroup, editor: IEditorInput, options?: IEditorOptions): Promise { if (!this.editorOpenHandler) { return super.doOpenEditor(group, editor, options); } - return this.editorOpenHandler(group, editor, options).then(control => { - if (control) { - return control; // the opening was handled, so return early - } + const control = await this.editorOpenHandler(group, editor, options); + if (control) { + return control; // the opening was handled, so return early + } - return super.doOpenEditor(group, editor, options); - }); + return super.doOpenEditor(group, editor, options); } } diff --git a/src/vs/workbench/services/editor/common/editorGroupsService.ts b/src/vs/workbench/services/editor/common/editorGroupsService.ts index 91b2ea587..a9ab498cc 100644 --- a/src/vs/workbench/services/editor/common/editorGroupsService.ts +++ b/src/vs/workbench/services/editor/common/editorGroupsService.ts @@ -179,7 +179,7 @@ export interface IEditorGroupsService { /** * The size of the editor groups area. */ - readonly dimension: IDimension; + readonly contentDimension: IDimension; /** * An active group is the default location for new editors to open. @@ -232,12 +232,12 @@ export interface IEditorGroupsService { /** * Returns the size of a group. */ - getSize(group: IEditorGroup | GroupIdentifier): number; + getSize(group: IEditorGroup | GroupIdentifier): { width: number, height: number }; /** * Sets the size of a group. */ - setSize(group: IEditorGroup | GroupIdentifier, size: number): void; + setSize(group: IEditorGroup | GroupIdentifier, size: { width: number, height: number }): void; /** * Arrange all groups according to the provided arrangement. @@ -411,7 +411,7 @@ export interface IEditorGroup { /** * Returns the editor at a specific index of the group. */ - getEditor(index: number): IEditorInput | null; + getEditor(index: number): IEditorInput | undefined; /** * Get all editors that are currently opened in the group optionally diff --git a/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts b/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts index 0fe83803a..477fdfc5b 100644 --- a/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorGroupsService.test.ts @@ -24,10 +24,10 @@ export class TestEditorControl extends BaseEditor { constructor(@ITelemetryService telemetryService: ITelemetryService) { super('MyFileEditorForEditorGroupService', NullTelemetryService, new TestThemeService(), new TestStorageService()); } - setInput(input: EditorInput, options: EditorOptions, token: CancellationToken): Promise { + async setInput(input: EditorInput, options: EditorOptions, token: CancellationToken): Promise { super.setInput(input, options, token); - return input.resolve().then(() => undefined); + await input.resolve(); } getId(): string { return 'MyFileEditorForEditorGroupService'; } @@ -45,11 +45,13 @@ export class TestEditorInput extends EditorInput implements IFileEditorInput { setEncoding(encoding: string) { } getEncoding(): string { return null!; } setPreferredEncoding(encoding: string) { } + setMode(mode: string) { } + setPreferredMode(mode: string) { } getResource(): URI { return this.resource; } setForceOpenAsBinary(): void { } } -suite('Editor groups service', () => { +suite('EditorGroupsService', () => { function registerTestEditorInput(): void { @@ -78,7 +80,7 @@ suite('Editor groups service', () => { } (Registry.as(EditorExtensions.EditorInputFactories)).registerEditorInputFactory('testEditorInputForGroupsService', TestEditorInputFactory); - (Registry.as(Extensions.Editors)).registerEditor(new EditorDescriptor(TestEditorControl, 'MyTestEditorForGroupsService', 'My Test File Editor'), new SyncDescriptor(TestEditorInput)); + (Registry.as(Extensions.Editors)).registerEditor(new EditorDescriptor(TestEditorControl, 'MyTestEditorForGroupsService', 'My Test File Editor'), [new SyncDescriptor(TestEditorInput)]); } registerTestEditorInput(); @@ -116,11 +118,6 @@ suite('Editor groups service', () => { groupMovedCounter++; }); - let preferredSizeChangeCounter = 0; - const preferredSizeChangeListener = part.onDidPreferredSizeChange(() => { - preferredSizeChangeCounter++; - }); - // always a root group const rootGroup = part.groups[0]; assert.equal(part.groups.length, 1); @@ -139,7 +136,6 @@ suite('Editor groups service', () => { assert.equal(part.groups.length, 2); assert.equal(part.count, 2); assert.ok(part.activeGroup === rootGroup); - assert.equal(preferredSizeChangeCounter, 1); assert.equal(rootGroup.label, 'Group 1'); assert.equal(rightGroup.label, 'Group 2'); @@ -187,7 +183,6 @@ suite('Editor groups service', () => { assert.equal(part.groups.length, 3); assert.ok(part.activeGroup === rightGroup); assert.ok(!downGroup.activeControl); - assert.equal(preferredSizeChangeCounter, 2); assert.equal(rootGroup.label, 'Group 1'); assert.equal(rightGroup.label, 'Group 2'); assert.equal(downGroup.label, 'Group 3'); @@ -206,13 +201,11 @@ suite('Editor groups service', () => { part.moveGroup(downGroup, rightGroup, GroupDirection.DOWN); assert.equal(groupMovedCounter, 1); - assert.equal(preferredSizeChangeCounter, 2); part.removeGroup(downGroup); assert.ok(!part.getGroup(downGroup.id)); assert.equal(didDispose, true); assert.equal(groupRemovedCounter, 1); - assert.equal(preferredSizeChangeCounter, 3); assert.equal(part.groups.length, 2); assert.ok(part.activeGroup === rightGroup); assert.equal(rootGroup.label, 'Group 1'); @@ -252,13 +245,11 @@ suite('Editor groups service', () => { assert.ok(part.activeGroup === rootGroup); part.setGroupOrientation(part.orientation === GroupOrientation.HORIZONTAL ? GroupOrientation.VERTICAL : GroupOrientation.HORIZONTAL); - assert.equal(preferredSizeChangeCounter, 5); activeGroupChangeListener.dispose(); groupAddedListener.dispose(); groupRemovedListener.dispose(); groupMovedListener.dispose(); - preferredSizeChangeListener.dispose(); part.dispose(); }); @@ -291,7 +282,7 @@ suite('Editor groups service', () => { part.dispose(); }); - test('copy/merge groups', function () { + test('copy/merge groups', async () => { const part = createPart(); let groupAddedCounter = 0; @@ -312,40 +303,32 @@ suite('Editor groups service', () => { const input = new TestEditorInput(URI.file('foo/bar')); - return rootGroup.openEditor(input, EditorOptions.create({ pinned: true })).then(() => { - const rightGroup = part.addGroup(rootGroup, GroupDirection.RIGHT, { activate: true }); - const downGroup = part.copyGroup(rootGroup, rightGroup, GroupDirection.DOWN); - - assert.equal(groupAddedCounter, 2); - assert.equal(downGroup.count, 1); - assert.ok(downGroup.activeEditor instanceof TestEditorInput); - - part.mergeGroup(rootGroup, rightGroup, { mode: MergeGroupMode.COPY_EDITORS }); - assert.equal(rightGroup.count, 1); - assert.ok(rightGroup.activeEditor instanceof TestEditorInput); - - part.mergeGroup(rootGroup, rightGroup, { mode: MergeGroupMode.MOVE_EDITORS }); - assert.equal(rootGroup.count, 0); - - part.mergeGroup(rootGroup, downGroup); - assert.equal(groupRemovedCounter, 1); - assert.equal(rootGroupDisposed, true); - - groupAddedListener.dispose(); - groupRemovedListener.dispose(); - disposeListener.dispose(); - - part.dispose(); - }); + await rootGroup.openEditor(input, EditorOptions.create({ pinned: true })); + const rightGroup = part.addGroup(rootGroup, GroupDirection.RIGHT, { activate: true }); + const downGroup = part.copyGroup(rootGroup, rightGroup, GroupDirection.DOWN); + assert.equal(groupAddedCounter, 2); + assert.equal(downGroup.count, 1); + assert.ok(downGroup.activeEditor instanceof TestEditorInput); + part.mergeGroup(rootGroup, rightGroup, { mode: MergeGroupMode.COPY_EDITORS }); + assert.equal(rightGroup.count, 1); + assert.ok(rightGroup.activeEditor instanceof TestEditorInput); + part.mergeGroup(rootGroup, rightGroup, { mode: MergeGroupMode.MOVE_EDITORS }); + assert.equal(rootGroup.count, 0); + part.mergeGroup(rootGroup, downGroup); + assert.equal(groupRemovedCounter, 1); + assert.equal(rootGroupDisposed, true); + groupAddedListener.dispose(); + groupRemovedListener.dispose(); + disposeListener.dispose(); + part.dispose(); }); - test('whenRestored', () => { + test('whenRestored', async () => { const part = createPart(); - return part.whenRestored.then(() => { - assert.ok(true); - part.dispose(); - }); + await part.whenRestored; + assert.ok(true); + part.dispose(); }); test('options', () => { @@ -467,7 +450,7 @@ suite('Editor groups service', () => { part.dispose(); }); - test('openEditors / closeEditors', function () { + test('openEditors / closeEditors', async () => { const part = createPart(); const group = part.activeGroup; assert.equal(group.isEmpty(), true); @@ -475,20 +458,17 @@ suite('Editor groups service', () => { const input = new TestEditorInput(URI.file('foo/bar')); const inputInactive = new TestEditorInput(URI.file('foo/bar/inactive')); - return group.openEditors([{ editor: input, options: { pinned: true } }, { editor: inputInactive }]).then(() => { - assert.equal(group.count, 2); - assert.equal(group.getEditor(0), input); - assert.equal(group.getEditor(1), inputInactive); - - return group.closeEditors([input, inputInactive]).then(() => { - assert.equal(group.isEmpty(), true); + await group.openEditors([{ editor: input, options: { pinned: true } }, { editor: inputInactive }]); + assert.equal(group.count, 2); + assert.equal(group.getEditor(0), input); + assert.equal(group.getEditor(1), inputInactive); - part.dispose(); - }); - }); + await group.closeEditors([input, inputInactive]); + assert.equal(group.isEmpty(), true); + part.dispose(); }); - test('closeEditors (except one)', function () { + test('closeEditors (except one)', async () => { const part = createPart(); const group = part.activeGroup; assert.equal(group.isEmpty(), true); @@ -497,22 +477,19 @@ suite('Editor groups service', () => { const input2 = new TestEditorInput(URI.file('foo/bar2')); const input3 = new TestEditorInput(URI.file('foo/bar3')); - return group.openEditors([{ editor: input1, options: { pinned: true } }, { editor: input2, options: { pinned: true } }, { editor: input3 }]).then(() => { - assert.equal(group.count, 3); - assert.equal(group.getEditor(0), input1); - assert.equal(group.getEditor(1), input2); - assert.equal(group.getEditor(2), input3); - - return group.closeEditors({ except: input2 }).then(() => { - assert.equal(group.count, 1); - assert.equal(group.getEditor(0), input2); + await group.openEditors([{ editor: input1, options: { pinned: true } }, { editor: input2, options: { pinned: true } }, { editor: input3 }]); + assert.equal(group.count, 3); + assert.equal(group.getEditor(0), input1); + assert.equal(group.getEditor(1), input2); + assert.equal(group.getEditor(2), input3); - part.dispose(); - }); - }); + await group.closeEditors({ except: input2 }); + assert.equal(group.count, 1); + assert.equal(group.getEditor(0), input2); + part.dispose(); }); - test('closeEditors (saved only)', function () { + test('closeEditors (saved only)', async () => { const part = createPart(); const group = part.activeGroup; assert.equal(group.isEmpty(), true); @@ -521,21 +498,18 @@ suite('Editor groups service', () => { const input2 = new TestEditorInput(URI.file('foo/bar2')); const input3 = new TestEditorInput(URI.file('foo/bar3')); - return group.openEditors([{ editor: input1, options: { pinned: true } }, { editor: input2, options: { pinned: true } }, { editor: input3 }]).then(() => { - assert.equal(group.count, 3); - assert.equal(group.getEditor(0), input1); - assert.equal(group.getEditor(1), input2); - assert.equal(group.getEditor(2), input3); - - return group.closeEditors({ savedOnly: true }).then(() => { - assert.equal(group.count, 0); + await group.openEditors([{ editor: input1, options: { pinned: true } }, { editor: input2, options: { pinned: true } }, { editor: input3 }]); + assert.equal(group.count, 3); + assert.equal(group.getEditor(0), input1); + assert.equal(group.getEditor(1), input2); + assert.equal(group.getEditor(2), input3); - part.dispose(); - }); - }); + await group.closeEditors({ savedOnly: true }); + assert.equal(group.count, 0); + part.dispose(); }); - test('closeEditors (direction: right)', function () { + test('closeEditors (direction: right)', async () => { const part = createPart(); const group = part.activeGroup; assert.equal(group.isEmpty(), true); @@ -544,23 +518,20 @@ suite('Editor groups service', () => { const input2 = new TestEditorInput(URI.file('foo/bar2')); const input3 = new TestEditorInput(URI.file('foo/bar3')); - return group.openEditors([{ editor: input1, options: { pinned: true } }, { editor: input2, options: { pinned: true } }, { editor: input3 }]).then(() => { - assert.equal(group.count, 3); - assert.equal(group.getEditor(0), input1); - assert.equal(group.getEditor(1), input2); - assert.equal(group.getEditor(2), input3); + await group.openEditors([{ editor: input1, options: { pinned: true } }, { editor: input2, options: { pinned: true } }, { editor: input3 }]); + assert.equal(group.count, 3); + assert.equal(group.getEditor(0), input1); + assert.equal(group.getEditor(1), input2); + assert.equal(group.getEditor(2), input3); - return group.closeEditors({ direction: CloseDirection.RIGHT, except: input2 }).then(() => { - assert.equal(group.count, 2); - assert.equal(group.getEditor(0), input1); - assert.equal(group.getEditor(1), input2); - - part.dispose(); - }); - }); + await group.closeEditors({ direction: CloseDirection.RIGHT, except: input2 }); + assert.equal(group.count, 2); + assert.equal(group.getEditor(0), input1); + assert.equal(group.getEditor(1), input2); + part.dispose(); }); - test('closeEditors (direction: left)', function () { + test('closeEditors (direction: left)', async () => { const part = createPart(); const group = part.activeGroup; assert.equal(group.isEmpty(), true); @@ -569,23 +540,20 @@ suite('Editor groups service', () => { const input2 = new TestEditorInput(URI.file('foo/bar2')); const input3 = new TestEditorInput(URI.file('foo/bar3')); - return group.openEditors([{ editor: input1, options: { pinned: true } }, { editor: input2, options: { pinned: true } }, { editor: input3 }]).then(() => { - assert.equal(group.count, 3); - assert.equal(group.getEditor(0), input1); - assert.equal(group.getEditor(1), input2); - assert.equal(group.getEditor(2), input3); - - return group.closeEditors({ direction: CloseDirection.LEFT, except: input2 }).then(() => { - assert.equal(group.count, 2); - assert.equal(group.getEditor(0), input2); - assert.equal(group.getEditor(1), input3); + await group.openEditors([{ editor: input1, options: { pinned: true } }, { editor: input2, options: { pinned: true } }, { editor: input3 }]); + assert.equal(group.count, 3); + assert.equal(group.getEditor(0), input1); + assert.equal(group.getEditor(1), input2); + assert.equal(group.getEditor(2), input3); - part.dispose(); - }); - }); + await group.closeEditors({ direction: CloseDirection.LEFT, except: input2 }); + assert.equal(group.count, 2); + assert.equal(group.getEditor(0), input2); + assert.equal(group.getEditor(1), input3); + part.dispose(); }); - test('closeAllEditors', () => { + test('closeAllEditors', async () => { const part = createPart(); const group = part.activeGroup; assert.equal(group.isEmpty(), true); @@ -593,20 +561,17 @@ suite('Editor groups service', () => { const input = new TestEditorInput(URI.file('foo/bar')); const inputInactive = new TestEditorInput(URI.file('foo/bar/inactive')); - return group.openEditors([{ editor: input, options: { pinned: true } }, { editor: inputInactive }]).then(() => { - assert.equal(group.count, 2); - assert.equal(group.getEditor(0), input); - assert.equal(group.getEditor(1), inputInactive); - - return group.closeAllEditors().then(() => { - assert.equal(group.isEmpty(), true); + await group.openEditors([{ editor: input, options: { pinned: true } }, { editor: inputInactive }]); + assert.equal(group.count, 2); + assert.equal(group.getEditor(0), input); + assert.equal(group.getEditor(1), inputInactive); - part.dispose(); - }); - }); + await group.closeAllEditors(); + assert.equal(group.isEmpty(), true); + part.dispose(); }); - test('moveEditor (same group)', function () { + test('moveEditor (same group)', async () => { const part = createPart(); const group = part.activeGroup; assert.equal(group.isEmpty(), true); @@ -622,22 +587,19 @@ suite('Editor groups service', () => { } }); - return group.openEditors([{ editor: input, options: { pinned: true } }, { editor: inputInactive }]).then(() => { - assert.equal(group.count, 2); - assert.equal(group.getEditor(0), input); - assert.equal(group.getEditor(1), inputInactive); - - group.moveEditor(inputInactive, group, { index: 0 }); - assert.equal(editorMoveCounter, 1); - assert.equal(group.getEditor(0), inputInactive); - assert.equal(group.getEditor(1), input); - - editorGroupChangeListener.dispose(); - part.dispose(); - }); + await group.openEditors([{ editor: input, options: { pinned: true } }, { editor: inputInactive }]); + assert.equal(group.count, 2); + assert.equal(group.getEditor(0), input); + assert.equal(group.getEditor(1), inputInactive); + group.moveEditor(inputInactive, group, { index: 0 }); + assert.equal(editorMoveCounter, 1); + assert.equal(group.getEditor(0), inputInactive); + assert.equal(group.getEditor(1), input); + editorGroupChangeListener.dispose(); + part.dispose(); }); - test('moveEditor (across groups)', function () { + test('moveEditor (across groups)', async () => { const part = createPart(); const group = part.activeGroup; assert.equal(group.isEmpty(), true); @@ -647,23 +609,19 @@ suite('Editor groups service', () => { const input = new TestEditorInput(URI.file('foo/bar')); const inputInactive = new TestEditorInput(URI.file('foo/bar/inactive')); - return group.openEditors([{ editor: input, options: { pinned: true } }, { editor: inputInactive }]).then(() => { - assert.equal(group.count, 2); - assert.equal(group.getEditor(0), input); - assert.equal(group.getEditor(1), inputInactive); - - group.moveEditor(inputInactive, rightGroup, { index: 0 }); - assert.equal(group.count, 1); - assert.equal(group.getEditor(0), input); - - assert.equal(rightGroup.count, 1); - assert.equal(rightGroup.getEditor(0), inputInactive); - - part.dispose(); - }); + await group.openEditors([{ editor: input, options: { pinned: true } }, { editor: inputInactive }]); + assert.equal(group.count, 2); + assert.equal(group.getEditor(0), input); + assert.equal(group.getEditor(1), inputInactive); + group.moveEditor(inputInactive, rightGroup, { index: 0 }); + assert.equal(group.count, 1); + assert.equal(group.getEditor(0), input); + assert.equal(rightGroup.count, 1); + assert.equal(rightGroup.getEditor(0), inputInactive); + part.dispose(); }); - test('copyEditor (across groups)', function () { + test('copyEditor (across groups)', async () => { const part = createPart(); const group = part.activeGroup; assert.equal(group.isEmpty(), true); @@ -673,24 +631,20 @@ suite('Editor groups service', () => { const input = new TestEditorInput(URI.file('foo/bar')); const inputInactive = new TestEditorInput(URI.file('foo/bar/inactive')); - return group.openEditors([{ editor: input, options: { pinned: true } }, { editor: inputInactive }]).then(() => { - assert.equal(group.count, 2); - assert.equal(group.getEditor(0), input); - assert.equal(group.getEditor(1), inputInactive); - - group.copyEditor(inputInactive, rightGroup, { index: 0 }); - assert.equal(group.count, 2); - assert.equal(group.getEditor(0), input); - assert.equal(group.getEditor(1), inputInactive); - - assert.equal(rightGroup.count, 1); - assert.equal(rightGroup.getEditor(0), inputInactive); - - part.dispose(); - }); + await group.openEditors([{ editor: input, options: { pinned: true } }, { editor: inputInactive }]); + assert.equal(group.count, 2); + assert.equal(group.getEditor(0), input); + assert.equal(group.getEditor(1), inputInactive); + group.copyEditor(inputInactive, rightGroup, { index: 0 }); + assert.equal(group.count, 2); + assert.equal(group.getEditor(0), input); + assert.equal(group.getEditor(1), inputInactive); + assert.equal(rightGroup.count, 1); + assert.equal(rightGroup.getEditor(0), inputInactive); + part.dispose(); }); - test('replaceEditors', () => { + test('replaceEditors', async () => { const part = createPart(); const group = part.activeGroup; assert.equal(group.isEmpty(), true); @@ -698,17 +652,14 @@ suite('Editor groups service', () => { const input = new TestEditorInput(URI.file('foo/bar')); const inputInactive = new TestEditorInput(URI.file('foo/bar/inactive')); - return group.openEditor(input).then(() => { - assert.equal(group.count, 1); - assert.equal(group.getEditor(0), input); - - return group.replaceEditors([{ editor: input, replacement: inputInactive }]).then(() => { - assert.equal(group.count, 1); - assert.equal(group.getEditor(0), inputInactive); + await group.openEditor(input); + assert.equal(group.count, 1); + assert.equal(group.getEditor(0), input); - part.dispose(); - }); - }); + await group.replaceEditors([{ editor: input, replacement: inputInactive }]); + assert.equal(group.count, 1); + assert.equal(group.getEditor(0), inputInactive); + part.dispose(); }); test('find neighbour group (left/right)', function () { 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 a670ff43a..913a95d4a 100644 --- a/src/vs/workbench/services/editor/test/browser/editorService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorService.test.ts @@ -8,7 +8,7 @@ import { IEditorModel } from 'vs/platform/editor/common/editor'; import { URI } from 'vs/base/common/uri'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { EditorInput, EditorOptions, IFileEditorInput, IEditorInput } from 'vs/workbench/common/editor'; -import { workbenchInstantiationService, TestStorageService, NullFileSystemProvider } from 'vs/workbench/test/workbenchTestServices'; +import { workbenchInstantiationService, TestStorageService } from 'vs/workbench/test/workbenchTestServices'; import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput'; import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService'; import { EditorService, DelegatingEditorService } from 'vs/workbench/services/editor/browser/editorService'; @@ -29,15 +29,18 @@ import { timeout } from 'vs/base/common/async'; import { toResource } from 'vs/base/test/common/utils'; import { IFileService } from 'vs/platform/files/common/files'; import { Disposable } from 'vs/base/common/lifecycle'; +import { ModesRegistry } from 'vs/editor/common/modes/modesRegistry'; +import { UntitledEditorModel } from 'vs/workbench/common/editor/untitledEditorModel'; +import { NullFileSystemProvider } from 'vs/platform/files/test/common/nullFileSystemProvider'; export class TestEditorControl extends BaseEditor { constructor(@ITelemetryService telemetryService: ITelemetryService) { super('MyTestEditorForEditorService', NullTelemetryService, new TestThemeService(), new TestStorageService()); } - setInput(input: EditorInput, options: EditorOptions, token: CancellationToken): Promise { + async setInput(input: EditorInput, options: EditorOptions, token: CancellationToken): Promise { super.setInput(input, options, token); - return input.resolve().then(() => undefined); + await input.resolve(); } getId(): string { return 'MyTestEditorForEditorService'; } @@ -56,6 +59,8 @@ export class TestEditorInput extends EditorInput implements IFileEditorInput { setEncoding(encoding: string) { } getEncoding(): string { return null!; } setPreferredEncoding(encoding: string) { } + setMode(mode: string) { } + setPreferredMode(mode: string) { } getResource(): URI { return this.resource; } setForceOpenAsBinary(): void { } setFailToOpen(): void { @@ -75,15 +80,15 @@ class FileServiceProvider extends Disposable { } } -suite('Editor service', () => { +suite('EditorService', () => { function registerTestEditorInput(): void { - Registry.as(Extensions.Editors).registerEditor(new EditorDescriptor(TestEditorControl, 'MyTestEditorForEditorService', 'My Test Editor For Next Editor Service'), new SyncDescriptor(TestEditorInput)); + Registry.as(Extensions.Editors).registerEditor(new EditorDescriptor(TestEditorControl, 'MyTestEditorForEditorService', 'My Test Editor For Next Editor Service'), [new SyncDescriptor(TestEditorInput)]); } registerTestEditorInput(); - test('basics', function () { + test('basics', async () => { const partInstantiator = workbenchInstantiationService(); const part = partInstantiator.createInstance(EditorPart); @@ -112,51 +117,49 @@ suite('Editor service', () => { didCloseEditorListenerCounter++; }); - return part.whenRestored.then(() => { - - // Open input - return service.openEditor(input, { pinned: true }).then(editor => { - assert.ok(editor instanceof TestEditorControl); - assert.equal(editor, service.activeControl); - assert.equal(input, service.activeEditor); - assert.equal(service.visibleControls.length, 1); - assert.equal(service.visibleControls[0], editor); - assert.ok(!service.activeTextEditorWidget); - assert.equal(service.visibleTextEditorWidgets.length, 0); - assert.equal(service.isOpen(input), true); - assert.equal(service.getOpened({ resource: input.getResource() }), input); - assert.equal(service.isOpen(input, part.activeGroup), true); - assert.equal(activeEditorChangeEventCounter, 1); - assert.equal(visibleEditorChangeEventCounter, 1); - - // Close input - return editor!.group!.closeEditor(input).then(() => { - assert.equal(didCloseEditorListenerCounter, 1); - assert.equal(activeEditorChangeEventCounter, 2); - assert.equal(visibleEditorChangeEventCounter, 2); - assert.ok(input.gotDisposed); - - // Open again 2 inputs - return service.openEditor(input, { pinned: true }).then(editor => { - return service.openEditor(otherInput, { pinned: true }).then(editor => { - assert.equal(service.visibleControls.length, 1); - assert.equal(service.isOpen(input), true); - assert.equal(service.isOpen(otherInput), true); - - assert.equal(activeEditorChangeEventCounter, 4); - assert.equal(visibleEditorChangeEventCounter, 4); - - activeEditorChangeListener.dispose(); - visibleEditorChangeListener.dispose(); - didCloseEditorListener.dispose(); - }); - }); - }); - }); - }); + await part.whenRestored; + + // Open input + let editor = await service.openEditor(input, { pinned: true }); + + assert.ok(editor instanceof TestEditorControl); + assert.equal(editor, service.activeControl); + assert.equal(input, service.activeEditor); + assert.equal(service.visibleControls.length, 1); + assert.equal(service.visibleControls[0], editor); + assert.ok(!service.activeTextEditorWidget); + assert.equal(service.visibleTextEditorWidgets.length, 0); + assert.equal(service.isOpen(input), true); + assert.equal(service.getOpened({ resource: input.getResource() }), input); + assert.equal(service.isOpen(input, part.activeGroup), true); + assert.equal(activeEditorChangeEventCounter, 1); + assert.equal(visibleEditorChangeEventCounter, 1); + + // Close input + await editor!.group!.closeEditor(input); + + assert.equal(didCloseEditorListenerCounter, 1); + assert.equal(activeEditorChangeEventCounter, 2); + assert.equal(visibleEditorChangeEventCounter, 2); + assert.ok(input.gotDisposed); + + // Open again 2 inputs + await service.openEditor(input, { pinned: true }); + editor = await service.openEditor(otherInput, { pinned: true }); + + assert.equal(service.visibleControls.length, 1); + assert.equal(service.isOpen(input), true); + assert.equal(service.isOpen(otherInput), true); + + assert.equal(activeEditorChangeEventCounter, 4); + assert.equal(visibleEditorChangeEventCounter, 4); + + activeEditorChangeListener.dispose(); + visibleEditorChangeListener.dispose(); + didCloseEditorListener.dispose(); }); - test('openEditors() / replaceEditors()', function () { + test('openEditors() / replaceEditors()', async () => { const partInstantiator = workbenchInstantiationService(); const part = partInstantiator.createInstance(EditorPart); @@ -171,18 +174,16 @@ suite('Editor service', () => { const otherInput = testInstantiationService.createInstance(TestEditorInput, URI.parse('my://resource2-openEditors')); const replaceInput = testInstantiationService.createInstance(TestEditorInput, URI.parse('my://resource3-openEditors')); - return part.whenRestored.then(() => { + await part.whenRestored; - // Open editors - return service.openEditors([{ editor: input }, { editor: otherInput }]).then(() => { - assert.equal(part.activeGroup.count, 2); + // Open editors + await service.openEditors([{ editor: input }, { editor: otherInput }]); + assert.equal(part.activeGroup.count, 2); - return service.replaceEditors([{ editor: input, replacement: replaceInput }], part.activeGroup).then(() => { - assert.equal(part.activeGroup.count, 2); - assert.equal(part.activeGroup.getIndexOfEditor(replaceInput), 0); - }); - }); - }); + // Replace editors + await service.replaceEditors([{ editor: input, replacement: replaceInput }], part.activeGroup); + assert.equal(part.activeGroup.count, 2); + assert.equal(part.activeGroup.getIndexOfEditor(replaceInput), 0); }); test('caching', function () { @@ -234,10 +235,15 @@ suite('Editor service', () => { assert.ok(!input1AgainAndAgain!.isDisposed()); }); - test('createInput', function () { + test('createInput', async function () { const instantiationService = workbenchInstantiationService(); const service: EditorService = instantiationService.createInstance(EditorService); + const mode = 'create-input-test'; + ModesRegistry.registerLanguage({ + id: mode, + }); + // Untyped Input (file) let input = service.createInput({ resource: toResource.call(this, '/index.html'), options: { selection: { startLineNumber: 1, startColumn: 1 } } }); assert(input instanceof FileEditorInput); @@ -250,6 +256,18 @@ suite('Editor service', () => { contentInput = input; assert.equal(contentInput.getPreferredEncoding(), 'utf16le'); + // Untyped Input (file, mode) + input = service.createInput({ resource: toResource.call(this, '/index.html'), mode }); + assert(input instanceof FileEditorInput); + contentInput = input; + assert.equal(contentInput.getPreferredMode(), mode); + + // Untyped Input (file, different mode) + input = service.createInput({ resource: toResource.call(this, '/index.html'), mode: 'text' }); + assert(input instanceof FileEditorInput); + contentInput = input; + assert.equal(contentInput.getPreferredMode(), 'text'); + // Untyped Input (untitled) input = service.createInput({ options: { selection: { startLineNumber: 1, startColumn: 1 } } }); assert(input instanceof UntitledEditorInput); @@ -257,6 +275,14 @@ suite('Editor service', () => { // Untyped Input (untitled with contents) input = service.createInput({ contents: 'Hello Untitled', options: { selection: { startLineNumber: 1, startColumn: 1 } } }); assert(input instanceof UntitledEditorInput); + let model = await input.resolve() as UntitledEditorModel; + assert.equal(model.textEditorModel!.getValue(), 'Hello Untitled'); + + // Untyped Input (untitled with mode) + input = service.createInput({ mode, options: { selection: { startLineNumber: 1, startColumn: 1 } } }); + assert(input instanceof UntitledEditorInput); + model = await input.resolve() as UntitledEditorModel; + assert.equal(model.getMode(), mode); // Untyped Input (untitled with file path) input = service.createInput({ resource: URI.file('/some/path.txt'), forceUntitled: true, options: { selection: { startLineNumber: 1, startColumn: 1 } } }); @@ -276,6 +302,10 @@ suite('Editor service', () => { assert.ok((input as UntitledEditorInput).hasAssociatedFilePath); provider.dispose(); + + // Untyped Input (resource) + input = service.createInput({ resource: URI.parse('custom:resource') }); + assert(input instanceof ResourceEditorInput); }); test('delegate', function (done) { @@ -298,7 +328,7 @@ suite('Editor service', () => { const ed = instantiationService.createInstance(MyEditor, 'my.editor'); - const inp = instantiationService.createInstance(ResourceEditorInput, 'name', 'description', URI.parse('my://resource-delegate')); + const inp = instantiationService.createInstance(ResourceEditorInput, 'name', 'description', URI.parse('my://resource-delegate'), undefined); const delegate = instantiationService.createInstance(DelegatingEditorService); delegate.setEditorOpenHandler((group: IEditorGroup, input: IEditorInput, options?: EditorOptions) => { assert.strictEqual(input, inp); @@ -311,7 +341,7 @@ suite('Editor service', () => { delegate.openEditor(inp); }); - test('close editor does not dispose when editor opened in other group', function () { + test('close editor does not dispose when editor opened in other group', async () => { const partInstantiator = workbenchInstantiationService(); const part = partInstantiator.createInstance(EditorPart); @@ -327,30 +357,26 @@ suite('Editor service', () => { const rootGroup = part.activeGroup; const rightGroup = part.addGroup(rootGroup, GroupDirection.RIGHT); - return part.whenRestored.then(() => { - - // Open input - return service.openEditor(input, { pinned: true }).then(editor => { - return service.openEditor(input, { pinned: true }, rightGroup).then(editor => { - const editors = service.editors; - assert.equal(editors.length, 2); - assert.equal(editors[0], input); - assert.equal(editors[1], input); - - // Close input - return rootGroup.closeEditor(input).then(() => { - assert.equal(input.isDisposed(), false); - - return rightGroup.closeEditor(input).then(() => { - assert.equal(input.isDisposed(), true); - }); - }); - }); - }); - }); + await part.whenRestored; + + // Open input + await service.openEditor(input, { pinned: true }); + await service.openEditor(input, { pinned: true }, rightGroup); + + const editors = service.editors; + assert.equal(editors.length, 2); + assert.equal(editors[0], input); + assert.equal(editors[1], input); + + // Close input + await rootGroup.closeEditor(input); + assert.equal(input.isDisposed(), false); + + await rightGroup.closeEditor(input); + assert.equal(input.isDisposed(), true); }); - test('open to the side', function () { + test('open to the side', async () => { const partInstantiator = workbenchInstantiationService(); const part = partInstantiator.createInstance(EditorPart); @@ -366,22 +392,20 @@ suite('Editor service', () => { const rootGroup = part.activeGroup; - return part.whenRestored.then(() => { - return service.openEditor(input1, { pinned: true }, rootGroup).then(editor => { - return service.openEditor(input1, { pinned: true, preserveFocus: true }, SIDE_GROUP).then(editor => { - assert.equal(part.activeGroup, rootGroup); - assert.equal(part.count, 2); - assert.equal(editor!.group, part.groups[1]); - - // Open to the side uses existing neighbour group if any - return service.openEditor(input2, { pinned: true, preserveFocus: true }, SIDE_GROUP).then(editor => { - assert.equal(part.activeGroup, rootGroup); - assert.equal(part.count, 2); - assert.equal(editor!.group, part.groups[1]); - }); - }); - }); - }); + await part.whenRestored; + + await service.openEditor(input1, { pinned: true }, rootGroup); + let editor = await service.openEditor(input1, { pinned: true, preserveFocus: true }, SIDE_GROUP); + + assert.equal(part.activeGroup, rootGroup); + assert.equal(part.count, 2); + assert.equal(editor!.group, part.groups[1]); + + // Open to the side uses existing neighbour group if any + editor = await service.openEditor(input2, { pinned: true, preserveFocus: true }, SIDE_GROUP); + assert.equal(part.activeGroup, rootGroup); + assert.equal(part.count, 2); + assert.equal(editor!.group, part.groups[1]); }); test('active editor change / visible editor change events', async function () { diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts new file mode 100644 index 000000000..2bd39c975 --- /dev/null +++ b/src/vs/workbench/services/environment/browser/environmentService.ts @@ -0,0 +1,185 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IWindowConfiguration, IPath, IPathsToWaitFor } from 'vs/platform/windows/common/windows'; +import { IEnvironmentService, IExtensionHostDebugParams, IDebugParams, BACKUPS } from 'vs/platform/environment/common/environment'; +import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { URI } from 'vs/base/common/uri'; +import { IProcessEnvironment } from 'vs/base/common/platform'; +import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { ExportData } from 'vs/base/common/performance'; +import { LogLevel } from 'vs/platform/log/common/log'; +import { joinPath } from 'vs/base/common/resources'; +import { Schemas } from 'vs/base/common/network'; + +export class BrowserWindowConfiguration implements IWindowConfiguration { + + _: any[]; + + machineId: string; + windowId: number; + logLevel: LogLevel; + + mainPid: number; + + appRoot: string; + execPath: string; + isInitialStartup?: boolean; + + userEnv: IProcessEnvironment; + nodeCachedDataDir?: string; + + backupPath?: string; + + workspace?: IWorkspaceIdentifier; + folderUri?: ISingleFolderWorkspaceIdentifier; + + remoteAuthority: string; + + zoomLevel?: number; + fullscreen?: boolean; + maximized?: boolean; + highContrast?: boolean; + frameless?: boolean; + accessibilitySupport?: boolean; + partsSplashPath?: string; + + perfStartTime?: number; + perfAppReady?: number; + perfWindowLoadTime?: number; + perfEntries: ExportData; + + filesToOpenOrCreate?: IPath[]; + filesToDiff?: IPath[]; + filesToWait?: IPathsToWaitFor; + termProgram?: string; +} + +export interface IBrowserWindowConfiguration { + workspaceId: string; + remoteAuthority?: string; + webviewEndpoint?: string; +} + +export class BrowserWorkbenchEnvironmentService implements IEnvironmentService { + _serviceBrand: ServiceIdentifier; + + readonly configuration: IWindowConfiguration = new BrowserWindowConfiguration(); + + constructor(configuration: IBrowserWindowConfiguration) { + this.args = { _: [] }; + this.appRoot = '/web/'; + this.appNameLong = 'Visual Studio Code - Web'; + + this.configuration.remoteAuthority = configuration.remoteAuthority; + this.userRoamingDataHome = URI.file('/User').with({ scheme: Schemas.userData }); + this.settingsResource = joinPath(this.userRoamingDataHome, 'settings.json'); + this.keybindingsResource = joinPath(this.userRoamingDataHome, 'keybindings.json'); + this.keyboardLayoutResource = joinPath(this.userRoamingDataHome, 'keyboardLayout.json'); + this.localeResource = joinPath(this.userRoamingDataHome, 'locale.json'); + this.backupHome = joinPath(this.userRoamingDataHome, BACKUPS); + this.configuration.backupWorkspaceResource = joinPath(this.backupHome, configuration.workspaceId); + + this.logsPath = '/web/logs'; + + this.debugExtensionHost = { + port: null, + break: false + }; + + this.webviewEndpoint = configuration.webviewEndpoint; + this.untitledWorkspacesHome = URI.from({ scheme: Schemas.untitled, path: 'Workspaces' }); + + if (document && document.location && document.location.search) { + + const map = new Map(); + const query = document.location.search.substring(1); + const vars = query.split('&'); + for (let p of vars) { + const pair = p.split('='); + if (pair.length >= 2) { + map.set(decodeURIComponent(pair[0]), decodeURIComponent(pair[1])); + } + } + + const edp = map.get('edp'); + if (edp) { + this.extensionDevelopmentLocationURI = [URI.parse(edp)]; + this.isExtensionDevelopment = true; + } + + const di = map.get('di'); + if (di) { + this.debugExtensionHost.debugId = di; + } + + const ibe = map.get('ibe'); + if (ibe) { + this.debugExtensionHost.port = parseInt(ibe); + this.debugExtensionHost.break = false; + } + } + } + + untitledWorkspacesHome: URI; + extensionTestsLocationURI?: URI; + args: any; + execPath: string; + cliPath: string; + appRoot: string; + userHome: string; + userDataPath: string; + appNameLong: string; + appQuality?: string; + appSettingsHome: URI; + userRoamingDataHome: URI; + settingsResource: URI; + keybindingsResource: URI; + keyboardLayoutResource: URI; + localeResource: URI; + machineSettingsHome: URI; + machineSettingsResource: URI; + globalStorageHome: string; + workspaceStorageHome: string; + backupHome: URI; + backupWorkspacesPath: string; + workspacesHome: string; + isExtensionDevelopment: boolean; + disableExtensions: boolean | string[]; + builtinExtensionsPath: string; + extensionsPath?: string; + extensionDevelopmentLocationURI?: URI[]; + extensionTestsPath?: string; + debugExtensionHost: IExtensionHostDebugParams; + debugSearch: IDebugParams; + logExtensionHostCommunication: boolean; + isBuilt: boolean; + wait: boolean; + status: boolean; + log?: string; + logsPath: string; + verbose: boolean; + skipGettingStarted: boolean; + skipReleaseNotes: boolean; + skipAddToRecentlyOpened: boolean; + mainIPCHandle: string; + sharedIPCHandle: string; + nodeCachedDataDir?: string; + installSourcePath: string; + disableUpdates: boolean; + disableCrashReporter: boolean; + driverHandle?: string; + driverVerbose: boolean; + webviewEndpoint?: string; + galleryMachineIdResource?: URI; + + get webviewResourceRoot(): string { + return this.webviewEndpoint ? this.webviewEndpoint + '/vscode-resource{{resource}}' : 'vscode-resource:{{resource}}'; + } + + get webviewCspSource(): string { + return this.webviewEndpoint ? this.webviewEndpoint : 'vscode-resource:'; + } +} diff --git a/src/vs/workbench/services/environment/common/environmentService.ts b/src/vs/workbench/services/environment/common/environmentService.ts index 84c501ee1..fd4beaf13 100644 --- a/src/vs/workbench/services/environment/common/environmentService.ts +++ b/src/vs/workbench/services/environment/common/environmentService.ts @@ -3,14 +3,15 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; export const IWorkbenchEnvironmentService = createDecorator('environmentService'); export interface IWorkbenchEnvironmentService extends IEnvironmentService { - _serviceBrand: any; + + _serviceBrand: ServiceIdentifier; readonly configuration: IWindowConfiguration; } diff --git a/src/vs/workbench/services/environment/node/environmentService.ts b/src/vs/workbench/services/environment/node/environmentService.ts index db2a229c0..8b8b9354b 100644 --- a/src/vs/workbench/services/environment/node/environmentService.ts +++ b/src/vs/workbench/services/environment/node/environmentService.ts @@ -6,6 +6,10 @@ import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { memoize } from 'vs/base/common/decorators'; +import { URI } from 'vs/base/common/uri'; +import { Schemas } from 'vs/base/common/network'; +import { toBackupWorkspaceResource } from 'vs/workbench/services/backup/common/backup'; export class WorkbenchEnvironmentService extends EnvironmentService implements IWorkbenchEnvironmentService { @@ -16,9 +20,13 @@ export class WorkbenchEnvironmentService extends EnvironmentService implements I execPath: string ) { super(_configuration, execPath); + this._configuration.backupWorkspaceResource = this._configuration.backupPath ? toBackupWorkspaceResource(this._configuration.backupPath, this) : undefined; } get configuration(): IWindowConfiguration { return this._configuration; } + + @memoize + get userRoamingDataHome(): URI { return this.appSettingsHome.with({ scheme: Schemas.userData }); } } diff --git a/src/vs/workbench/services/extensionManagement/node/extensionEnablementService.ts b/src/vs/workbench/services/extensionManagement/common/extensionEnablementService.ts similarity index 86% rename from src/vs/workbench/services/extensionManagement/node/extensionEnablementService.ts rename to src/vs/workbench/services/extensionManagement/common/extensionEnablementService.ts index 2cc63fe63..3ceb5b208 100644 --- a/src/vs/workbench/services/extensionManagement/node/extensionEnablementService.ts +++ b/src/vs/workbench/services/extensionManagement/common/extensionEnablementService.ts @@ -6,7 +6,8 @@ import { localize } from 'vs/nls'; import { Event, Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; -import { IExtensionManagementService, DidUninstallExtensionEvent, IExtensionEnablementService, IExtensionIdentifier, EnablementState, DidInstallExtensionEvent, InstallOperation, IExtensionManagementServerService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementService, DidUninstallExtensionEvent, IExtensionIdentifier, DidInstallExtensionEvent, InstallOperation } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionEnablementService, EnablementState, IExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IStorageService, StorageScope, IWorkspaceStorageChangeEvent } from 'vs/platform/storage/common/storage'; @@ -14,8 +15,9 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { isUndefinedOrNull } from 'vs/base/common/types'; import { ExtensionType, IExtension } from 'vs/platform/extensions/common/extensions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { isUIExtension } from 'vs/workbench/services/extensions/node/extensionsUtil'; +import { isUIExtension } from 'vs/workbench/services/extensions/common/extensionsUtil'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IProductService } from 'vs/platform/product/common/product'; const DISABLED_EXTENSIONS_STORAGE_PATH = 'extensionsIdentifiers/disabled'; const ENABLED_EXTENSIONS_STORAGE_PATH = 'extensionsIdentifiers/enabled'; @@ -36,6 +38,7 @@ export class ExtensionEnablementService extends Disposable implements IExtension @IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService, @IConfigurationService private readonly configurationService: IConfigurationService, @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService, + @IProductService private readonly productService: IProductService, ) { super(); this.storageManger = this._register(new StorageManager(storageService)); @@ -53,30 +56,34 @@ export class ExtensionEnablementService extends Disposable implements IExtension } getEnablementState(extension: IExtension): EnablementState { - if (this._isSystemDisabled(extension)) { - return EnablementState.Disabled; + if (this._isDisabledInEnv(extension)) { + return EnablementState.DisabledByEnvironemt; + } + if (this._isDisabledByExtensionKind(extension)) { + return EnablementState.DisabledByExtensionKind; } const identifier = extension.identifier; if (this.hasWorkspace) { if (this._getEnabledExtensions(StorageScope.WORKSPACE).filter(e => areSameExtensions(e, identifier))[0]) { - return EnablementState.WorkspaceEnabled; + return EnablementState.EnabledWorkspace; } if (this._getDisabledExtensions(StorageScope.WORKSPACE).filter(e => areSameExtensions(e, identifier))[0]) { - return EnablementState.WorkspaceDisabled; + return EnablementState.DisabledWorkspace; } } if (this._getDisabledExtensions(StorageScope.GLOBAL).filter(e => areSameExtensions(e, identifier))[0]) { - return EnablementState.Disabled; + return EnablementState.DisabledGlobally; } - return EnablementState.Enabled; + return EnablementState.EnabledGlobally; } canChangeEnablement(extension: IExtension): boolean { if (extension.manifest && extension.manifest.contributes && extension.manifest.contributes.localizations && extension.manifest.contributes.localizations.length) { return false; } - if (this._isSystemDisabled(extension)) { + const enablementState = this.getEnablementState(extension); + if (enablementState === EnablementState.DisabledByEnvironemt || enablementState === EnablementState.DisabledByExtensionKind) { return false; } return true; @@ -84,7 +91,7 @@ export class ExtensionEnablementService extends Disposable implements IExtension async setEnablement(extensions: IExtension[], newState: EnablementState): Promise { - const workspace = newState === EnablementState.WorkspaceDisabled || newState === EnablementState.WorkspaceEnabled; + const workspace = newState === EnablementState.DisabledWorkspace || newState === EnablementState.EnabledWorkspace; if (workspace && !this.hasWorkspace) { return Promise.reject(new Error(localize('noWorkspace', "No workspace."))); } @@ -106,16 +113,16 @@ export class ExtensionEnablementService extends Disposable implements IExtension } switch (newState) { - case EnablementState.Enabled: + case EnablementState.EnabledGlobally: this._enableExtension(extension.identifier); break; - case EnablementState.Disabled: + case EnablementState.DisabledGlobally: this._disableExtension(extension.identifier); break; - case EnablementState.WorkspaceEnabled: + case EnablementState.EnabledWorkspace: this._enableExtensionInWorkspace(extension.identifier); break; - case EnablementState.WorkspaceDisabled: + case EnablementState.DisabledWorkspace: this._disableExtensionInWorkspace(extension.identifier); break; } @@ -125,10 +132,10 @@ export class ExtensionEnablementService extends Disposable implements IExtension isEnabled(extension: IExtension): boolean { const enablementState = this.getEnablementState(extension); - return enablementState === EnablementState.WorkspaceEnabled || enablementState === EnablementState.Enabled; + return enablementState === EnablementState.EnabledWorkspace || enablementState === EnablementState.EnabledGlobally; } - private _isSystemDisabled(extension: IExtension): boolean { + private _isDisabledInEnv(extension: IExtension): boolean { if (this.allUserExtensionsDisabled) { return extension.type === ExtensionType.User; } @@ -136,8 +143,12 @@ export class ExtensionEnablementService extends Disposable implements IExtension if (Array.isArray(disabledExtensions)) { return disabledExtensions.some(id => areSameExtensions({ id }, extension.identifier)); } - if (this.environmentService.configuration.remoteAuthority) { - const server = isUIExtension(extension.manifest, this.configurationService) ? this.extensionManagementServerService.localExtensionManagementServer : this.extensionManagementServerService.remoteExtensionManagementServer; + return false; + } + + private _isDisabledByExtensionKind(extension: IExtension): boolean { + if (this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) { + const server = isUIExtension(extension.manifest, this.productService, this.configurationService) ? this.extensionManagementServerService.localExtensionManagementServer : this.extensionManagementServerService.remoteExtensionManagementServer; return this.extensionManagementServerService.getExtensionManagementServer(extension.location) !== server; } return false; @@ -146,17 +157,17 @@ export class ExtensionEnablementService extends Disposable implements IExtension private _getEnablementState(identifier: IExtensionIdentifier): EnablementState { if (this.hasWorkspace) { if (this._getEnabledExtensions(StorageScope.WORKSPACE).filter(e => areSameExtensions(e, identifier))[0]) { - return EnablementState.WorkspaceEnabled; + return EnablementState.EnabledWorkspace; } if (this._getDisabledExtensions(StorageScope.WORKSPACE).filter(e => areSameExtensions(e, identifier))[0]) { - return EnablementState.WorkspaceDisabled; + return EnablementState.DisabledWorkspace; } } if (this._getDisabledExtensions(StorageScope.GLOBAL).filter(e => areSameExtensions(e, identifier))[0]) { - return EnablementState.Disabled; + return EnablementState.DisabledGlobally; } - return EnablementState.Enabled; + return EnablementState.EnabledGlobally; } private _enableExtension(identifier: IExtensionIdentifier): void { diff --git a/src/vs/workbench/services/extensionManagement/common/extensionManagement.ts b/src/vs/workbench/services/extensionManagement/common/extensionManagement.ts new file mode 100644 index 000000000..bd16a2ca8 --- /dev/null +++ b/src/vs/workbench/services/extensionManagement/common/extensionManagement.ts @@ -0,0 +1,117 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Event } from 'vs/base/common/event'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { URI } from 'vs/base/common/uri'; +import { IExtension } from 'vs/platform/extensions/common/extensions'; +import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IWorkspace, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; + +export const IExtensionManagementServerService = createDecorator('extensionManagementServerService'); + +export interface IExtensionManagementServer { + extensionManagementService: IExtensionManagementService; + authority: string; + label: string; +} + +export interface IExtensionManagementServerService { + _serviceBrand: any; + readonly localExtensionManagementServer: IExtensionManagementServer | null; + readonly remoteExtensionManagementServer: IExtensionManagementServer | null; + getExtensionManagementServer(location: URI): IExtensionManagementServer | null; +} + +export const enum EnablementState { + DisabledByExtensionKind, + DisabledByEnvironemt, + DisabledGlobally, + DisabledWorkspace, + EnabledGlobally, + EnabledWorkspace +} + +export const IExtensionEnablementService = createDecorator('extensionEnablementService'); + +export interface IExtensionEnablementService { + _serviceBrand: any; + + readonly allUserExtensionsDisabled: boolean; + + /** + * Event to listen on for extension enablement changes + */ + onEnablementChanged: Event; + + /** + * Returns the enablement state for the given extension + */ + getEnablementState(extension: IExtension): EnablementState; + + /** + * Returns `true` if the enablement can be changed. + */ + canChangeEnablement(extension: IExtension): boolean; + + /** + * Returns `true` if the given extension identifier is enabled. + */ + isEnabled(extension: IExtension): boolean; + + /** + * Enable or disable the given extension. + * if `workspace` is `true` then enablement is done for workspace, otherwise globally. + * + * Returns a promise that resolves to boolean value. + * if resolves to `true` then requires restart for the change to take effect. + * + * Throws error if enablement is requested for workspace and there is no workspace + */ + setEnablement(extensions: IExtension[], state: EnablementState): Promise; +} + +export interface IExtensionsConfigContent { + recommendations: string[]; + unwantedRecommendations: string[]; +} + +export type RecommendationChangeNotification = { + extensionId: string, + isRecommended: boolean +}; + +export type DynamicRecommendation = 'dynamic'; +export type ExecutableRecommendation = 'executable'; +export type CachedRecommendation = 'cached'; +export type ApplicationRecommendation = 'application'; +export type ExtensionRecommendationSource = IWorkspace | IWorkspaceFolder | URI | DynamicRecommendation | ExecutableRecommendation | CachedRecommendation | ApplicationRecommendation; + +export interface IExtensionRecommendation { + extensionId: string; + sources: ExtensionRecommendationSource[]; +} + +export const IExtensionTipsService = createDecorator('extensionTipsService'); + +export interface IExtensionTipsService { + _serviceBrand: any; + getAllRecommendationsWithReason(): { [id: string]: { reasonId: ExtensionRecommendationReason, reasonText: string }; }; + getFileBasedRecommendations(): IExtensionRecommendation[]; + getOtherRecommendations(): Promise; + getWorkspaceRecommendations(): Promise; + getKeymapRecommendations(): IExtensionRecommendation[]; + toggleIgnoredRecommendation(extensionId: string, shouldIgnore: boolean): void; + getAllIgnoredRecommendations(): { global: string[], workspace: string[] }; + onRecommendationChange: Event; +} + +export const enum ExtensionRecommendationReason { + Workspace, + File, + Executable, + DynamicWorkspace, + Experimental +} diff --git a/src/vs/workbench/services/extensionManagement/common/extensionManagementServerService.ts b/src/vs/workbench/services/extensionManagement/common/extensionManagementServerService.ts new file mode 100644 index 000000000..0a48d2989 --- /dev/null +++ b/src/vs/workbench/services/extensionManagement/common/extensionManagementServerService.ts @@ -0,0 +1,45 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { localize } from 'vs/nls'; +import { URI } from 'vs/base/common/uri'; +import { IExtensionManagementServer, IExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; +import { ExtensionManagementChannelClient } from 'vs/platform/extensionManagement/common/extensionManagementIpc'; +import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; +import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; +import { IChannel } from 'vs/base/parts/ipc/common/ipc'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { ILabelService } from 'vs/platform/label/common/label'; + +export class ExtensionManagementServerService implements IExtensionManagementServerService { + + _serviceBrand: any; + + readonly localExtensionManagementServer: IExtensionManagementServer | null = null; + readonly remoteExtensionManagementServer: IExtensionManagementServer | null = null; + + constructor( + @IRemoteAgentService remoteAgentService: IRemoteAgentService, + @ILabelService labelService: ILabelService, + ) { + const remoteAgentConnection = remoteAgentService.getConnection(); + if (remoteAgentConnection) { + const extensionManagementService = new ExtensionManagementChannelClient(remoteAgentConnection!.getChannel('extensions')); + this.remoteExtensionManagementServer = { + authority: remoteAgentConnection.remoteAuthority, extensionManagementService, + get label() { return labelService.getHostLabel(REMOTE_HOST_SCHEME, remoteAgentConnection!.remoteAuthority) || localize('remote', "Remote"); } + }; + } + } + + getExtensionManagementServer(location: URI): IExtensionManagementServer | null { + if (location.scheme === REMOTE_HOST_SCHEME) { + return this.remoteExtensionManagementServer; + } + return null; + } +} + +registerSingleton(IExtensionManagementServerService, ExtensionManagementServerService); \ No newline at end of file diff --git a/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts b/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts new file mode 100644 index 000000000..337f52b27 --- /dev/null +++ b/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts @@ -0,0 +1,194 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Event, EventMultiplexer } from 'vs/base/common/event'; +import { + IExtensionManagementService, ILocalExtension, IGalleryExtension, InstallExtensionEvent, DidInstallExtensionEvent, IExtensionIdentifier, DidUninstallExtensionEvent, IReportedExtension, IGalleryMetadata, IExtensionGalleryService +} from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementServer, IExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; +import { ExtensionType, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions'; +import { URI } from 'vs/base/common/uri'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { localize } from 'vs/nls'; +import { isUIExtension } from 'vs/workbench/services/extensions/common/extensionsUtil'; +import { IProductService } from 'vs/platform/product/common/product'; + +export class ExtensionManagementService extends Disposable implements IExtensionManagementService { + + _serviceBrand: any; + + readonly onInstallExtension: Event; + readonly onDidInstallExtension: Event; + readonly onUninstallExtension: Event; + readonly onDidUninstallExtension: Event; + + protected readonly servers: IExtensionManagementServer[] = []; + + constructor( + @IExtensionManagementServerService protected readonly extensionManagementServerService: IExtensionManagementServerService, + @IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService, + @IConfigurationService protected readonly configurationService: IConfigurationService, + @IProductService protected readonly productService: IProductService, + ) { + super(); + if (this.extensionManagementServerService.localExtensionManagementServer) { + this.servers.push(this.extensionManagementServerService.localExtensionManagementServer); + } + if (this.extensionManagementServerService.remoteExtensionManagementServer) { + this.servers.push(this.extensionManagementServerService.remoteExtensionManagementServer); + } + + this.onInstallExtension = this._register(this.servers.reduce((emitter: EventMultiplexer, server) => { emitter.add(server.extensionManagementService.onInstallExtension); return emitter; }, new EventMultiplexer())).event; + this.onDidInstallExtension = this._register(this.servers.reduce((emitter: EventMultiplexer, server) => { emitter.add(server.extensionManagementService.onDidInstallExtension); return emitter; }, new EventMultiplexer())).event; + this.onUninstallExtension = this._register(this.servers.reduce((emitter: EventMultiplexer, server) => { emitter.add(server.extensionManagementService.onUninstallExtension); return emitter; }, new EventMultiplexer())).event; + this.onDidUninstallExtension = this._register(this.servers.reduce((emitter: EventMultiplexer, server) => { emitter.add(server.extensionManagementService.onDidUninstallExtension); return emitter; }, new EventMultiplexer())).event; + } + + getInstalled(type?: ExtensionType): Promise { + const installedExtensions: ILocalExtension[] = []; + return Promise.all(this.servers.map(({ extensionManagementService }) => extensionManagementService.getInstalled(type).then(extensions => installedExtensions.push(...extensions)))) + .then(_ => installedExtensions) + .catch(e => installedExtensions); + } + + async uninstall(extension: ILocalExtension): Promise { + const server = this.getServer(extension); + if (!server) { + return Promise.reject(`Invalid location ${extension.location.toString()}`); + } + if (this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) { + if (isLanguagePackExtension(extension.manifest)) { + return this.uninstallEverywhere(extension); + } + return this.uninstallInServer(extension, server); + } + return server.extensionManagementService.uninstall(extension); + } + + private async uninstallEverywhere(extension: ILocalExtension): Promise { + const server = this.getServer(extension); + if (!server) { + return Promise.reject(`Invalid location ${extension.location.toString()}`); + } + const promise = server.extensionManagementService.uninstall(extension); + const anotherServer: IExtensionManagementServer | null = server === this.extensionManagementServerService.localExtensionManagementServer ? this.extensionManagementServerService.remoteExtensionManagementServer! : this.extensionManagementServerService.localExtensionManagementServer; + if (anotherServer) { + const installed = await anotherServer.extensionManagementService.getInstalled(ExtensionType.User); + extension = installed.filter(i => areSameExtensions(i.identifier, extension.identifier))[0]; + if (extension) { + await anotherServer.extensionManagementService.uninstall(extension); + } + } + return promise; + } + + private async uninstallInServer(extension: ILocalExtension, server: IExtensionManagementServer, force?: boolean): Promise { + if (server === this.extensionManagementServerService.localExtensionManagementServer) { + const installedExtensions = await this.extensionManagementServerService.remoteExtensionManagementServer!.extensionManagementService.getInstalled(ExtensionType.User); + const dependentNonUIExtensions = installedExtensions.filter(i => !isUIExtension(i.manifest, this.productService, this.configurationService) + && i.manifest.extensionDependencies && i.manifest.extensionDependencies.some(id => areSameExtensions({ id }, extension.identifier))); + if (dependentNonUIExtensions.length) { + return Promise.reject(new Error(this.getDependentsErrorMessage(extension, dependentNonUIExtensions))); + } + } + return server.extensionManagementService.uninstall(extension, force); + } + + private getDependentsErrorMessage(extension: ILocalExtension, dependents: ILocalExtension[]): string { + if (dependents.length === 1) { + return localize('singleDependentError', "Cannot uninstall extension '{0}'. Extension '{1}' depends on this.", + extension.manifest.displayName || extension.manifest.name, dependents[0].manifest.displayName || dependents[0].manifest.name); + } + if (dependents.length === 2) { + return localize('twoDependentsError', "Cannot uninstall extension '{0}'. Extensions '{1}' and '{2}' depend on this.", + extension.manifest.displayName || extension.manifest.name, dependents[0].manifest.displayName || dependents[0].manifest.name, dependents[1].manifest.displayName || dependents[1].manifest.name); + } + return localize('multipleDependentsError', "Cannot uninstall extension '{0}'. Extensions '{1}', '{2}' and others depend on this.", + extension.manifest.displayName || extension.manifest.name, dependents[0].manifest.displayName || dependents[0].manifest.name, dependents[1].manifest.displayName || dependents[1].manifest.name); + + } + + reinstallFromGallery(extension: ILocalExtension): Promise { + const server = this.getServer(extension); + if (server) { + return server.extensionManagementService.reinstallFromGallery(extension); + } + return Promise.reject(`Invalid location ${extension.location.toString()}`); + } + + updateMetadata(extension: ILocalExtension, metadata: IGalleryMetadata): Promise { + const server = this.getServer(extension); + if (server) { + return server.extensionManagementService.updateMetadata(extension, metadata); + } + return Promise.reject(`Invalid location ${extension.location.toString()}`); + } + + zip(extension: ILocalExtension): Promise { + const server = this.getServer(extension); + if (server) { + return server.extensionManagementService.zip(extension); + } + return Promise.reject(`Invalid location ${extension.location.toString()}`); + } + + unzip(zipLocation: URI, type: ExtensionType): Promise { + return Promise.all(this.servers.map(({ extensionManagementService }) => extensionManagementService.unzip(zipLocation, type))).then(([extensionIdentifier]) => extensionIdentifier); + } + + async install(vsix: URI): Promise { + if (this.extensionManagementServerService.localExtensionManagementServer) { + return this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.install(vsix); + } + if (this.extensionManagementServerService.remoteExtensionManagementServer) { + return this.extensionManagementServerService.remoteExtensionManagementServer.extensionManagementService.install(vsix); + } + return Promise.reject('No Servers to Install'); + } + + async installFromGallery(gallery: IGalleryExtension): Promise { + if (this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) { + const manifest = await this.extensionGalleryService.getManifest(gallery, CancellationToken.None); + if (manifest) { + if (isLanguagePackExtension(manifest)) { + // Install on both servers + return Promise.all(this.servers.map(server => server.extensionManagementService.installFromGallery(gallery))).then(([local]) => local); + } + if (isUIExtension(manifest, this.productService, this.configurationService)) { + // Install only on local server + return this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.installFromGallery(gallery); + } + // Install only on remote server + return this.extensionManagementServerService.remoteExtensionManagementServer.extensionManagementService.installFromGallery(gallery); + } else { + return Promise.reject(localize('Manifest is not found', "Installing Extension {0} failed: Manifest is not found.", gallery.displayName || gallery.name)); + } + } + if (this.extensionManagementServerService.localExtensionManagementServer) { + return this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.installFromGallery(gallery); + } + if (this.extensionManagementServerService.remoteExtensionManagementServer) { + return this.extensionManagementServerService.remoteExtensionManagementServer.extensionManagementService.installFromGallery(gallery); + } + return Promise.reject('No Servers to Install'); + } + + getExtensionsReport(): Promise { + if (this.extensionManagementServerService.localExtensionManagementServer) { + return this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.getExtensionsReport(); + } + if (this.extensionManagementServerService.remoteExtensionManagementServer) { + return this.extensionManagementServerService.remoteExtensionManagementServer.extensionManagementService.getExtensionsReport(); + } + return Promise.resolve([]); + } + + private getServer(extension: ILocalExtension): IExtensionManagementServer | null { + return this.extensionManagementServerService.getExtensionManagementServer(extension.location); + } +} \ No newline at end of file diff --git a/src/vs/workbench/services/extensionManagement/electron-browser/extensionManagementServerService.ts b/src/vs/workbench/services/extensionManagement/electron-browser/extensionManagementServerService.ts new file mode 100644 index 000000000..c3921f17a --- /dev/null +++ b/src/vs/workbench/services/extensionManagement/electron-browser/extensionManagementServerService.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. + *--------------------------------------------------------------------------------------------*/ + +import { localize } from 'vs/nls'; +import { Schemas } from 'vs/base/common/network'; +import { URI } from 'vs/base/common/uri'; +import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionManagementServer, IExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; +import { ExtensionManagementChannelClient } from 'vs/platform/extensionManagement/common/extensionManagementIpc'; +import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; +import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; +import { IChannel } from 'vs/base/parts/ipc/common/ipc'; +import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { ILogService } from 'vs/platform/log/common/log'; +import { RemoteExtensionManagementChannelClient } from 'vs/workbench/services/extensions/electron-browser/remoteExtensionManagementIpc'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IProductService } from 'vs/platform/product/common/product'; +import { ILabelService } from 'vs/platform/label/common/label'; + +const localExtensionManagementServerAuthority: string = 'vscode-local'; + +export class ExtensionManagementServerService implements IExtensionManagementServerService { + + _serviceBrand: any; + + readonly localExtensionManagementServer: IExtensionManagementServer; + readonly remoteExtensionManagementServer: IExtensionManagementServer | null = null; + readonly isSingleServer: boolean = false; + + constructor( + @ISharedProcessService sharedProcessService: ISharedProcessService, + @IRemoteAgentService remoteAgentService: IRemoteAgentService, + @IExtensionGalleryService galleryService: IExtensionGalleryService, + @IConfigurationService configurationService: IConfigurationService, + @IProductService productService: IProductService, + @ILogService logService: ILogService, + @ILabelService labelService: ILabelService, + ) { + const localExtensionManagementService = new ExtensionManagementChannelClient(sharedProcessService.getChannel('extensions')); + + this.localExtensionManagementServer = { extensionManagementService: localExtensionManagementService, authority: localExtensionManagementServerAuthority, label: localize('local', "Local") }; + const remoteAgentConnection = remoteAgentService.getConnection(); + if (remoteAgentConnection) { + const extensionManagementService = new RemoteExtensionManagementChannelClient(remoteAgentConnection.getChannel('extensions'), this.localExtensionManagementServer.extensionManagementService, galleryService, logService, configurationService, productService); + this.remoteExtensionManagementServer = { + authority: remoteAgentConnection.remoteAuthority, extensionManagementService, + get label() { return labelService.getHostLabel(REMOTE_HOST_SCHEME, remoteAgentConnection!.remoteAuthority) || localize('remote', "Remote"); } + }; + } + } + + getExtensionManagementServer(location: URI): IExtensionManagementServer | null { + if (location.scheme === Schemas.file) { + return this.localExtensionManagementServer; + } + if (location.scheme === REMOTE_HOST_SCHEME) { + return this.remoteExtensionManagementServer; + } + return null; + } +} + +registerSingleton(IExtensionManagementServerService, ExtensionManagementServerService); \ No newline at end of file diff --git a/src/vs/workbench/services/extensionManagement/node/extensionManagementService.ts b/src/vs/workbench/services/extensionManagement/node/extensionManagementService.ts new file mode 100644 index 000000000..46db06b9d --- /dev/null +++ b/src/vs/workbench/services/extensionManagement/node/extensionManagementService.ts @@ -0,0 +1,36 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { isLanguagePackExtension } from 'vs/platform/extensions/common/extensions'; +import { URI } from 'vs/base/common/uri'; +import { getManifest } from 'vs/platform/extensionManagement/node/extensionManagementUtil'; +import { isUIExtension } from 'vs/workbench/services/extensions/common/extensionsUtil'; +import { ExtensionManagementService as BaseExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagementService'; + +export class ExtensionManagementService extends BaseExtensionManagementService { + + async install(vsix: URI): Promise { + if (this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) { + const manifest = await getManifest(vsix.fsPath); + if (isLanguagePackExtension(manifest)) { + // Install on both servers + const [local] = await Promise.all(this.servers.map(server => server.extensionManagementService.install(vsix))); + return local; + } + if (isUIExtension(manifest, this.productService, this.configurationService)) { + // Install only on local server + return this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.install(vsix); + } + // Install only on remote server + return this.extensionManagementServerService.remoteExtensionManagementServer.extensionManagementService.install(vsix); + } + if (this.extensionManagementServerService.localExtensionManagementServer) { + return this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.install(vsix); + } + return Promise.reject('No Servers to Install'); + } + +} diff --git a/src/vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test.ts b/src/vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test.ts index 9faa4c1c7..5852ce2d5 100644 --- a/src/vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test.ts +++ b/src/vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test.ts @@ -4,8 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; import * as sinon from 'sinon'; -import { IExtensionManagementService, IExtensionEnablementService, DidUninstallExtensionEvent, EnablementState, ILocalExtension, DidInstallExtensionEvent, InstallOperation, IExtensionManagementServerService } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { ExtensionEnablementService } from 'vs/workbench/services/extensionManagement/node/extensionEnablementService'; +import { IExtensionManagementService, DidUninstallExtensionEvent, ILocalExtension, DidInstallExtensionEvent, InstallOperation } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionEnablementService, EnablementState, IExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; +import { ExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionEnablementService'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { Emitter } from 'vs/base/common/event'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; @@ -15,6 +16,12 @@ import { IExtensionContributions, ExtensionType, IExtension } from 'vs/platform/ import { isUndefinedOrNull } from 'vs/base/common/types'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { ProductService } from 'vs/platform/product/node/productService'; +import { URI } from 'vs/base/common/uri'; +import { Schemas } from 'vs/base/common/network'; +import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; +import { assign } from 'vs/base/common/objects'; +import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; function storageService(instantiationService: TestInstantiationService): IStorageService { let service = instantiationService.get(IStorageService); @@ -38,7 +45,9 @@ export class TestExtensionEnablementService extends ExtensionEnablementService { instantiationService.get(IWorkbenchEnvironmentService) || instantiationService.stub(IWorkbenchEnvironmentService, { configuration: Object.create(null) } as IWorkbenchEnvironmentService), instantiationService.get(IExtensionManagementService) || instantiationService.stub(IExtensionManagementService, { onDidInstallExtension: new Emitter().event, onDidUninstallExtension: new Emitter().event } as IExtensionManagementService), - instantiationService.get(IConfigurationService), instantiationService.get(IExtensionManagementServerService)); + instantiationService.get(IConfigurationService), instantiationService.get(IExtensionManagementServerService), + new ProductService() + ); } public reset(): void { @@ -52,7 +61,7 @@ export class TestExtensionEnablementService extends ExtensionEnablementService { if (workspaceEnabledExtensions.length) { extensions = extensions.filter(r => !workspaceEnabledExtensions.some(e => areSameExtensions(e, r))); } - extensions.forEach(d => this.setEnablement([aLocalExtension(d.id)], EnablementState.Enabled)); + extensions.forEach(d => this.setEnablement([aLocalExtension(d.id)], EnablementState.EnabledGlobally)); } } @@ -66,7 +75,13 @@ suite('ExtensionEnablementService Test', () => { setup(() => { instantiationService = new TestInstantiationService(); + instantiationService.stub(IConfigurationService, new TestConfigurationService()); instantiationService.stub(IExtensionManagementService, { onDidUninstallExtension: didUninstallEvent.event, onDidInstallExtension: didInstallEvent.event, getInstalled: () => Promise.resolve([] as ILocalExtension[]) } as IExtensionManagementService); + instantiationService.stub(IExtensionManagementServerService, { + localExtensionManagementServer: { + extensionManagementService: instantiationService.get(IExtensionManagementService) + } + }); testObject = new TestExtensionEnablementService(instantiationService); }); @@ -76,20 +91,20 @@ suite('ExtensionEnablementService Test', () => { test('test disable an extension globally', async () => { const extension = aLocalExtension('pub.a'); - await testObject.setEnablement([extension], EnablementState.Disabled); + await testObject.setEnablement([extension], EnablementState.DisabledGlobally); assert.ok(!testObject.isEnabled(extension)); - assert.equal(testObject.getEnablementState(extension), EnablementState.Disabled); + assert.equal(testObject.getEnablementState(extension), EnablementState.DisabledGlobally); }); test('test disable an extension globally should return truthy promise', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally) .then(value => assert.ok(value)); }); test('test disable an extension globally triggers the change event', () => { const target = sinon.spy(); testObject.onEnablementChanged(target); - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally) .then(() => { assert.ok(target.calledOnce); assert.deepEqual((target.args[0][0][0]).identifier, { id: 'pub.a' }); @@ -97,116 +112,116 @@ suite('ExtensionEnablementService Test', () => { }); test('test disable an extension globally again should return a falsy promise', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled)) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally)) .then(value => assert.ok(!value[0])); }); test('test state of globally disabled extension', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled) - .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.Disabled)); + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally) + .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.DisabledGlobally)); }); test('test state of globally enabled extension', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Enabled)) - .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.Enabled)); + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.EnabledGlobally)) + .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.EnabledGlobally)); }); test('test disable an extension for workspace', async () => { const extension = aLocalExtension('pub.a'); - await testObject.setEnablement([extension], EnablementState.WorkspaceDisabled); + await testObject.setEnablement([extension], EnablementState.DisabledWorkspace); assert.ok(!testObject.isEnabled(extension)); - assert.equal(testObject.getEnablementState(extension), EnablementState.WorkspaceDisabled); + assert.equal(testObject.getEnablementState(extension), EnablementState.DisabledWorkspace); }); test('test disable an extension for workspace returns a truthy promise', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace) .then(value => assert.ok(value)); }); test('test disable an extension for workspace again should return a falsy promise', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace)) .then(value => assert.ok(!value[0])); }); test('test state of workspace disabled extension', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled) - .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.WorkspaceDisabled)); + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace) + .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.DisabledWorkspace)); }); test('test state of workspace and globally disabled extension', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)) - .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.WorkspaceDisabled)); + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace)) + .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.DisabledWorkspace)); }); test('test state of workspace enabled extension', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceEnabled)) - .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.WorkspaceEnabled)); + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.EnabledWorkspace)) + .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.EnabledWorkspace)); }); test('test state of globally disabled and workspace enabled extension', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceEnabled)) - .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.WorkspaceEnabled)); + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace)) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.EnabledWorkspace)) + .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.EnabledWorkspace)); }); test('test state of an extension when disabled for workspace from workspace enabled', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceEnabled)) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)) - .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.WorkspaceDisabled)); + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.EnabledWorkspace)) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace)) + .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.DisabledWorkspace)); }); test('test state of an extension when disabled globally from workspace enabled', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceEnabled)) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled)) - .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.Disabled)); + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.EnabledWorkspace)) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally)) + .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.DisabledGlobally)); }); test('test state of an extension when disabled globally from workspace disabled', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled)) - .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.Disabled)); + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally)) + .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.DisabledGlobally)); }); test('test state of an extension when enabled globally from workspace enabled', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceEnabled)) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Enabled)) - .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.Enabled)); + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.EnabledWorkspace)) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.EnabledGlobally)) + .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.EnabledGlobally)); }); test('test state of an extension when enabled globally from workspace disabled', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Enabled)) - .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.Enabled)); + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.EnabledGlobally)) + .then(() => assert.equal(testObject.getEnablementState(aLocalExtension('pub.a')), EnablementState.EnabledGlobally)); }); test('test disable an extension for workspace and then globally', async () => { const extension = aLocalExtension('pub.a'); - await testObject.setEnablement([extension], EnablementState.WorkspaceDisabled); - await testObject.setEnablement([extension], EnablementState.Disabled); + await testObject.setEnablement([extension], EnablementState.DisabledWorkspace); + await testObject.setEnablement([extension], EnablementState.DisabledGlobally); assert.ok(!testObject.isEnabled(extension)); - assert.equal(testObject.getEnablementState(extension), EnablementState.Disabled); + assert.equal(testObject.getEnablementState(extension), EnablementState.DisabledGlobally); }); test('test disable an extension for workspace and then globally return a truthy promise', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled)) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally)) .then(value => assert.ok(value)); }); test('test disable an extension for workspace and then globally trigger the change event', () => { const target = sinon.spy(); - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace) .then(() => testObject.onEnablementChanged(target)) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled)) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally)) .then(() => { assert.ok(target.calledOnce); assert.deepEqual((target.args[0][0][0]).identifier, { id: 'pub.a' }); @@ -215,23 +230,23 @@ suite('ExtensionEnablementService Test', () => { test('test disable an extension globally and then for workspace', async () => { const extension = aLocalExtension('pub.a'); - await testObject.setEnablement([extension], EnablementState.Disabled); - await testObject.setEnablement([extension], EnablementState.WorkspaceDisabled); + await testObject.setEnablement([extension], EnablementState.DisabledGlobally); + await testObject.setEnablement([extension], EnablementState.DisabledWorkspace); assert.ok(!testObject.isEnabled(extension)); - assert.equal(testObject.getEnablementState(extension), EnablementState.WorkspaceDisabled); + assert.equal(testObject.getEnablementState(extension), EnablementState.DisabledWorkspace); }); test('test disable an extension globally and then for workspace return a truthy promise', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace)) .then(value => assert.ok(value)); }); test('test disable an extension globally and then for workspace triggers the change event', () => { const target = sinon.spy(); - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally) .then(() => testObject.onEnablementChanged(target)) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled)) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace)) .then(() => { assert.ok(target.calledOnce); assert.deepEqual((target.args[0][0][0]).identifier, { id: 'pub.a' }); @@ -240,29 +255,29 @@ suite('ExtensionEnablementService Test', () => { test('test disable an extension for workspace when there is no workspace throws error', () => { instantiationService.stub(IWorkspaceContextService, 'getWorkbenchState', WorkbenchState.EMPTY); - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace) .then(() => assert.fail('should throw an error'), error => assert.ok(error)); }); test('test enable an extension globally', async () => { const extension = aLocalExtension('pub.a'); - await testObject.setEnablement([extension], EnablementState.Disabled); - await testObject.setEnablement([extension], EnablementState.Enabled); + await testObject.setEnablement([extension], EnablementState.DisabledGlobally); + await testObject.setEnablement([extension], EnablementState.EnabledGlobally); assert.ok(testObject.isEnabled(extension)); - assert.equal(testObject.getEnablementState(extension), EnablementState.Enabled); + assert.equal(testObject.getEnablementState(extension), EnablementState.EnabledGlobally); }); test('test enable an extension globally return truthy promise', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Enabled)) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.EnabledGlobally)) .then(value => assert.ok(value)); }); test('test enable an extension globally triggers change event', () => { const target = sinon.spy(); - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally) .then(() => testObject.onEnablementChanged(target)) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Enabled)) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.EnabledGlobally)) .then(() => { assert.ok(target.calledOnce); assert.deepEqual((target.args[0][0][0]).identifier, { id: 'pub.a' }); @@ -270,29 +285,29 @@ suite('ExtensionEnablementService Test', () => { }); test('test enable an extension globally when already enabled return falsy promise', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Enabled) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.EnabledGlobally) .then(value => assert.ok(!value[0])); }); test('test enable an extension for workspace', async () => { const extension = aLocalExtension('pub.a'); - await testObject.setEnablement([extension], EnablementState.WorkspaceDisabled); - await testObject.setEnablement([extension], EnablementState.WorkspaceEnabled); + await testObject.setEnablement([extension], EnablementState.DisabledWorkspace); + await testObject.setEnablement([extension], EnablementState.EnabledWorkspace); assert.ok(testObject.isEnabled(extension)); - assert.equal(testObject.getEnablementState(extension), EnablementState.WorkspaceEnabled); + assert.equal(testObject.getEnablementState(extension), EnablementState.EnabledWorkspace); }); test('test enable an extension for workspace return truthy promise', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled) - .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceEnabled)) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace) + .then(() => testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.EnabledWorkspace)) .then(value => assert.ok(value)); }); test('test enable an extension for workspace triggers change event', () => { const target = sinon.spy(); - return testObject.setEnablement([aLocalExtension('pub.b')], EnablementState.WorkspaceDisabled) + return testObject.setEnablement([aLocalExtension('pub.b')], EnablementState.DisabledWorkspace) .then(() => testObject.onEnablementChanged(target)) - .then(() => testObject.setEnablement([aLocalExtension('pub.b')], EnablementState.WorkspaceEnabled)) + .then(() => testObject.setEnablement([aLocalExtension('pub.b')], EnablementState.EnabledWorkspace)) .then(() => { assert.ok(target.calledOnce); assert.deepEqual((target.args[0][0][0]).identifier, { id: 'pub.b' }); @@ -300,48 +315,48 @@ suite('ExtensionEnablementService Test', () => { }); test('test enable an extension for workspace when already enabled return truthy promise', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceEnabled) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.EnabledWorkspace) .then(value => assert.ok(value)); }); test('test enable an extension for workspace when disabled in workspace and gloablly', async () => { const extension = aLocalExtension('pub.a'); - await testObject.setEnablement([extension], EnablementState.WorkspaceDisabled); - await testObject.setEnablement([extension], EnablementState.Disabled); - await testObject.setEnablement([extension], EnablementState.WorkspaceEnabled); + await testObject.setEnablement([extension], EnablementState.DisabledWorkspace); + await testObject.setEnablement([extension], EnablementState.DisabledGlobally); + await testObject.setEnablement([extension], EnablementState.EnabledWorkspace); assert.ok(testObject.isEnabled(extension)); - assert.equal(testObject.getEnablementState(extension), EnablementState.WorkspaceEnabled); + assert.equal(testObject.getEnablementState(extension), EnablementState.EnabledWorkspace); }); test('test enable an extension globally when disabled in workspace and gloablly', async () => { const extension = aLocalExtension('pub.a'); - await testObject.setEnablement([extension], EnablementState.WorkspaceEnabled); - await testObject.setEnablement([extension], EnablementState.WorkspaceDisabled); - await testObject.setEnablement([extension], EnablementState.Disabled); - await testObject.setEnablement([extension], EnablementState.Enabled); + await testObject.setEnablement([extension], EnablementState.EnabledWorkspace); + await testObject.setEnablement([extension], EnablementState.DisabledWorkspace); + await testObject.setEnablement([extension], EnablementState.DisabledGlobally); + await testObject.setEnablement([extension], EnablementState.EnabledGlobally); assert.ok(testObject.isEnabled(extension)); - assert.equal(testObject.getEnablementState(extension), EnablementState.Enabled); + assert.equal(testObject.getEnablementState(extension), EnablementState.EnabledGlobally); }); test('test installing an extension re-eanbles it when disabled globally', async () => { const local = aLocalExtension('pub.a'); - await testObject.setEnablement([local], EnablementState.Disabled); + await testObject.setEnablement([local], EnablementState.DisabledGlobally); didInstallEvent.fire({ local, identifier: local.identifier, operation: InstallOperation.Install }); assert.ok(testObject.isEnabled(local)); - assert.equal(testObject.getEnablementState(local), EnablementState.Enabled); + assert.equal(testObject.getEnablementState(local), EnablementState.EnabledGlobally); }); test('test updating an extension does not re-eanbles it when disabled globally', async () => { const local = aLocalExtension('pub.a'); - await testObject.setEnablement([local], EnablementState.Disabled); + await testObject.setEnablement([local], EnablementState.DisabledGlobally); didInstallEvent.fire({ local, identifier: local.identifier, operation: InstallOperation.Update }); assert.ok(!testObject.isEnabled(local)); - assert.equal(testObject.getEnablementState(local), EnablementState.Disabled); + assert.equal(testObject.getEnablementState(local), EnablementState.DisabledGlobally); }); test('test installing an extension fires enablement change event when disabled globally', async () => { const local = aLocalExtension('pub.a'); - await testObject.setEnablement([local], EnablementState.Disabled); + await testObject.setEnablement([local], EnablementState.DisabledGlobally); return new Promise((c, e) => { testObject.onEnablementChanged(([e]) => { if (e.identifier.id === local.identifier.id) { @@ -355,7 +370,7 @@ suite('ExtensionEnablementService Test', () => { test('test updating an extension does not fires enablement change event when disabled globally', async () => { const target = sinon.spy(); const local = aLocalExtension('pub.a'); - await testObject.setEnablement([local], EnablementState.Disabled); + await testObject.setEnablement([local], EnablementState.DisabledGlobally); testObject.onEnablementChanged(target); didInstallEvent.fire({ local, identifier: local.identifier, operation: InstallOperation.Update }); assert.ok(!target.called); @@ -363,23 +378,23 @@ suite('ExtensionEnablementService Test', () => { test('test installing an extension re-eanbles it when workspace disabled', async () => { const local = aLocalExtension('pub.a'); - await testObject.setEnablement([local], EnablementState.WorkspaceDisabled); + await testObject.setEnablement([local], EnablementState.DisabledWorkspace); didInstallEvent.fire({ local, identifier: local.identifier, operation: InstallOperation.Install }); assert.ok(testObject.isEnabled(local)); - assert.equal(testObject.getEnablementState(local), EnablementState.Enabled); + assert.equal(testObject.getEnablementState(local), EnablementState.EnabledGlobally); }); test('test updating an extension does not re-eanbles it when workspace disabled', async () => { const local = aLocalExtension('pub.a'); - await testObject.setEnablement([local], EnablementState.WorkspaceDisabled); + await testObject.setEnablement([local], EnablementState.DisabledWorkspace); didInstallEvent.fire({ local, identifier: local.identifier, operation: InstallOperation.Update }); assert.ok(!testObject.isEnabled(local)); - assert.equal(testObject.getEnablementState(local), EnablementState.WorkspaceDisabled); + assert.equal(testObject.getEnablementState(local), EnablementState.DisabledWorkspace); }); test('test installing an extension fires enablement change event when workspace disabled', async () => { const local = aLocalExtension('pub.a'); - await testObject.setEnablement([local], EnablementState.WorkspaceDisabled); + await testObject.setEnablement([local], EnablementState.DisabledWorkspace); return new Promise((c, e) => { testObject.onEnablementChanged(([e]) => { if (e.identifier.id === local.identifier.id) { @@ -393,7 +408,7 @@ suite('ExtensionEnablementService Test', () => { test('test updating an extension does not fires enablement change event when workspace disabled', async () => { const target = sinon.spy(); const local = aLocalExtension('pub.a'); - await testObject.setEnablement([local], EnablementState.WorkspaceDisabled); + await testObject.setEnablement([local], EnablementState.DisabledWorkspace); testObject.onEnablementChanged(target); didInstallEvent.fire({ local, identifier: local.identifier, operation: InstallOperation.Update }); assert.ok(!target.called); @@ -409,26 +424,26 @@ suite('ExtensionEnablementService Test', () => { test('test remove an extension from disablement list when uninstalled', async () => { const extension = aLocalExtension('pub.a'); - await testObject.setEnablement([extension], EnablementState.WorkspaceDisabled); - await testObject.setEnablement([extension], EnablementState.Disabled); + await testObject.setEnablement([extension], EnablementState.DisabledWorkspace); + await testObject.setEnablement([extension], EnablementState.DisabledGlobally); didUninstallEvent.fire({ identifier: { id: 'pub.a' } }); assert.ok(testObject.isEnabled(extension)); - assert.equal(testObject.getEnablementState(extension), EnablementState.Enabled); + assert.equal(testObject.getEnablementState(extension), EnablementState.EnabledGlobally); }); test('test isEnabled return false extension is disabled globally', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.Disabled) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledGlobally) .then(() => assert.ok(!testObject.isEnabled(aLocalExtension('pub.a')))); }); test('test isEnabled return false extension is disabled in workspace', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace) .then(() => assert.ok(!testObject.isEnabled(aLocalExtension('pub.a')))); }); test('test isEnabled return true extension is not disabled', () => { - return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.WorkspaceDisabled) - .then(() => testObject.setEnablement([aLocalExtension('pub.c')], EnablementState.Disabled)) + return testObject.setEnablement([aLocalExtension('pub.a')], EnablementState.DisabledWorkspace) + .then(() => testObject.setEnablement([aLocalExtension('pub.c')], EnablementState.DisabledGlobally)) .then(() => assert.ok(testObject.isEnabled(aLocalExtension('pub.b')))); }); @@ -468,22 +483,109 @@ suite('ExtensionEnablementService Test', () => { instantiationService.stub(IExtensionManagementService, { onDidUninstallExtension: didUninstallEvent.event, onDidInstallExtension: didInstallEvent.event, getInstalled: () => Promise.resolve([extension, aLocalExtension('pub.b')]) } as IExtensionManagementService); testObject = new TestExtensionEnablementService(instantiationService); assert.ok(!testObject.isEnabled(extension)); - assert.deepEqual(testObject.getEnablementState(extension), EnablementState.Disabled); + assert.deepEqual(testObject.getEnablementState(extension), EnablementState.DisabledByEnvironemt); + }); + + test('test local workspace extension is disabled by kind', async () => { + instantiationService.stub(IExtensionManagementServerService, aMultiExtensionManagementServerService(instantiationService)); + const localWorkspaceExtension = aLocalExtension2('pub.a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`) }); + testObject = new TestExtensionEnablementService(instantiationService); + assert.ok(!testObject.isEnabled(localWorkspaceExtension)); + assert.deepEqual(testObject.getEnablementState(localWorkspaceExtension), EnablementState.DisabledByExtensionKind); + }); + + test('test local ui extension is not disabled by kind', async () => { + instantiationService.stub(IExtensionManagementServerService, aMultiExtensionManagementServerService(instantiationService)); + const localWorkspaceExtension = aLocalExtension2('pub.a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`) }); + testObject = new TestExtensionEnablementService(instantiationService); + assert.ok(testObject.isEnabled(localWorkspaceExtension)); + assert.deepEqual(testObject.getEnablementState(localWorkspaceExtension), EnablementState.EnabledGlobally); + }); + + test('test canChangeEnablement return false when the local workspace extension is disabled by kind', () => { + instantiationService.stub(IExtensionManagementServerService, aMultiExtensionManagementServerService(instantiationService)); + const localWorkspaceExtension = aLocalExtension2('pub.a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`) }); + testObject = new TestExtensionEnablementService(instantiationService); + assert.equal(testObject.canChangeEnablement(localWorkspaceExtension), false); + }); + + test('test canChangeEnablement return true for local ui extension', () => { + instantiationService.stub(IExtensionManagementServerService, aMultiExtensionManagementServerService(instantiationService)); + const localWorkspaceExtension = aLocalExtension2('pub.a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`) }); + testObject = new TestExtensionEnablementService(instantiationService); + assert.equal(testObject.canChangeEnablement(localWorkspaceExtension), true); + }); + + test('test remote ui extension is disabled by kind', async () => { + instantiationService.stub(IExtensionManagementServerService, aMultiExtensionManagementServerService(instantiationService)); + const localWorkspaceExtension = aLocalExtension2('pub.a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) }); + testObject = new TestExtensionEnablementService(instantiationService); + assert.ok(!testObject.isEnabled(localWorkspaceExtension)); + assert.deepEqual(testObject.getEnablementState(localWorkspaceExtension), EnablementState.DisabledByExtensionKind); + }); + + test('test remote workspace extension is not disabled by kind', async () => { + instantiationService.stub(IExtensionManagementServerService, aMultiExtensionManagementServerService(instantiationService)); + const localWorkspaceExtension = aLocalExtension2('pub.a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) }); + testObject = new TestExtensionEnablementService(instantiationService); + assert.ok(testObject.isEnabled(localWorkspaceExtension)); + assert.deepEqual(testObject.getEnablementState(localWorkspaceExtension), EnablementState.EnabledGlobally); + }); + + test('test canChangeEnablement return false when the remote ui extension is disabled by kind', () => { + instantiationService.stub(IExtensionManagementServerService, aMultiExtensionManagementServerService(instantiationService)); + const localWorkspaceExtension = aLocalExtension2('pub.a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) }); + testObject = new TestExtensionEnablementService(instantiationService); + assert.equal(testObject.canChangeEnablement(localWorkspaceExtension), false); + }); + + test('test canChangeEnablement return true for remote workspace extension', () => { + instantiationService.stub(IExtensionManagementServerService, aMultiExtensionManagementServerService(instantiationService)); + const localWorkspaceExtension = aLocalExtension2('pub.a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) }); + testObject = new TestExtensionEnablementService(instantiationService); + assert.equal(testObject.canChangeEnablement(localWorkspaceExtension), true); }); }); +function aMultiExtensionManagementServerService(instantiationService: TestInstantiationService): IExtensionManagementServerService { + const localExtensionManagementServer = { + authority: 'vscode-local', + label: 'local', + extensionManagementService: instantiationService.get(IExtensionManagementService) + }; + const remoteExtensionManagementServer = { + authority: 'vscode-remote', + label: 'remote', + extensionManagementService: instantiationService.get(IExtensionManagementService) + }; + return { + _serviceBrand: {}, + localExtensionManagementServer, + remoteExtensionManagementServer, + getExtensionManagementServer: (location: URI) => { + if (location.scheme === Schemas.file) { + return localExtensionManagementServer; + } + if (location.scheme === REMOTE_HOST_SCHEME) { + return remoteExtensionManagementServer; + } + return null; + } + }; +} + function aLocalExtension(id: string, contributes?: IExtensionContributions, type?: ExtensionType): ILocalExtension { + return aLocalExtension2(id, contributes ? { contributes } : {}, isUndefinedOrNull(type) ? {} : { type }); +} + +function aLocalExtension2(id: string, manifest: any = {}, properties: any = {}): ILocalExtension { const [publisher, name] = id.split('.'); - type = isUndefinedOrNull(type) ? ExtensionType.User : type; - return Object.create({ + properties = assign({ identifier: { id }, galleryIdentifier: { id, uuid: undefined }, - manifest: { - name, - publisher, - contributes - }, - type - }); + type: ExtensionType.User + }, properties); + manifest = assign({ name, publisher }, manifest); + return Object.create({ manifest, ...properties }); } diff --git a/src/vs/workbench/services/extensions/browser/extensionService.ts b/src/vs/workbench/services/extensions/browser/extensionService.ts new file mode 100644 index 000000000..077598d16 --- /dev/null +++ b/src/vs/workbench/services/extensions/browser/extensionService.ts @@ -0,0 +1,100 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { IExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; +import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IFileService } from 'vs/platform/files/common/files'; +import { IProductService } from 'vs/platform/product/common/product'; +import { AbstractExtensionService } from 'vs/workbench/services/extensions/common/abstractExtensionService'; +import { ExtensionHostProcessManager } from 'vs/workbench/services/extensions/common/extensionHostProcessManager'; +import { RemoteExtensionHostClient, IInitDataProvider } from 'vs/workbench/services/extensions/common/remoteExtensionHostClient'; +import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment'; +import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; + +export class ExtensionService extends AbstractExtensionService implements IExtensionService { + + private _remoteExtensionsEnvironmentData: IRemoteAgentEnvironment | null; + + constructor( + @IInstantiationService instantiationService: IInstantiationService, + @INotificationService notificationService: INotificationService, + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, + @ITelemetryService telemetryService: ITelemetryService, + @IExtensionEnablementService extensionEnablementService: IExtensionEnablementService, + @IFileService fileService: IFileService, + @IProductService productService: IProductService, + @IRemoteAgentService private readonly _remoteAgentService: IRemoteAgentService, + ) { + super( + instantiationService, + notificationService, + environmentService, + telemetryService, + extensionEnablementService, + fileService, + productService, + ); + + this._remoteExtensionsEnvironmentData = null; + this._initialize(); + } + + private _createProvider(remoteAuthority: string): IInitDataProvider { + return { + remoteAuthority: remoteAuthority, + getInitData: () => { + return this.whenInstalledExtensionsRegistered().then(() => { + return this._remoteExtensionsEnvironmentData!; + }); + } + }; + } + + protected _createExtensionHosts(isInitialStart: boolean, initialActivationEvents: string[]): ExtensionHostProcessManager[] { + const result: ExtensionHostProcessManager[] = []; + + const remoteAgentConnection = this._remoteAgentService.getConnection()!; + const remoteExtHostProcessWorker = this._instantiationService.createInstance(RemoteExtensionHostClient, this.getExtensions(), this._createProvider(remoteAgentConnection.remoteAuthority), this._remoteAgentService.socketFactory); + const remoteExtHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, false, remoteExtHostProcessWorker, remoteAgentConnection.remoteAuthority, initialActivationEvents); + result.push(remoteExtHostProcessManager); + + return result; + } + + protected async _scanAndHandleExtensions(): Promise { + // fetch the remote environment + const remoteEnv = (await this._remoteAgentService.getEnvironment())!; + + // enable or disable proposed API per extension + this._checkEnableProposedApi(remoteEnv.extensions); + + // remove disabled extensions + remoteEnv.extensions = remoteEnv.extensions.filter(extension => this._isEnabled(extension)); + + // save for remote extension's init data + this._remoteExtensionsEnvironmentData = remoteEnv; + + // this._handleExtensionPoints(([]).concat(remoteEnv.extensions).concat(localExtensions)); + const result = this._registry.deltaExtensions(remoteEnv.extensions, []); + if (result.removedDueToLooping.length > 0) { + this._logOrShowMessage(Severity.Error, nls.localize('looping', "The following extensions contain dependency loops and have been disabled: {0}", result.removedDueToLooping.map(e => `'${e.identifier.value}'`).join(', '))); + } + + this._doHandleExtensionPoints(this._registry.getAllExtensionDescriptions()); + } + + public _onExtensionHostExit(code: number): void { + console.log(`vscode:exit`, code); + // ipc.send('vscode:exit', code); + } +} + +registerSingleton(IExtensionService, ExtensionService); diff --git a/src/vs/workbench/services/extensions/common/abstractExtensionService.ts b/src/vs/workbench/services/extensions/common/abstractExtensionService.ts new file mode 100644 index 000000000..eed7a6163 --- /dev/null +++ b/src/vs/workbench/services/extensions/common/abstractExtensionService.ts @@ -0,0 +1,498 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { isNonEmptyArray } from 'vs/base/common/arrays'; +import { Barrier } from 'vs/base/common/async'; +import { Emitter, Event } from 'vs/base/common/event'; +import { Disposable } from 'vs/base/common/lifecycle'; +import * as perf from 'vs/base/common/performance'; +import { isEqualOrParent } from 'vs/base/common/resources'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { IExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; +import { BetterMergeId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { ActivationTimes, ExtensionPointContribution, IExtensionService, IExtensionsStatus, IMessage, IWillActivateEvent, IResponsiveStateChangeEvent, toExtension } from 'vs/workbench/services/extensions/common/extensions'; +import { ExtensionMessageCollector, ExtensionPoint, ExtensionsRegistry, IExtensionPoint, IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry'; +import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry'; +import { ResponsiveState } from 'vs/workbench/services/extensions/common/rpcProtocol'; +import { ExtensionHostProcessManager } from 'vs/workbench/services/extensions/common/extensionHostProcessManager'; +import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { IFileService } from 'vs/platform/files/common/files'; +import { parseExtensionDevOptions } from 'vs/workbench/services/extensions/common/extensionDevOptions'; +import { IProductService } from 'vs/platform/product/common/product'; + +const hasOwnProperty = Object.hasOwnProperty; +const NO_OP_VOID_PROMISE = Promise.resolve(undefined); + +export abstract class AbstractExtensionService extends Disposable implements IExtensionService { + + public _serviceBrand: any; + + protected readonly _onDidRegisterExtensions: Emitter = this._register(new Emitter()); + public readonly onDidRegisterExtensions = this._onDidRegisterExtensions.event; + + protected readonly _onDidChangeExtensionsStatus: Emitter = this._register(new Emitter()); + public readonly onDidChangeExtensionsStatus: Event = this._onDidChangeExtensionsStatus.event; + + protected readonly _onDidChangeExtensions: Emitter = this._register(new Emitter()); + public readonly onDidChangeExtensions: Event = this._onDidChangeExtensions.event; + + protected readonly _onWillActivateByEvent = this._register(new Emitter()); + public readonly onWillActivateByEvent: Event = this._onWillActivateByEvent.event; + + protected readonly _onDidChangeResponsiveChange = this._register(new Emitter()); + public readonly onDidChangeResponsiveChange: Event = this._onDidChangeResponsiveChange.event; + + protected readonly _registry: ExtensionDescriptionRegistry; + private readonly _installedExtensionsReady: Barrier; + protected readonly _isDev: boolean; + private readonly _extensionsMessages: Map; + protected readonly _allRequestedActivateEvents = new Set(); + private readonly _proposedApiController: ProposedApiController; + private readonly _isExtensionDevHost: boolean; + protected readonly _isExtensionDevTestFromCli: boolean; + + // --- Members used per extension host process + protected _extensionHostProcessManagers: ExtensionHostProcessManager[]; + protected _extensionHostActiveExtensions: Map; + private _extensionHostProcessActivationTimes: Map; + private _extensionHostExtensionRuntimeErrors: Map; + + constructor( + @IInstantiationService protected readonly _instantiationService: IInstantiationService, + @INotificationService protected readonly _notificationService: INotificationService, + @IWorkbenchEnvironmentService protected readonly _environmentService: IWorkbenchEnvironmentService, + @ITelemetryService protected readonly _telemetryService: ITelemetryService, + @IExtensionEnablementService protected readonly _extensionEnablementService: IExtensionEnablementService, + @IFileService protected readonly _fileService: IFileService, + @IProductService protected readonly _productService: IProductService + ) { + super(); + + // help the file service to activate providers by activating extensions by file system event + this._register(this._fileService.onWillActivateFileSystemProvider(e => { + e.join(this.activateByEvent(`onFileSystem:${e.scheme}`)); + })); + + this._registry = new ExtensionDescriptionRegistry([]); + this._installedExtensionsReady = new Barrier(); + this._isDev = !this._environmentService.isBuilt || this._environmentService.isExtensionDevelopment; + this._extensionsMessages = new Map(); + this._proposedApiController = new ProposedApiController(this._environmentService, this._productService); + + this._extensionHostProcessManagers = []; + this._extensionHostActiveExtensions = new Map(); + this._extensionHostProcessActivationTimes = new Map(); + this._extensionHostExtensionRuntimeErrors = new Map(); + + const devOpts = parseExtensionDevOptions(this._environmentService); + this._isExtensionDevHost = devOpts.isExtensionDevHost; + this._isExtensionDevTestFromCli = devOpts.isExtensionDevTestFromCli; + } + + protected async _initialize(): Promise { + perf.mark('willLoadExtensions'); + this._startExtensionHostProcess(true, []); + this.whenInstalledExtensionsRegistered().then(() => perf.mark('didLoadExtensions')); + await this._scanAndHandleExtensions(); + this._releaseBarrier(); + } + + private _releaseBarrier(): void { + perf.mark('extensionHostReady'); + this._installedExtensionsReady.open(); + this._onDidRegisterExtensions.fire(undefined); + this._onDidChangeExtensionsStatus.fire(this._registry.getAllExtensionDescriptions().map(e => e.identifier)); + } + + private _stopExtensionHostProcess(): void { + let previouslyActivatedExtensionIds: ExtensionIdentifier[] = []; + this._extensionHostActiveExtensions.forEach((value) => { + previouslyActivatedExtensionIds.push(value); + }); + + for (const manager of this._extensionHostProcessManagers) { + manager.dispose(); + } + this._extensionHostProcessManagers = []; + this._extensionHostActiveExtensions = new Map(); + this._extensionHostProcessActivationTimes = new Map(); + this._extensionHostExtensionRuntimeErrors = new Map(); + + if (previouslyActivatedExtensionIds.length > 0) { + this._onDidChangeExtensionsStatus.fire(previouslyActivatedExtensionIds); + } + } + + private _startExtensionHostProcess(isInitialStart: boolean, initialActivationEvents: string[]): void { + this._stopExtensionHostProcess(); + + const processManagers = this._createExtensionHosts(isInitialStart, initialActivationEvents); + processManagers.forEach((processManager) => { + processManager.onDidExit(([code, signal]) => this._onExtensionHostCrashOrExit(processManager, code, signal)); + processManager.onDidChangeResponsiveState((responsiveState) => { this._onDidChangeResponsiveChange.fire({ isResponsive: responsiveState === ResponsiveState.Responsive }); }); + this._extensionHostProcessManagers.push(processManager); + }); + } + + private _onExtensionHostCrashOrExit(extensionHost: ExtensionHostProcessManager, code: number, signal: string | null): void { + + // Unexpected termination + if (!this._isExtensionDevHost) { + this._onExtensionHostCrashed(extensionHost, code, signal); + return; + } + + this._onExtensionHostExit(code); + } + + protected _onExtensionHostCrashed(extensionHost: ExtensionHostProcessManager, code: number, signal: string | null): void { + console.error('Extension host terminated unexpectedly. Code: ', code, ' Signal: ', signal); + this._stopExtensionHostProcess(); + } + + //#region IExtensionService + + public canAddExtension(extension: IExtensionDescription): boolean { + return false; + } + + public canRemoveExtension(extension: IExtensionDescription): boolean { + return false; + } + + public restartExtensionHost(): void { + this._stopExtensionHostProcess(); + this._startExtensionHostProcess(false, Array.from(this._allRequestedActivateEvents.keys())); + } + + public startExtensionHost(): void { + this._startExtensionHostProcess(false, Array.from(this._allRequestedActivateEvents.keys())); + } + + public stopExtensionHost(): void { + this._stopExtensionHostProcess(); + } + + public activateByEvent(activationEvent: string): Promise { + if (this._installedExtensionsReady.isOpen()) { + // Extensions have been scanned and interpreted + + // Record the fact that this activationEvent was requested (in case of a restart) + this._allRequestedActivateEvents.add(activationEvent); + + if (!this._registry.containsActivationEvent(activationEvent)) { + // There is no extension that is interested in this activation event + return NO_OP_VOID_PROMISE; + } + + return this._activateByEvent(activationEvent); + } else { + // Extensions have not been scanned yet. + + // Record the fact that this activationEvent was requested (in case of a restart) + this._allRequestedActivateEvents.add(activationEvent); + + return this._installedExtensionsReady.wait().then(() => this._activateByEvent(activationEvent)); + } + } + + private _activateByEvent(activationEvent: string): Promise { + const result = Promise.all( + this._extensionHostProcessManagers.map(extHostManager => extHostManager.activateByEvent(activationEvent)) + ).then(() => { }); + this._onWillActivateByEvent.fire({ + event: activationEvent, + activation: result + }); + return result; + } + + public whenInstalledExtensionsRegistered(): Promise { + return this._installedExtensionsReady.wait(); + } + + public getExtensions(): Promise { + return this._installedExtensionsReady.wait().then(() => { + return this._registry.getAllExtensionDescriptions(); + }); + } + + public getExtension(id: string): Promise { + return this._installedExtensionsReady.wait().then(() => { + return this._registry.getExtensionDescription(id); + }); + } + + public readExtensionPointContributions(extPoint: IExtensionPoint): Promise[]> { + return this._installedExtensionsReady.wait().then(() => { + const availableExtensions = this._registry.getAllExtensionDescriptions(); + + const result: ExtensionPointContribution[] = []; + for (const desc of availableExtensions) { + if (desc.contributes && hasOwnProperty.call(desc.contributes, extPoint.name)) { + result.push(new ExtensionPointContribution(desc, desc.contributes[extPoint.name as keyof typeof desc.contributes])); + } + } + + return result; + }); + } + + public getExtensionsStatus(): { [id: string]: IExtensionsStatus; } { + let result: { [id: string]: IExtensionsStatus; } = Object.create(null); + if (this._registry) { + const extensions = this._registry.getAllExtensionDescriptions(); + for (const extension of extensions) { + const extensionKey = ExtensionIdentifier.toKey(extension.identifier); + result[extension.identifier.value] = { + messages: this._extensionsMessages.get(extensionKey) || [], + activationTimes: this._extensionHostProcessActivationTimes.get(extensionKey), + runtimeErrors: this._extensionHostExtensionRuntimeErrors.get(extensionKey) || [], + }; + } + } + return result; + } + + public getInspectPort(): number { + return 0; + } + + //#endregion + + // --- impl + + protected _checkEnableProposedApi(extensions: IExtensionDescription[]): void { + for (let extension of extensions) { + this._proposedApiController.updateEnableProposedApi(extension); + } + } + + private _isExtensionUnderDevelopment(extension: IExtensionDescription): boolean { + if (this._environmentService.isExtensionDevelopment) { + const extDevLocs = this._environmentService.extensionDevelopmentLocationURI; + if (extDevLocs) { + const extLocation = extension.extensionLocation; + for (let p of extDevLocs) { + if (isEqualOrParent(extLocation, p)) { + return true; + } + } + } + } + return false; + } + + protected _isEnabled(extension: IExtensionDescription): boolean { + if (this._isExtensionUnderDevelopment(extension)) { + // Never disable extensions under development + return true; + } + + if (ExtensionIdentifier.equals(extension.identifier, BetterMergeId)) { + // Check if this is the better merge extension which was migrated to a built-in extension + return false; + } + + return this._extensionEnablementService.isEnabled(toExtension(extension)); + } + + protected _doHandleExtensionPoints(affectedExtensions: IExtensionDescription[]): void { + const affectedExtensionPoints: { [extPointName: string]: boolean; } = Object.create(null); + for (let extensionDescription of affectedExtensions) { + if (extensionDescription.contributes) { + for (let extPointName in extensionDescription.contributes) { + if (hasOwnProperty.call(extensionDescription.contributes, extPointName)) { + affectedExtensionPoints[extPointName] = true; + } + } + } + } + + const messageHandler = (msg: IMessage) => this._handleExtensionPointMessage(msg); + const availableExtensions = this._registry.getAllExtensionDescriptions(); + const extensionPoints = ExtensionsRegistry.getExtensionPoints(); + for (const extensionPoint of extensionPoints) { + if (affectedExtensionPoints[extensionPoint.name]) { + AbstractExtensionService._handleExtensionPoint(extensionPoint, availableExtensions, messageHandler); + } + } + } + + private _handleExtensionPointMessage(msg: IMessage) { + const extensionKey = ExtensionIdentifier.toKey(msg.extensionId); + + if (!this._extensionsMessages.has(extensionKey)) { + this._extensionsMessages.set(extensionKey, []); + } + this._extensionsMessages.get(extensionKey)!.push(msg); + + const extension = this._registry.getExtensionDescription(msg.extensionId); + const strMsg = `[${msg.extensionId.value}]: ${msg.message}`; + if (extension && extension.isUnderDevelopment) { + // This message is about the extension currently being developed + this._showMessageToUser(msg.type, strMsg); + } else { + this._logMessageInConsole(msg.type, strMsg); + } + + if (!this._isDev && msg.extensionId) { + const { type, extensionId, extensionPointId, message } = msg; + type ExtensionsMessageClassification = { + type: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; + extensionId: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth' }; + extensionPointId: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth' }; + message: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth' }; + }; + type ExtensionsMessageEvent = { + type: Severity; + extensionId: string; + extensionPointId: string; + message: string; + }; + this._telemetryService.publicLog2('extensionsMessage', { + type, extensionId: extensionId.value, extensionPointId, message + }); + } + } + + private static _handleExtensionPoint(extensionPoint: ExtensionPoint, availableExtensions: IExtensionDescription[], messageHandler: (msg: IMessage) => void): void { + const users: IExtensionPointUser[] = []; + for (const desc of availableExtensions) { + if (desc.contributes && hasOwnProperty.call(desc.contributes, extensionPoint.name)) { + users.push({ + description: desc, + value: desc.contributes[extensionPoint.name as keyof typeof desc.contributes], + collector: new ExtensionMessageCollector(messageHandler, desc, extensionPoint.name) + }); + } + } + perf.mark(`willHandleExtensionPoint/${extensionPoint.name}`); + extensionPoint.acceptUsers(users); + perf.mark(`didHandleExtensionPoint/${extensionPoint.name}`); + } + + private _showMessageToUser(severity: Severity, msg: string): void { + if (severity === Severity.Error || severity === Severity.Warning) { + this._notificationService.notify({ severity, message: msg }); + } else { + this._logMessageInConsole(severity, msg); + } + } + + private _logMessageInConsole(severity: Severity, msg: string): void { + if (severity === Severity.Error) { + console.error(msg); + } else if (severity === Severity.Warning) { + console.warn(msg); + } else { + console.log(msg); + } + } + + //#region Called by extension host + + public _logOrShowMessage(severity: Severity, msg: string): void { + if (this._isDev) { + this._showMessageToUser(severity, msg); + } else { + this._logMessageInConsole(severity, msg); + } + } + + public async _activateById(extensionId: ExtensionIdentifier, activationEvent: string): Promise { + const results = await Promise.all( + this._extensionHostProcessManagers.map(manager => manager.activate(extensionId, activationEvent)) + ); + const activated = results.some(e => e); + if (!activated) { + throw new Error(`Unknown extension ${extensionId.value}`); + } + } + + public _onWillActivateExtension(extensionId: ExtensionIdentifier): void { + this._extensionHostActiveExtensions.set(ExtensionIdentifier.toKey(extensionId), extensionId); + } + + public _onDidActivateExtension(extensionId: ExtensionIdentifier, startup: boolean, codeLoadingTime: number, activateCallTime: number, activateResolvedTime: number, activationEvent: string): void { + this._extensionHostProcessActivationTimes.set(ExtensionIdentifier.toKey(extensionId), new ActivationTimes(startup, codeLoadingTime, activateCallTime, activateResolvedTime, activationEvent)); + this._onDidChangeExtensionsStatus.fire([extensionId]); + } + + public _onExtensionRuntimeError(extensionId: ExtensionIdentifier, err: Error): void { + const extensionKey = ExtensionIdentifier.toKey(extensionId); + if (!this._extensionHostExtensionRuntimeErrors.has(extensionKey)) { + this._extensionHostExtensionRuntimeErrors.set(extensionKey, []); + } + this._extensionHostExtensionRuntimeErrors.get(extensionKey)!.push(err); + this._onDidChangeExtensionsStatus.fire([extensionId]); + } + + //#endregion + + protected abstract _createExtensionHosts(isInitialStart: boolean, initialActivationEvents: string[]): ExtensionHostProcessManager[]; + protected abstract _scanAndHandleExtensions(): Promise; + public abstract _onExtensionHostExit(code: number): void; +} + +class ProposedApiController { + + private readonly enableProposedApiFor: string | string[]; + private readonly enableProposedApiForAll: boolean; + private readonly productAllowProposedApi: Set; + + constructor( + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, + @IProductService productService: IProductService + ) { + this.enableProposedApiFor = environmentService.args['enable-proposed-api'] || []; + if (this.enableProposedApiFor.length) { + // Make enabled proposed API be lowercase for case insensitive comparison + if (Array.isArray(this.enableProposedApiFor)) { + this.enableProposedApiFor = this.enableProposedApiFor.map(id => id.toLowerCase()); + } else { + this.enableProposedApiFor = this.enableProposedApiFor.toLowerCase(); + } + } + + this.enableProposedApiForAll = !environmentService.isBuilt || + (!!environmentService.extensionDevelopmentLocationURI && productService.nameLong !== 'Visual Studio Code') || + (this.enableProposedApiFor.length === 0 && 'enable-proposed-api' in environmentService.args); + + this.productAllowProposedApi = new Set(); + if (isNonEmptyArray(productService.extensionAllowedProposedApi)) { + productService.extensionAllowedProposedApi.forEach((id) => this.productAllowProposedApi.add(ExtensionIdentifier.toKey(id))); + } + } + + public updateEnableProposedApi(extension: IExtensionDescription): void { + if (this._allowProposedApiFromProduct(extension.identifier)) { + // fast lane -> proposed api is available to all extensions + // that are listed in product.json-files + extension.enableProposedApi = true; + + } else if (extension.enableProposedApi && !extension.isBuiltin) { + if ( + !this.enableProposedApiForAll && + this.enableProposedApiFor.indexOf(extension.identifier.value.toLowerCase()) < 0 + ) { + extension.enableProposedApi = false; + console.error(`Extension '${extension.identifier.value} cannot use PROPOSED API (must started out of dev or enabled via --enable-proposed-api)`); + + } else { + // proposed api is available when developing or when an extension was explicitly + // spelled out via a command line argument + console.warn(`Extension '${extension.identifier.value}' uses PROPOSED API which is subject to change and removal without notice.`); + } + } + } + + private _allowProposedApiFromProduct(id: ExtensionIdentifier): boolean { + return this.productAllowProposedApi.has(ExtensionIdentifier.toKey(id)); + } +} diff --git a/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts b/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts index 4e63fa924..21cddb137 100644 --- a/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts +++ b/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts @@ -14,7 +14,7 @@ import { ExtHostCustomersRegistry } from 'vs/workbench/api/common/extHostCustome import { ExtHostContext, ExtHostExtensionServiceShape, IExtHostContext, MainContext } from 'vs/workbench/api/common/extHost.protocol'; import { ProxyIdentifier } from 'vs/workbench/services/extensions/common/proxyIdentifier'; import { IRPCProtocolLogger, RPCProtocol, RequestInitiator, ResponsiveState } from 'vs/workbench/services/extensions/common/rpcProtocol'; -import { ResolvedAuthority, RemoteAuthorityResolverError } from 'vs/platform/remote/common/remoteAuthorityResolver'; +import { RemoteAuthorityResolverError, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import * as nls from 'vs/nls'; import { Action } from 'vs/base/common/actions'; @@ -35,7 +35,7 @@ const NO_OP_VOID_PROMISE = Promise.resolve(undefined); export class ExtensionHostProcessManager extends Disposable { - public readonly onDidCrash: Event<[number, string | null]>; + public readonly onDidExit: Event<[number, string | null]>; private readonly _onDidChangeResponsiveState: Emitter = this._register(new Emitter()); public readonly onDidChangeResponsiveState: Event = this._onDidChangeResponsiveState.event; @@ -54,6 +54,7 @@ export class ExtensionHostProcessManager extends Disposable { private _resolveAuthorityAttempt: number; constructor( + public readonly isLocal: boolean, extensionHostProcessWorker: IExtensionHostStarter, private readonly _remoteAuthority: string, initialActivationEvents: string[], @@ -66,7 +67,7 @@ export class ExtensionHostProcessManager extends Disposable { this._extensionHostProcessCustomers = []; this._extensionHostProcessWorker = extensionHostProcessWorker; - this.onDidCrash = this._extensionHostProcessWorker.onCrashed; + this.onDidExit = this._extensionHostProcessWorker.onExit; this._extensionHostProcessProxy = this._extensionHostProcessWorker.start()!.then( (protocol) => { return { value: this._createExtensionHostCustomers(protocol) }; @@ -246,15 +247,17 @@ export class ExtensionHostProcessManager extends Disposable { return this._extensionHostProcessWorker && Boolean(this._extensionHostProcessWorker.getInspectPort()); } - public async resolveAuthority(remoteAuthority: string): Promise { + public async resolveAuthority(remoteAuthority: string): Promise { const authorityPlusIndex = remoteAuthority.indexOf('+'); if (authorityPlusIndex === -1) { // This authority does not need to be resolved, simply parse the port number const pieces = remoteAuthority.split(':'); return Promise.resolve({ - authority: remoteAuthority, - host: pieces[0], - port: parseInt(pieces[1], 10) + authority: { + authority: remoteAuthority, + host: pieces[0], + port: parseInt(pieces[1], 10) + } }); } const proxy = await this._getExtensionHostProcessProxy(); diff --git a/src/vs/workbench/services/extensions/common/extensionHostProtocol.ts b/src/vs/workbench/services/extensions/common/extensionHostProtocol.ts index bfba4c230..f85f7fa40 100644 --- a/src/vs/workbench/services/extensions/common/extensionHostProtocol.ts +++ b/src/vs/workbench/services/extensions/common/extensionHostProtocol.ts @@ -12,6 +12,7 @@ export interface IExtHostReadyMessage { export interface IExtHostSocketMessage { type: 'VSCODE_EXTHOST_IPC_SOCKET'; initialDataChunk: string; + skipWebSocketFrames: boolean; } export const enum MessageType { diff --git a/src/vs/workbench/services/extensions/common/extensionPoints.ts b/src/vs/workbench/services/extensions/common/extensionPoints.ts new file mode 100644 index 000000000..58a5a4835 --- /dev/null +++ b/src/vs/workbench/services/extensions/common/extensionPoints.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 { Severity } from 'vs/platform/notification/common/notification'; + +export interface Translations { + [id: string]: string; +} + +export namespace Translations { + export function equals(a: Translations, b: Translations): boolean { + if (a === b) { + return true; + } + let aKeys = Object.keys(a); + let bKeys: Set = new Set(); + for (let key of Object.keys(b)) { + bKeys.add(key); + } + if (aKeys.length !== bKeys.size) { + return false; + } + + for (let key of aKeys) { + if (a[key] !== b[key]) { + return false; + } + bKeys.delete(key); + } + return bKeys.size === 0; + } +} + +export interface ILog { + error(source: string, message: string): void; + warn(source: string, message: string): void; + info(source: string, message: string): void; +} + +export class Logger implements ILog { + + private readonly _messageHandler: (severity: Severity, source: string, message: string) => void; + + constructor( + messageHandler: (severity: Severity, source: string, message: string) => void + ) { + this._messageHandler = messageHandler; + } + + public error(source: string, message: string): void { + this._messageHandler(Severity.Error, source, message); + } + + public warn(source: string, message: string): void { + this._messageHandler(Severity.Warning, source, message); + } + + public info(source: string, message: string): void { + this._messageHandler(Severity.Info, source, message); + } +} diff --git a/src/vs/workbench/services/extensions/common/extensions.ts b/src/vs/workbench/services/extensions/common/extensions.ts index 2daf6549b..1bd329231 100644 --- a/src/vs/workbench/services/extensions/common/extensions.ts +++ b/src/vs/workbench/services/extensions/common/extensions.ts @@ -84,7 +84,8 @@ export interface IExtensionHostProfile { } export interface IExtensionHostStarter { - readonly onCrashed: Event<[number, string | null]>; + readonly onExit: Event<[number, string | null]>; + start(): Promise | null; getInspectPort(): number | undefined; dispose(): void; diff --git a/src/vs/workbench/services/extensions/common/extensionsRegistry.ts b/src/vs/workbench/services/extensions/common/extensionsRegistry.ts index 6fc035817..9776a42da 100644 --- a/src/vs/workbench/services/extensions/common/extensionsRegistry.ts +++ b/src/vs/workbench/services/extensions/common/extensionsRegistry.ts @@ -206,7 +206,7 @@ export const schema = { type: 'object', properties: { // extensions will fill in - }, + } as { [key: string]: any }, default: {} }, preview: { @@ -341,6 +341,19 @@ export const schema = { pattern: EXTENSION_IDENTIFIER_PATTERN } }, + extensionKind: { + description: nls.localize('extensionKind', "Define the kind of an extension. `ui` extensions are installed and run on the local machine while `workspace` extensions are run on the remote."), + type: 'string', + enum: [ + 'ui', + 'workspace' + ], + enumDescriptions: [ + nls.localize('ui', "UI extension kind. In a remote window, such extensions are enabled only when available on the local machine."), + nls.localize('workspace', "Workspace extension kind. In a remote window, such extensions are enabled only when available on the remote.") + ], + default: 'workspace' + }, scripts: { type: 'object', properties: { diff --git a/src/vs/workbench/services/extensions/common/extensionsUtil.ts b/src/vs/workbench/services/extensions/common/extensionsUtil.ts new file mode 100644 index 000000000..e03ddb102 --- /dev/null +++ b/src/vs/workbench/services/extensions/common/extensionsUtil.ts @@ -0,0 +1,53 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IExtensionManifest } from 'vs/platform/extensions/common/extensions'; +import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; +import { getGalleryExtensionId, areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { isNonEmptyArray } from 'vs/base/common/arrays'; +import { IProductService } from 'vs/platform/product/common/product'; + +export function isUIExtension(manifest: IExtensionManifest, productService: IProductService, configurationService: IConfigurationService): boolean { + const uiContributions = ExtensionsRegistry.getExtensionPoints().filter(e => e.defaultExtensionKind !== 'workspace').map(e => e.name); + const extensionId = getGalleryExtensionId(manifest.publisher, manifest.name); + const extensionKind = getExtensionKind(manifest, configurationService); + switch (extensionKind) { + case 'ui': return true; + case 'workspace': return false; + default: { + // Tagged as UI extension in product + if (isNonEmptyArray(productService.uiExtensions) && productService.uiExtensions.some(id => areSameExtensions({ id }, { id: extensionId }))) { + return true; + } + // Not an UI extension if it has main + if (manifest.main) { + return false; + } + // Not an UI extension if it has dependencies or an extension pack + if (isNonEmptyArray(manifest.extensionDependencies) || isNonEmptyArray(manifest.extensionPack)) { + return false; + } + if (manifest.contributes) { + // Not an UI extension if it has no ui contributions + if (!uiContributions.length || Object.keys(manifest.contributes).some(contribution => uiContributions.indexOf(contribution) === -1)) { + return false; + } + } + return true; + } + } +} + +function getExtensionKind(manifest: IExtensionManifest, configurationService: IConfigurationService): string | undefined { + const extensionId = getGalleryExtensionId(manifest.publisher, manifest.name); + const configuredExtensionKinds = configurationService.getValue<{ [key: string]: string }>('remote.extensionKind') || {}; + for (const id of Object.keys(configuredExtensionKinds)) { + if (areSameExtensions({ id: extensionId }, { id })) { + return configuredExtensionKinds[id]; + } + } + return manifest.extensionKind; +} diff --git a/src/vs/workbench/services/extensions/common/inactiveExtensionUrlHandler.ts b/src/vs/workbench/services/extensions/common/inactiveExtensionUrlHandler.ts index 263a45a98..7330ceede 100644 --- a/src/vs/workbench/services/extensions/common/inactiveExtensionUrlHandler.ts +++ b/src/vs/workbench/services/extensions/common/inactiveExtensionUrlHandler.ts @@ -5,10 +5,12 @@ import { localize } from 'vs/nls'; import { Action } from 'vs/base/common/actions'; -import { IDisposable, combinedDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, toDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { EnablementState, IExtensionEnablementService, IExtensionGalleryService, IExtensionIdentifier, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionGalleryService, IExtensionIdentifier, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionEnablementService, EnablementState } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { INotificationHandle, INotificationService, Severity } from 'vs/platform/notification/common/notification'; @@ -22,6 +24,8 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; const FIVE_MINUTES = 5 * 60 * 1000; const THIRTY_SECONDS = 30 * 1000; const URL_TO_HANDLE = 'extensionUrlHandler.urlToHandle'; +const CONFIRMED_EXTENSIONS_CONFIGURATION_KEY = 'extensions.confirmedUriHandlerExtensionIds'; +const CONFIRMED_EXTENSIONS_STORAGE_KEY = 'extensionUrlHandler.confirmedExtensions'; function isExtensionId(value: string): boolean { return /^[a-z0-9][a-z0-9\-]*\.[a-z0-9][a-z0-9\-]*$/i.test(value); @@ -61,7 +65,9 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { @IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService, @IWindowService private readonly windowService: IWindowService, @IExtensionGalleryService private readonly galleryService: IExtensionGalleryService, - @IStorageService private readonly storageService: IStorageService + @IStorageService private readonly storageService: IStorageService, + @IConfigurationService private readonly configurationService: IConfigurationService + ) { const interval = setInterval(() => this.garbageCollect(), THIRTY_SECONDS); const urlToHandleValue = this.storageService.get(URL_TO_HANDLE, StorageScope.WORKSPACE); @@ -70,10 +76,10 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { this.handleURL(URI.revive(JSON.parse(urlToHandleValue)), true); } - this.disposable = combinedDisposable([ + this.disposable = combinedDisposable( urlService.registerHandler(this), toDisposable(() => clearInterval(interval)) - ]); + ); } async handleURL(uri: URI, confirmed?: boolean): Promise { @@ -90,6 +96,11 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { return true; } + if (!confirmed) { + const confirmedExtensionIds = this.getConfirmedExtensionIds(); + confirmed = confirmedExtensionIds.has(ExtensionIdentifier.toKey(extensionId)); + } + if (!confirmed) { let uriString = uri.toString(); @@ -99,6 +110,9 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { const result = await this.dialogService.confirm({ message: localize('confirmUrl', "Allow an extension to open this URL?", extensionId), + checkbox: { + label: localize('rememberConfirmUrl', "Don't ask again for this extension."), + }, detail: `${extension.displayName || extension.name} (${extensionId}) wants to open a URL:\n\n${uriString}`, primaryButton: localize('open', "&&Open"), type: 'question' @@ -107,6 +121,10 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { if (!result.confirmed) { return true; } + + if (result.checkboxChecked) { + this.addConfirmedExtensionIdToStorage(extensionId); + } } const handler = this.extensionHandlers.get(ExtensionIdentifier.toKey(extensionId)); @@ -190,7 +208,7 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { return; } - await this.extensionEnablementService.setEnablement([extension], EnablementState.Enabled); + await this.extensionEnablementService.setEnablement([extension], EnablementState.EnabledGlobally); await this.reloadAndHandle(uri); } } @@ -266,6 +284,47 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { this.uriBuffer = uriBuffer; } + private getConfirmedExtensionIds(): Set { + const ids = [ + ...this.getConfirmedExtensionIdsFromStorage(), + ...this.getConfirmedExtensionIdsFromConfiguration(), + ].map(extensionId => ExtensionIdentifier.toKey(extensionId)); + + return new Set(ids); + } + + private getConfirmedExtensionIdsFromConfiguration(): Array { + const confirmedExtensionIds = this.configurationService.getValue>(CONFIRMED_EXTENSIONS_CONFIGURATION_KEY); + + if (!Array.isArray(confirmedExtensionIds)) { + return []; + } + + return confirmedExtensionIds; + } + + private getConfirmedExtensionIdsFromStorage(): Array { + const confirmedExtensionIdsJson = this.storageService.get(CONFIRMED_EXTENSIONS_STORAGE_KEY, StorageScope.GLOBAL, '[]'); + + try { + return JSON.parse(confirmedExtensionIdsJson); + } catch (err) { + return []; + } + } + + private addConfirmedExtensionIdToStorage(extensionId: string): void { + const existingConfirmedExtensionIds = this.getConfirmedExtensionIdsFromStorage(); + this.storageService.store( + CONFIRMED_EXTENSIONS_STORAGE_KEY, + JSON.stringify([ + ...existingConfirmedExtensionIds, + ExtensionIdentifier.toKey(extensionId), + ]), + StorageScope.GLOBAL, + ); + } + dispose(): void { this.disposable.dispose(); this.extensionHandlers.clear(); diff --git a/src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts b/src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts new file mode 100644 index 000000000..037a2534d --- /dev/null +++ b/src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts @@ -0,0 +1,243 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Emitter, Event } from 'vs/base/common/event'; +import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { ILabelService } from 'vs/platform/label/common/label'; +import { ILogService } from 'vs/platform/log/common/log'; +import { connectRemoteAgentExtensionHost, IRemoteExtensionHostStartParams, IConnectionOptions, ISocketFactory } from 'vs/platform/remote/common/remoteAgentConnection'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; +import { IInitData } from 'vs/workbench/api/common/extHost.protocol'; +import { MessageType, createMessageOfType, isMessageOfType } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; +import { IExtensionHostStarter } from 'vs/workbench/services/extensions/common/extensions'; +import { parseExtensionDevOptions } from 'vs/workbench/services/extensions/common/extensionDevOptions'; +import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment'; +import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; +import * as platform from 'vs/base/common/platform'; +import { Schemas } from 'vs/base/common/network'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; +import { PersistentProtocol } from 'vs/base/parts/ipc/common/ipc.net'; +import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { VSBuffer } from 'vs/base/common/buffer'; +import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug'; +import { IProductService } from 'vs/platform/product/common/product'; +import { ISignService } from 'vs/platform/sign/common/sign'; + +export interface IInitDataProvider { + readonly remoteAuthority: string; + getInitData(): Promise; +} + +export class RemoteExtensionHostClient extends Disposable implements IExtensionHostStarter { + + private _onExit: Emitter<[number, string | null]> = this._register(new Emitter<[number, string | null]>()); + public readonly onExit: Event<[number, string | null]> = this._onExit.event; + + private _protocol: PersistentProtocol | null; + + private readonly _isExtensionDevHost: boolean; + + private _terminating: boolean; + + constructor( + private readonly _allExtensions: Promise, + private readonly _initDataProvider: IInitDataProvider, + private readonly _socketFactory: ISocketFactory, + @IWorkspaceContextService private readonly _contextService: IWorkspaceContextService, + @IEnvironmentService private readonly _environmentService: IEnvironmentService, + @ITelemetryService private readonly _telemetryService: ITelemetryService, + @ILifecycleService private readonly _lifecycleService: ILifecycleService, + @ILogService private readonly _logService: ILogService, + @ILabelService private readonly _labelService: ILabelService, + @IRemoteAuthorityResolverService private readonly remoteAuthorityResolverService: IRemoteAuthorityResolverService, + @IExtensionHostDebugService private readonly _extensionHostDebugService: IExtensionHostDebugService, + @IProductService private readonly _productService: IProductService, + @ISignService private readonly _signService: ISignService + ) { + super(); + this._protocol = null; + this._terminating = false; + + this._register(this._lifecycleService.onShutdown(reason => this.dispose())); + + const devOpts = parseExtensionDevOptions(this._environmentService); + this._isExtensionDevHost = devOpts.isExtensionDevHost; + } + + public start(): Promise { + const options: IConnectionOptions = { + isBuilt: this._environmentService.isBuilt, + commit: this._productService.commit, + socketFactory: this._socketFactory, + addressProvider: { + getAddress: async () => { + const { authority } = await this.remoteAuthorityResolverService.resolveAuthority(this._initDataProvider.remoteAuthority); + return { host: authority.host, port: authority.port }; + } + }, + signService: this._signService + }; + return this.remoteAuthorityResolverService.resolveAuthority(this._initDataProvider.remoteAuthority).then((resolverResult) => { + + const startParams: IRemoteExtensionHostStartParams = { + language: platform.language, + debugId: this._environmentService.debugExtensionHost.debugId, + break: this._environmentService.debugExtensionHost.break, + port: this._environmentService.debugExtensionHost.port, + env: resolverResult.options && resolverResult.options.extensionHostEnv + }; + + const extDevLocs = this._environmentService.extensionDevelopmentLocationURI; + + let debugOk = true; + if (extDevLocs && extDevLocs.length > 0) { + // TODO@AW: handles only first path in array + if (extDevLocs[0].scheme === Schemas.file) { + debugOk = false; + } + } + + if (!debugOk) { + startParams.break = false; + } + + return connectRemoteAgentExtensionHost(options, startParams).then(result => { + let { protocol, debugPort } = result; + const isExtensionDevelopmentDebug = typeof debugPort === 'number'; + if (debugOk && this._environmentService.isExtensionDevelopment && this._environmentService.debugExtensionHost.debugId && debugPort) { + this._extensionHostDebugService.attachSession(this._environmentService.debugExtensionHost.debugId, debugPort, this._initDataProvider.remoteAuthority); + } + + protocol.onClose(() => { + this._onExtHostConnectionLost(); + }); + + protocol.onSocketClose(() => { + if (this._isExtensionDevHost) { + this._onExtHostConnectionLost(); + } + }); + + // 1) wait for the incoming `ready` event and send the initialization data. + // 2) wait for the incoming `initialized` event. + return new Promise((resolve, reject) => { + + let handle = setTimeout(() => { + reject('timeout'); + }, 60 * 1000); + + const disposable = protocol.onMessage(msg => { + + if (isMessageOfType(msg, MessageType.Ready)) { + // 1) Extension Host is ready to receive messages, initialize it + this._createExtHostInitData(isExtensionDevelopmentDebug).then(data => protocol.send(VSBuffer.fromString(JSON.stringify(data)))); + return; + } + + if (isMessageOfType(msg, MessageType.Initialized)) { + // 2) Extension Host is initialized + + clearTimeout(handle); + + // stop listening for messages here + disposable.dispose(); + + // release this promise + this._protocol = protocol; + resolve(protocol); + return; + } + + console.error(`received unexpected message during handshake phase from the extension host: `, msg); + }); + + }); + }); + }); + } + + private _onExtHostConnectionLost(): void { + + if (this._isExtensionDevHost && this._environmentService.debugExtensionHost.debugId) { + this._extensionHostDebugService.close(this._environmentService.debugExtensionHost.debugId); + } + + if (this._terminating) { + // Expected termination path (we asked the process to terminate) + return; + } + + this._onExit.fire([0, null]); + } + + private _createExtHostInitData(isExtensionDevelopmentDebug: boolean): Promise { + return Promise.all([this._allExtensions, this._telemetryService.getTelemetryInfo(), this._initDataProvider.getInitData()]).then(([allExtensions, telemetryInfo, remoteExtensionHostData]) => { + // Collect all identifiers for extension ids which can be considered "resolved" + const resolvedExtensions = allExtensions.filter(extension => !extension.main).map(extension => extension.identifier); + const hostExtensions = allExtensions.filter(extension => extension.main && extension.api === 'none').map(extension => extension.identifier); + const workspace = this._contextService.getWorkspace(); + const r: IInitData = { + commit: this._productService.commit, + version: this._productService.version, + parentPid: remoteExtensionHostData.pid, + environment: { + isExtensionDevelopmentDebug, + appRoot: remoteExtensionHostData.appRoot, + appSettingsHome: remoteExtensionHostData.appSettingsHome, + appName: this._productService.nameLong, + appUriScheme: this._productService.urlProtocol, + appLanguage: platform.language, + extensionDevelopmentLocationURI: this._environmentService.extensionDevelopmentLocationURI, + extensionTestsLocationURI: this._environmentService.extensionTestsLocationURI, + globalStorageHome: remoteExtensionHostData.globalStorageHome, + userHome: remoteExtensionHostData.userHome, + webviewResourceRoot: this._environmentService.webviewResourceRoot, + webviewCspSource: this._environmentService.webviewCspSource, + }, + workspace: this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? null : { + configuration: workspace.configuration, + id: workspace.id, + name: this._labelService.getWorkspaceLabel(workspace) + }, + remote: { + isRemote: true, + authority: this._initDataProvider.remoteAuthority + }, + resolvedExtensions: resolvedExtensions, + hostExtensions: hostExtensions, + extensions: remoteExtensionHostData.extensions, + telemetryInfo, + logLevel: this._logService.getLevel(), + logsLocation: remoteExtensionHostData.extensionHostLogsPath, + autoStart: true, + }; + return r; + }); + } + + getInspectPort(): number | undefined { + return undefined; + } + + dispose(): void { + super.dispose(); + + this._terminating = true; + + if (this._protocol) { + // Send the extension host a request to terminate itself + // (graceful termination) + const socket = this._protocol.getSocket(); + this._protocol.send(createMessageOfType(MessageType.Terminate)); + this._protocol.sendDisconnect(); + this._protocol.dispose(); + socket.end(); + this._protocol = null; + } + } +} diff --git a/src/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts b/src/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts index 40a8c8363..10fd66cbd 100644 --- a/src/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts +++ b/src/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts @@ -15,13 +15,14 @@ import { originalFSPath } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import * as pfs from 'vs/base/node/pfs'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { BUILTIN_MANIFEST_CACHE_FILE, MANIFEST_CACHE_FOLDER, USER_MANIFEST_CACHE_FILE, ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import pkg from 'vs/platform/product/node/package'; import product from 'vs/platform/product/node/product'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { IWindowService } from 'vs/platform/windows/common/windows'; -import { ExtensionScanner, ExtensionScannerInput, IExtensionReference, IExtensionResolver, ILog, IRelaxedExtensionDescription, Translations } from 'vs/workbench/services/extensions/node/extensionPoints'; +import { ExtensionScanner, ExtensionScannerInput, IExtensionReference, IExtensionResolver, IRelaxedExtensionDescription } from 'vs/workbench/services/extensions/node/extensionPoints'; +import { Translations, ILog } from 'vs/workbench/services/extensions/common/extensionPoints'; interface IExtensionCacheData { input: ExtensionScannerInput; @@ -100,10 +101,6 @@ export class CachedExtensionScanner { development.forEach(developedExtension => { log.info('', nls.localize('extensionUnderDevelopment', "Loading development extension at {0}", developedExtension.extensionLocation.fsPath)); const extensionKey = ExtensionIdentifier.toKey(developedExtension.identifier); - const extension = result.get(extensionKey); - if (extension) { - log.warn(developedExtension.extensionLocation.fsPath, nls.localize('overwritingExtension', "Overwriting extension {0} with {1}.", extension.extensionLocation.fsPath, developedExtension.extensionLocation.fsPath)); - } result.set(extensionKey, developedExtension); }); let r: IExtensionDescription[] = []; @@ -387,26 +384,3 @@ class NullLogger implements ILog { public info(source: string, message: string): void { } } - -export class Logger implements ILog { - - private readonly _messageHandler: (severity: Severity, source: string, message: string) => void; - - constructor( - messageHandler: (severity: Severity, source: string, message: string) => void - ) { - this._messageHandler = messageHandler; - } - - public error(source: string, message: string): void { - this._messageHandler(Severity.Error, source, message); - } - - public warn(source: string, message: string): void { - this._messageHandler(Severity.Warning, source, message); - } - - public info(source: string, message: string): void { - this._messageHandler(Severity.Info, source, message); - } -} diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts index 1707b523b..8e923aea1 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts @@ -5,13 +5,12 @@ import * as nls from 'vs/nls'; import { ChildProcess, fork } from 'child_process'; -import { ipcRenderer as ipc } from 'electron'; import { Server, Socket, createServer } from 'net'; import { getPathFromAmdModule } from 'vs/base/common/amd'; import { timeout } from 'vs/base/common/async'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import { Emitter, Event } from 'vs/base/common/event'; -import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; +import { toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import * as objects from 'vs/base/common/objects'; import * as platform from 'vs/base/common/platform'; import pkg from 'vs/platform/product/node/package'; @@ -36,16 +35,16 @@ import { withNullAsUndefined } from 'vs/base/common/types'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { parseExtensionDevOptions } from '../common/extensionDevOptions'; import { VSBuffer } from 'vs/base/common/buffer'; -import { IExtensionHostDebugService } from 'vs/workbench/services/extensions/common/extensionHostDebug'; +import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug'; import { IExtensionHostStarter } from 'vs/workbench/services/extensions/common/extensions'; import { isEqualOrParent } from 'vs/base/common/resources'; export class ExtensionHostProcessWorker implements IExtensionHostStarter { - private readonly _onCrashed: Emitter<[number, string]> = new Emitter<[number, string]>(); - public readonly onCrashed: Event<[number, string]> = this._onCrashed.event; + private readonly _onExit: Emitter<[number, string]> = new Emitter<[number, string]>(); + public readonly onExit: Event<[number, string]> = this._onExit.event; - private readonly _toDispose: IDisposable[]; + private readonly _toDispose = new DisposableStore(); private readonly _isExtensionDevHost: boolean; private readonly _isExtensionDevDebug: boolean; @@ -58,7 +57,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { // Resources, in order they get acquired/created when .start() is called: private _namedPipeServer: Server | null; - private _inspectPort: number; + private _inspectPort: number | null; private _extensionHostProcess: ChildProcess | null; private _extensionHostConnection: Socket | null; private _messageProtocol: Promise | null; @@ -92,16 +91,15 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { this._extensionHostConnection = null; this._messageProtocol = null; - this._toDispose = []; - this._toDispose.push(this._onCrashed); - this._toDispose.push(this._lifecycleService.onWillShutdown(e => this._onWillShutdown(e))); - this._toDispose.push(this._lifecycleService.onShutdown(reason => this.terminate())); - this._toDispose.push(this._extensionHostDebugService.onClose(event => { + this._toDispose.add(this._onExit); + this._toDispose.add(this._lifecycleService.onWillShutdown(e => this._onWillShutdown(e))); + this._toDispose.add(this._lifecycleService.onShutdown(reason => this.terminate())); + this._toDispose.add(this._extensionHostDebugService.onClose(event => { if (this._isExtensionDevHost && this._environmentService.debugExtensionHost.debugId === event.sessionId) { this._windowService.closeWindow(); } })); - this._toDispose.push(this._extensionHostDebugService.onReload(event => { + this._toDispose.add(this._extensionHostDebugService.onReload(event => { if (this._isExtensionDevHost && this._environmentService.debugExtensionHost.debugId === event.sessionId) { this._windowService.reloadWindow(); } @@ -109,7 +107,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { const globalExitListener = () => this.terminate(); process.once('exit', globalExitListener); - this._toDispose.push(toDisposable(() => { + this._toDispose.add(toDisposable(() => { process.removeListener('exit', globalExitListener); })); } @@ -125,7 +123,10 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { } if (!this._messageProtocol) { - this._messageProtocol = Promise.all([this._tryListenOnPipe(), this._tryFindDebugPort()]).then(data => { + this._messageProtocol = Promise.all([ + this._tryListenOnPipe(), + !this._environmentService.args['disable-inspect'] ? this._tryFindDebugPort() : Promise.resolve(null) + ]).then(data => { const pipeName = data[0]; const portData = data[1]; @@ -148,7 +149,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { silent: true }; - if (portData.actual) { + if (portData && portData.actual) { opts.execArgv = [ '--nolazy', (this._isExtensionDevDebugBrk ? '--inspect-brk=' : '--inspect=') + portData.actual @@ -191,7 +192,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { const inspectorUrlMatch = output.data && output.data.match(/ws:\/\/([^\s]+:(\d+)\/[^\s]+)/); if (inspectorUrlMatch) { if (!this._environmentService.isBuilt) { - console.log(`%c[Extension Host] %cdebugger inspector at chrome-devtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=${inspectorUrlMatch[1]}`, 'color: blue', 'color: black'); + console.log(`%c[Extension Host] %cdebugger inspector at chrome-devtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=${inspectorUrlMatch[1]}`, 'color: blue', 'color:'); } if (!this._inspectPort) { this._inspectPort = Number(inspectorUrlMatch[2]); @@ -215,10 +216,12 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { this._extensionHostProcess.on('exit', (code: number, signal: string) => this._onExtHostProcessExit(code, signal)); // Notify debugger that we are ready to attach to the process if we run a development extension - if (this._isExtensionDevHost && portData.actual && this._isExtensionDevDebug && this._environmentService.debugExtensionHost.debugId) { - this._extensionHostDebugService.attachSession(this._environmentService.debugExtensionHost.debugId, portData.actual); + if (portData) { + if (this._isExtensionDevHost && portData.actual && this._isExtensionDevDebug && this._environmentService.debugExtensionHost.debugId) { + this._extensionHostDebugService.attachSession(this._environmentService.debugExtensionHost.debugId, portData.actual); + } + this._inspectPort = portData.actual; } - this._inspectPort = portData.actual; // Help in case we fail to start it let startupTimeoutHandle: any; @@ -279,15 +282,15 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { return new Promise(resolve => { return findFreePort(startPort, 10 /* try 10 ports */, 5000 /* try up to 5 seconds */).then(port => { if (!port) { - console.warn('%c[Extension Host] %cCould not find a free port for debugging', 'color: blue', 'color: black'); + console.warn('%c[Extension Host] %cCould not find a free port for debugging', 'color: blue', 'color:'); } else { if (expected && port !== expected) { - console.warn(`%c[Extension Host] %cProvided debugging port ${expected} is not free, using ${port} instead.`, 'color: blue', 'color: black'); + console.warn(`%c[Extension Host] %cProvided debugging port ${expected} is not free, using ${port} instead.`, 'color: blue', 'color:'); } if (this._isExtensionDevDebugBrk) { - console.warn(`%c[Extension Host] %cSTOPPED on first line for debugging on port ${port}`, 'color: blue', 'color: black'); + console.warn(`%c[Extension Host] %cSTOPPED on first line for debugging on port ${port}`, 'color: blue', 'color:'); } else { - console.info(`%c[Extension Host] %cdebugger listening on port ${port}`, 'color: blue', 'color: black'); + console.info(`%c[Extension Host] %cdebugger listening on port ${port}`, 'color: blue', 'color:'); } } return resolve({ expected, actual: port }); @@ -389,14 +392,16 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { environment: { isExtensionDevelopmentDebug: this._isExtensionDevDebug, appRoot: this._environmentService.appRoot ? URI.file(this._environmentService.appRoot) : undefined, - appSettingsHome: this._environmentService.appSettingsHome ? URI.file(this._environmentService.appSettingsHome) : undefined, + appSettingsHome: this._environmentService.appSettingsHome ? this._environmentService.appSettingsHome : undefined, appName: product.nameLong, appUriScheme: product.urlProtocol, appLanguage: platform.language, extensionDevelopmentLocationURI: this._environmentService.extensionDevelopmentLocationURI, extensionTestsLocationURI: this._environmentService.extensionTestsLocationURI, globalStorageHome: URI.file(this._environmentService.globalStorageHome), - userHome: URI.file(this._environmentService.userHome) + userHome: URI.file(this._environmentService.userHome), + webviewResourceRoot: this._environmentService.webviewResourceRoot, + webviewCspSource: this._environmentService.webviewCspSource, }, workspace: this._contextService.getWorkbenchState() === WorkbenchState.EMPTY ? undefined : { configuration: withNullAsUndefined(workspace.configuration), @@ -404,6 +409,10 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { name: this._labelService.getWorkspaceLabel(workspace), isUntitled: workspace.configuration ? isEqualOrParent(workspace.configuration, this._environmentService.untitledWorkspacesHome) : false }, + remote: { + authority: this._environmentService.configuration.remoteAuthority, + isRemote: false + }, resolvedExtensions: [], hostExtensions: [], extensions: extensionDescriptions, @@ -425,7 +434,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { // Log on main side if running tests from cli if (this._isExtensionDevTestFromCli) { - this._windowsService.log(entry.severity, ...parse(entry).args); + this._windowsService.log(entry.severity, parse(entry).args); } // Broadcast to other windows if we are in development mode @@ -451,36 +460,11 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { return; } - // Unexpected termination - if (!this._isExtensionDevHost) { - this._onCrashed.fire([code, signal]); - } - - // Expected development extension termination: When the extension host goes down we also shutdown the window - else if (!this._isExtensionDevTestFromCli) { - this._windowService.closeWindow(); - } - - // When CLI testing make sure to exit with proper exit code - else { - ipc.send('vscode:exit', code); - } - } - - public enableInspector(): Promise { - if (this._inspectPort) { - return Promise.resolve(); - } - // send SIGUSR1 and wait a little the actual port is read from the process stdout which we - // scan here: https://github.com/Microsoft/vscode/blob/67ffab8dcd1a6752d8b62bcd13d7020101eef568/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts#L225-L240 - if (this._extensionHostProcess) { - this._extensionHostProcess.kill('SIGUSR1'); - } - return timeout(1000); + this._onExit.fire([code, signal]); } - public getInspectPort(): number { - return this._inspectPort; + public getInspectPort(): number | undefined { + return withNullAsUndefined(this._inspectPort); } public terminate(): void { @@ -489,7 +473,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { } this._terminating = true; - dispose(this._toDispose); + this._toDispose.dispose(); if (!this._messageProtocol) { // .start() was not called diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHostDebugService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHostDebugService.ts index aa4a35f54..e292a9ecd 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionHostDebugService.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionHostDebugService.ts @@ -3,128 +3,17 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Event, Emitter } from 'vs/base/common/event'; -import { IWindowService } from 'vs/platform/windows/common/windows'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IExtensionHostDebugService, IAttachSessionEvent, ITerminateSessionEvent, ILogToSessionEvent, IReloadSessionEvent, ICloseSessionEvent } from 'vs/workbench/services/extensions/common/extensionHostDebug'; -import { IRemoteConsoleLog } from 'vs/base/common/console'; -import { ipcRenderer as ipc } from 'electron'; +import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug'; +import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; +import { ExtensionHostDebugChannelClient, ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/extensionHostDebugIpc'; -interface IReloadBroadcast extends IReloadSessionEvent { - type: 'vscode:extensionReload'; -} - -interface IAttachSessionBroadcast extends IAttachSessionEvent { - type: 'vscode:extensionAttach'; -} - -interface ICloseBroadcast extends ICloseSessionEvent { - type: 'vscode:extensionCloseExtensionHost'; -} - -interface ILogToSessionBroadcast extends ILogToSessionEvent { - type: 'vscode:extensionLog'; -} - -interface ITerminateSessionBroadcast extends ITerminateSessionEvent { - type: 'vscode:extensionTerminate'; -} - -const CHANNEL = 'vscode:extensionHostDebug'; - -class ExtensionHostDebugService implements IExtensionHostDebugService { - _serviceBrand: any; - - private windowId: number; - private readonly _onReload = new Emitter(); - private readonly _onClose = new Emitter(); - private readonly _onAttachSession = new Emitter(); - private readonly _onLogToSession = new Emitter(); - private readonly _onTerminateSession = new Emitter(); +export class ExtensionHostDebugService extends ExtensionHostDebugChannelClient { constructor( - @IWindowService readonly windowService: IWindowService, + @IMainProcessService readonly windowService: IMainProcessService, ) { - this.windowId = windowService.windowId; - - ipc.on(CHANNEL, (_: unknown, broadcast: IReloadBroadcast | ICloseBroadcast | IAttachSessionBroadcast | ILogToSessionBroadcast | ITerminateSessionBroadcast) => { - switch (broadcast.type) { - case 'vscode:extensionReload': - this._onReload.fire(broadcast); - break; - case 'vscode:extensionCloseExtensionHost': - this._onClose.fire(broadcast); - break; - case 'vscode:extensionAttach': - this._onAttachSession.fire(broadcast); - break; - case 'vscode:extensionLog': - this._onLogToSession.fire(broadcast); - break; - case 'vscode:extensionTerminate': - this._onTerminateSession.fire(broadcast); - break; - } - }); - } - - reload(sessionId: string): void { - ipc.send(CHANNEL, this.windowId, { - type: 'vscode:extensionReload', - sessionId - }); - } - - get onReload(): Event { - return this._onReload.event; - } - - close(sessionId: string): void { - ipc.send(CHANNEL, this.windowId, { - type: 'vscode:extensionCloseExtensionHost', - sessionId - }); - } - - get onClose(): Event { - return this._onClose.event; - } - - attachSession(sessionId: string, port: number, subId?: string): void { - ipc.send(CHANNEL, this.windowId, { - type: 'vscode:extensionAttach', - sessionId, - port, - subId - }); - } - - get onAttachSession(): Event { - return this._onAttachSession.event; - } - - logToSession(sessionId: string, log: IRemoteConsoleLog): void { - ipc.send(CHANNEL, this.windowId, { - type: 'vscode:extensionLog', - sessionId, - log - }); - } - - get onLogToSession(): Event { - return this._onLogToSession.event; - } - - terminateSession(sessionId: string, subId?: string): void { - ipc.send(CHANNEL, this.windowId, { - type: 'vscode:extensionTerminate', - sessionId, - subId - }); - } - - get onTerminateSession(): Event { - return this._onTerminateSession.event; + super(windowService.getChannel(ExtensionHostDebugBroadcastChannel.ChannelName)); } } diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionManagementServerService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionManagementServerService.ts deleted file mode 100644 index 64343563a..000000000 --- a/src/vs/workbench/services/extensions/electron-browser/extensionManagementServerService.ts +++ /dev/null @@ -1,51 +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 { localize } from 'vs/nls'; -import { Schemas } from 'vs/base/common/network'; -import { URI } from 'vs/base/common/uri'; -import { IExtensionManagementServer, IExtensionManagementServerService } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { ExtensionManagementChannelClient } from 'vs/platform/extensionManagement/node/extensionManagementIpc'; -import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; -import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; -import { IChannel } from 'vs/base/parts/ipc/common/ipc'; -import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; - -const localExtensionManagementServerAuthority: string = 'vscode-local'; - -export class ExtensionManagementServerService implements IExtensionManagementServerService { - - _serviceBrand: any; - - readonly localExtensionManagementServer: IExtensionManagementServer; - readonly remoteExtensionManagementServer: IExtensionManagementServer | null = null; - - constructor( - @ISharedProcessService sharedProcessService: ISharedProcessService, - @IRemoteAgentService remoteAgentService: IRemoteAgentService - ) { - const localExtensionManagementService = new ExtensionManagementChannelClient(sharedProcessService.getChannel('extensions')); - - this.localExtensionManagementServer = { extensionManagementService: localExtensionManagementService, authority: localExtensionManagementServerAuthority, label: localize('local', "Local") }; - const remoteAgentConnection = remoteAgentService.getConnection(); - if (remoteAgentConnection) { - const extensionManagementService = new ExtensionManagementChannelClient(remoteAgentConnection.getChannel('extensions')); - this.remoteExtensionManagementServer = { authority: remoteAgentConnection.remoteAuthority, extensionManagementService, label: localize('remote', "Remote") }; - } - } - - getExtensionManagementServer(location: URI): IExtensionManagementServer | null { - if (location.scheme === Schemas.file) { - return this.localExtensionManagementServer; - } - if (location.scheme === REMOTE_HOST_SCHEME) { - return this.remoteExtensionManagementServer; - } - return null; - } -} - -registerSingleton(IExtensionManagementServerService, ExtensionManagementServerService); \ No newline at end of file diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts index 6692f75ea..6fb7d2d1b 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts @@ -3,55 +3,37 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { ipcRenderer as ipc } from 'electron'; +import { ExtensionHostProcessWorker } from 'vs/workbench/services/extensions/electron-browser/extensionHost'; +import { CachedExtensionScanner } from 'vs/workbench/services/extensions/electron-browser/cachedExtensionScanner'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { AbstractExtensionService } from 'vs/workbench/services/extensions/common/abstractExtensionService'; import * as nls from 'vs/nls'; import * as path from 'vs/base/common/path'; -import { ipcRenderer as ipc } from 'electron'; -import { isNonEmptyArray } from 'vs/base/common/arrays'; -import { Barrier, runWhenIdle } from 'vs/base/common/async'; -import { Emitter, Event } from 'vs/base/common/event'; -import { Disposable } from 'vs/base/common/lifecycle'; -import * as perf from 'vs/base/common/performance'; -import { isEqualOrParent } from 'vs/base/common/resources'; +import { runWhenIdle } from 'vs/base/common/async'; import { URI } from 'vs/base/common/uri'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { EnablementState, IExtensionEnablementService, IExtensionIdentifier, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { BetterMergeId, areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionEnablementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IInitDataProvider, RemoteExtensionHostClient } from 'vs/workbench/services/extensions/common/remoteExtensionHostClient'; +import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; +import { IRemoteAuthorityResolverService, RemoteAuthorityResolverError, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver'; +import { isUIExtension } from 'vs/workbench/services/extensions/common/extensionsUtil'; +import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; -import pkg from 'vs/platform/product/node/package'; -import product from 'vs/platform/product/node/product'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows'; -import { ActivationTimes, ExtensionPointContribution, IExtensionService, IExtensionsStatus, IMessage, IWillActivateEvent, IResponsiveStateChangeEvent, toExtension } from 'vs/workbench/services/extensions/common/extensions'; -import { ExtensionMessageCollector, ExtensionPoint, ExtensionsRegistry, IExtensionPoint, IExtensionPointUser, schema } from 'vs/workbench/services/extensions/common/extensionsRegistry'; -import { ExtensionHostProcessWorker } from 'vs/workbench/services/extensions/electron-browser/extensionHost'; -import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry'; -import { ResponsiveState } from 'vs/workbench/services/extensions/common/rpcProtocol'; -import { CachedExtensionScanner, Logger } from 'vs/workbench/services/extensions/electron-browser/cachedExtensionScanner'; +import { IExtensionService, toExtension } from 'vs/workbench/services/extensions/common/extensions'; import { ExtensionHostProcessManager } from 'vs/workbench/services/extensions/common/extensionHostProcessManager'; import { ExtensionIdentifier, IExtension, ExtensionType, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { Schemas } from 'vs/base/common/network'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IFileService } from 'vs/platform/files/common/files'; -import { parseExtensionDevOptions } from 'vs/workbench/services/extensions/common/extensionDevOptions'; - -const hasOwnProperty = Object.hasOwnProperty; -const NO_OP_VOID_PROMISE = Promise.resolve(undefined); - -schema.properties.engines.properties.vscode.default = `^${pkg.version}`; - -let productAllowProposedApi: Set | null = null; -function allowProposedApiFromProduct(id: ExtensionIdentifier): boolean { - // create set if needed - if (!productAllowProposedApi) { - productAllowProposedApi = new Set(); - if (isNonEmptyArray(product.extensionAllowedProposedApi)) { - product.extensionAllowedProposedApi.forEach((id) => productAllowProposedApi!.add(ExtensionIdentifier.toKey(id))); - } - } - return productAllowProposedApi.has(ExtensionIdentifier.toKey(id)); -} +import { PersistentConnectionEventType } from 'vs/platform/remote/common/remoteAgentConnection'; +import { IProductService } from 'vs/platform/product/common/product'; +import { Logger } from 'vs/workbench/services/extensions/common/extensionPoints'; class DeltaExtensionsQueueItem { constructor( @@ -60,73 +42,38 @@ class DeltaExtensionsQueueItem { ) { } } -export class ExtensionService extends Disposable implements IExtensionService { +export class ExtensionService extends AbstractExtensionService implements IExtensionService { - public _serviceBrand: any; + private readonly _remoteExtensionsEnvironmentData: Map; private readonly _extensionHostLogsLocation: URI; - private readonly _registry: ExtensionDescriptionRegistry; - private readonly _installedExtensionsReady: Barrier; - private readonly _isDev: boolean; - private readonly _extensionsMessages: Map; - private _allRequestedActivateEvents: { [activationEvent: string]: boolean; }; private readonly _extensionScanner: CachedExtensionScanner; private _deltaExtensionsQueue: DeltaExtensionsQueueItem[]; - private readonly _onDidRegisterExtensions: Emitter = this._register(new Emitter()); - public readonly onDidRegisterExtensions = this._onDidRegisterExtensions.event; - - private readonly _onDidChangeExtensionsStatus: Emitter = this._register(new Emitter()); - public readonly onDidChangeExtensionsStatus: Event = this._onDidChangeExtensionsStatus.event; - - private readonly _onDidChangeExtensions: Emitter = this._register(new Emitter()); - public readonly onDidChangeExtensions: Event = this._onDidChangeExtensions.event; - - private readonly _onWillActivateByEvent = this._register(new Emitter()); - public readonly onWillActivateByEvent: Event = this._onWillActivateByEvent.event; - - private readonly _onDidChangeResponsiveChange = this._register(new Emitter()); - public readonly onDidChangeResponsiveChange: Event = this._onDidChangeResponsiveChange.event; - - // --- Members used per extension host process - private _extensionHostProcessManagers: ExtensionHostProcessManager[]; - private _extensionHostActiveExtensions: Map; - private _extensionHostProcessActivationTimes: Map; - private _extensionHostExtensionRuntimeErrors: Map; - constructor( - @IInstantiationService private readonly _instantiationService: IInstantiationService, - @INotificationService private readonly _notificationService: INotificationService, - @IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService, - @ITelemetryService private readonly _telemetryService: ITelemetryService, - @IExtensionEnablementService private readonly _extensionEnablementService: IExtensionEnablementService, + @IInstantiationService instantiationService: IInstantiationService, + @INotificationService notificationService: INotificationService, + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, + @ITelemetryService telemetryService: ITelemetryService, + @IExtensionEnablementService extensionEnablementService: IExtensionEnablementService, + @IFileService fileService: IFileService, + @IProductService productService: IProductService, @IExtensionManagementService private readonly _extensionManagementService: IExtensionManagementService, - @IWindowService private readonly _windowService: IWindowService, + @IRemoteAgentService private readonly _remoteAgentService: IRemoteAgentService, + @IRemoteAuthorityResolverService private readonly _remoteAuthorityResolverService: IRemoteAuthorityResolverService, + @IConfigurationService private readonly _configurationService: IConfigurationService, @ILifecycleService private readonly _lifecycleService: ILifecycleService, - @IFileService fileService: IFileService + @IWindowService protected readonly _windowService: IWindowService, ) { - super(); - - // help the file service to activate providers by activating extensions by file system event - this._register(fileService.onWillActivateFileSystemProvider(e => { - e.join(this.activateByEvent(`onFileSystem:${e.scheme}`)); - })); - - this._extensionHostLogsLocation = URI.file(path.join(this._environmentService.logsPath, `exthost${this._windowService.windowId}`)); - this._registry = new ExtensionDescriptionRegistry([]); - this._installedExtensionsReady = new Barrier(); - this._isDev = !this._environmentService.isBuilt || this._environmentService.isExtensionDevelopment; - this._extensionsMessages = new Map(); - this._allRequestedActivateEvents = Object.create(null); - this._extensionScanner = this._instantiationService.createInstance(CachedExtensionScanner); - this._deltaExtensionsQueue = []; - - this._extensionHostProcessManagers = []; - this._extensionHostActiveExtensions = new Map(); - this._extensionHostProcessActivationTimes = new Map(); - this._extensionHostExtensionRuntimeErrors = new Map(); - - this._startDelayed(this._lifecycleService); + super( + instantiationService, + notificationService, + environmentService, + telemetryService, + extensionEnablementService, + fileService, + productService, + ); if (this._extensionEnablementService.allUserExtensionsDisabled) { this._notificationService.prompt(Severity.Info, nls.localize('extensionsDisabled', "All installed extensions are temporarily disabled. Reload the window to return to the previous state."), [{ @@ -137,6 +84,12 @@ export class ExtensionService extends Disposable implements IExtensionService { }]); } + this._remoteExtensionsEnvironmentData = new Map(); + + this._extensionHostLogsLocation = URI.file(path.join(this._environmentService.logsPath, `exthost${this._windowService.windowId}`)); + this._extensionScanner = instantiationService.createInstance(CachedExtensionScanner); + this._deltaExtensionsQueue = []; + this._register(this._extensionEnablementService.onEnablementChanged((extensions) => { let toAdd: IExtension[] = []; let toRemove: string[] = []; @@ -167,8 +120,24 @@ export class ExtensionService extends Disposable implements IExtensionService { this._handleDeltaExtensions(new DeltaExtensionsQueueItem([], [event.identifier.id])); } })); + + // delay extension host creation and extension scanning + // until the workbench is running. we cannot defer the + // extension host more (LifecyclePhase.Restored) because + // some editors require the extension host to restore + // and this would result in a deadlock + // see https://github.com/Microsoft/vscode/issues/41322 + this._lifecycleService.when(LifecyclePhase.Ready).then(() => { + // reschedule to ensure this runs after restoring viewlets, panels, and editors + runWhenIdle(() => { + this._initialize(); + }, 50 /*max delay*/); + }); } + + //#region deltaExtensions + private _inHandleDeltaExtensions = false; private async _handleDeltaExtensions(item: DeltaExtensionsQueueItem): Promise { this._deltaExtensionsQueue.push(item); @@ -197,13 +166,7 @@ export class ExtensionService extends Disposable implements IExtensionService { for (let i = 0, len = _toAdd.length; i < len; i++) { const extension = _toAdd[i]; - if (extension.location.scheme !== Schemas.file) { - continue; - } - - const existingExtensionDescription = this._registry.getExtensionDescription(extension.identifier.id); - if (existingExtensionDescription) { - // this extension is already running (most likely at a different version) + if (!this._canAddExtension(extension)) { continue; } @@ -239,11 +202,16 @@ export class ExtensionService extends Disposable implements IExtensionService { // Update the local registry const result = this._registry.deltaExtensions(toAdd, toRemove.map(e => e.identifier)); + this._onDidChangeExtensions.fire(undefined); + toRemove = toRemove.concat(result.removedDueToLooping); if (result.removedDueToLooping.length > 0) { this._logOrShowMessage(Severity.Error, nls.localize('looping', "The following extensions contain dependency loops and have been disabled: {0}", result.removedDueToLooping.map(e => `'${e.identifier.value}'`).join(', '))); } + // enable or disable proposed API per extension + this._checkEnableProposedApi(toAdd); + // Update extension points this._rehandleExtensionPoints(([]).concat(toAdd).concat(toRemove)); @@ -252,51 +220,37 @@ export class ExtensionService extends Disposable implements IExtensionService { await this._extensionHostProcessManagers[0].deltaExtensions(toAdd, toRemove.map(e => e.identifier)); } - this._onDidChangeExtensions.fire(undefined); - for (let i = 0; i < toAdd.length; i++) { this._activateAddedExtensionIfNeeded(toAdd[i]); } } private _rehandleExtensionPoints(extensionDescriptions: IExtensionDescription[]): void { - const affectedExtensionPoints: { [extPointName: string]: boolean; } = Object.create(null); - for (let extensionDescription of extensionDescriptions) { - if (extensionDescription.contributes) { - for (let extPointName in extensionDescription.contributes) { - if (hasOwnProperty.call(extensionDescription.contributes, extPointName)) { - affectedExtensionPoints[extPointName] = true; - } - } - } - } - - const messageHandler = (msg: IMessage) => this._handleExtensionPointMessage(msg); + this._doHandleExtensionPoints(extensionDescriptions); + } - const availableExtensions = this._registry.getAllExtensionDescriptions(); - const extensionPoints = ExtensionsRegistry.getExtensionPoints(); - for (let i = 0, len = extensionPoints.length; i < len; i++) { - if (affectedExtensionPoints[extensionPoints[i].name]) { - ExtensionService._handleExtensionPoint(extensionPoints[i], availableExtensions, messageHandler); - } - } + public canAddExtension(extensionDescription: IExtensionDescription): boolean { + return this._canAddExtension(toExtension(extensionDescription)); } - public canAddExtension(extension: IExtensionDescription): boolean { + public _canAddExtension(extension: IExtension): boolean { if (this._environmentService.configuration.remoteAuthority) { return false; } - if (extension.extensionLocation.scheme !== Schemas.file) { + if (extension.location.scheme !== Schemas.file) { return false; } - const extensionDescription = this._registry.getExtensionDescription(extension.identifier); + const extensionDescription = this._registry.getExtensionDescription(extension.identifier.id); if (extensionDescription) { - // ignore adding an extension which is already running and cannot be removed - if (!this._canRemoveExtension(extensionDescription)) { - return false; - } + // this extension is already running (most likely at a different version) + return false; + } + + // Check if extension is renamed + if (extension.identifier.uuid && this._registry.getAllExtensionDescriptions().some(e => e.uuid === extension.identifier.uuid)) { + return false; } return true; @@ -340,7 +294,7 @@ export class ExtensionService extends Disposable implements IExtensionService { activationEvent = `onUri:${ExtensionIdentifier.toKey(extensionDescription.identifier)}`; } - if (this._allRequestedActivateEvents[activationEvent]) { + if (this._allRequestedActivateEvents.has(activationEvent)) { // This activation event was fired before the extension was added shouldActivate = true; shouldActivateReason = activationEvent; @@ -369,215 +323,80 @@ export class ExtensionService extends Disposable implements IExtensionService { } } - private _startDelayed(lifecycleService: ILifecycleService): void { - // delay extension host creation and extension scanning - // until the workbench is running. we cannot defer the - // extension host more (LifecyclePhase.Restored) because - // some editors require the extension host to restore - // and this would result in a deadlock - // see https://github.com/Microsoft/vscode/issues/41322 - lifecycleService.when(LifecyclePhase.Ready).then(() => { - // reschedule to ensure this runs after restoring viewlets, panels, and editors - runWhenIdle(() => { - perf.mark('willLoadExtensions'); - this._startExtensionHostProcess(true, []); - this._scanAndHandleExtensions(); - this.whenInstalledExtensionsRegistered().then(() => perf.mark('didLoadExtensions')); - }, 50 /*max delay*/); - }); - } - - public dispose(): void { - super.dispose(); - this._onWillActivateByEvent.dispose(); - this._onDidChangeResponsiveChange.dispose(); - } + //#endregion - public restartExtensionHost(): void { - this._stopExtensionHostProcess(); - this._startExtensionHostProcess(false, Object.keys(this._allRequestedActivateEvents)); - } - - public startExtensionHost(): void { - this._startExtensionHostProcess(false, Object.keys(this._allRequestedActivateEvents)); - } - - public stopExtensionHost(): void { - this._stopExtensionHostProcess(); - } - - private _stopExtensionHostProcess(): void { - let previouslyActivatedExtensionIds: ExtensionIdentifier[] = []; - this._extensionHostActiveExtensions.forEach((value) => { - previouslyActivatedExtensionIds.push(value); - }); - - for (const manager of this._extensionHostProcessManagers) { - manager.dispose(); - } - this._extensionHostProcessManagers = []; - this._extensionHostActiveExtensions = new Map(); - this._extensionHostProcessActivationTimes = new Map(); - this._extensionHostExtensionRuntimeErrors = new Map(); - - if (previouslyActivatedExtensionIds.length > 0) { - this._onDidChangeExtensionsStatus.fire(previouslyActivatedExtensionIds); - } + private _createProvider(remoteAuthority: string): IInitDataProvider { + return { + remoteAuthority: remoteAuthority, + getInitData: () => { + return this.whenInstalledExtensionsRegistered().then(() => { + return this._remoteExtensionsEnvironmentData.get(remoteAuthority)!; + }); + } + }; } - private _startExtensionHostProcess(isInitialStart: boolean, initialActivationEvents: string[]): void { - this._stopExtensionHostProcess(); - + protected _createExtensionHosts(isInitialStart: boolean, initialActivationEvents: string[]): ExtensionHostProcessManager[] { let autoStart: boolean; let extensions: Promise; if (isInitialStart) { autoStart = false; - extensions = this._extensionScanner.scannedExtensions; + extensions = this._extensionScanner.scannedExtensions.then(extensions => extensions.filter(extension => this._isEnabled(extension))); // remove disabled extensions } else { // restart case autoStart = true; - extensions = this.getExtensions(); + extensions = this.getExtensions().then((extensions) => extensions.filter(ext => ext.extensionLocation.scheme === Schemas.file)); } + const result: ExtensionHostProcessManager[] = []; const extHostProcessWorker = this._instantiationService.createInstance(ExtensionHostProcessWorker, autoStart, extensions, this._extensionHostLogsLocation); - const extHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, extHostProcessWorker, null, initialActivationEvents); - extHostProcessManager.onDidCrash(([code, signal]) => this._onExtensionHostCrashed(code, signal)); - extHostProcessManager.onDidChangeResponsiveState((responsiveState) => { this._onDidChangeResponsiveChange.fire({ isResponsive: responsiveState === ResponsiveState.Responsive }); }); - this._extensionHostProcessManagers.push(extHostProcessManager); - } + const extHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, true, extHostProcessWorker, null, initialActivationEvents); + result.push(extHostProcessManager); - private _onExtensionHostCrashed(code: number, signal: string | null): void { - console.error('Extension host terminated unexpectedly. Code: ', code, ' Signal: ', signal); - this._stopExtensionHostProcess(); - - if (code === 55) { - this._notificationService.prompt( - Severity.Error, - nls.localize('extensionService.versionMismatchCrash', "Extension host cannot start: version mismatch."), - [{ - label: nls.localize('relaunch', "Relaunch VS Code"), - run: () => { - this._instantiationService.invokeFunction((accessor) => { - const windowsService = accessor.get(IWindowsService); - windowsService.relaunch({}); - }); - } - }] - ); - return; + const remoteAgentConnection = this._remoteAgentService.getConnection(); + if (remoteAgentConnection) { + const remoteExtHostProcessWorker = this._instantiationService.createInstance(RemoteExtensionHostClient, this.getExtensions(), this._createProvider(remoteAgentConnection.remoteAuthority), this._remoteAgentService.socketFactory); + const remoteExtHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, false, remoteExtHostProcessWorker, remoteAgentConnection.remoteAuthority, initialActivationEvents); + result.push(remoteExtHostProcessManager); } - let message = nls.localize('extensionService.crash', "Extension host terminated unexpectedly."); - if (code === 87) { - message = nls.localize('extensionService.unresponsiveCrash', "Extension host terminated because it was not responsive."); - } - - this._notificationService.prompt(Severity.Error, message, - [{ - label: nls.localize('devTools', "Open Developer Tools"), - run: () => this._windowService.openDevTools() - }, - { - label: nls.localize('restart', "Restart Extension Host"), - run: () => this._startExtensionHostProcess(false, Object.keys(this._allRequestedActivateEvents)) - }] - ); - } - - // ---- begin IExtensionService - - public activateByEvent(activationEvent: string): Promise { - if (this._installedExtensionsReady.isOpen()) { - // Extensions have been scanned and interpreted - - // Record the fact that this activationEvent was requested (in case of a restart) - this._allRequestedActivateEvents[activationEvent] = true; - - if (!this._registry.containsActivationEvent(activationEvent)) { - // There is no extension that is interested in this activation event - return NO_OP_VOID_PROMISE; - } - - return this._activateByEvent(activationEvent); - } else { - // Extensions have not been scanned yet. - - // Record the fact that this activationEvent was requested (in case of a restart) - this._allRequestedActivateEvents[activationEvent] = true; - - return this._installedExtensionsReady.wait().then(() => this._activateByEvent(activationEvent)); - } - } - - private _activateByEvent(activationEvent: string): Promise { - const result = Promise.all( - this._extensionHostProcessManagers.map(extHostManager => extHostManager.activateByEvent(activationEvent)) - ).then(() => { }); - this._onWillActivateByEvent.fire({ - event: activationEvent, - activation: result - }); return result; } - public whenInstalledExtensionsRegistered(): Promise { - return this._installedExtensionsReady.wait(); - } - - public getExtensions(): Promise { - return this._installedExtensionsReady.wait().then(() => { - return this._registry.getAllExtensionDescriptions(); - }); - } - - public getExtension(id: string): Promise { - return this._installedExtensionsReady.wait().then(() => { - return this._registry.getExtensionDescription(id); - }); - } - - public readExtensionPointContributions(extPoint: IExtensionPoint): Promise[]> { - return this._installedExtensionsReady.wait().then(() => { - let availableExtensions = this._registry.getAllExtensionDescriptions(); - - let result: ExtensionPointContribution[] = [], resultLen = 0; - for (let i = 0, len = availableExtensions.length; i < len; i++) { - let desc = availableExtensions[i]; - - if (desc.contributes && hasOwnProperty.call(desc.contributes, extPoint.name)) { - result[resultLen++] = new ExtensionPointContribution(desc, desc.contributes[extPoint.name]); - } - } - - return result; - }); - } - - public getExtensionsStatus(): { [id: string]: IExtensionsStatus; } { - let result: { [id: string]: IExtensionsStatus; } = Object.create(null); - if (this._registry) { - const extensions = this._registry.getAllExtensionDescriptions(); - for (const extension of extensions) { - const extensionKey = ExtensionIdentifier.toKey(extension.identifier); - result[extension.identifier.value] = { - messages: this._extensionsMessages.get(extensionKey) || [], - activationTimes: this._extensionHostProcessActivationTimes.get(extensionKey), - runtimeErrors: this._extensionHostExtensionRuntimeErrors.get(extensionKey) || [], - }; + protected _onExtensionHostCrashed(extensionHost: ExtensionHostProcessManager, code: number, signal: string | null): void { + super._onExtensionHostCrashed(extensionHost, code, signal); + + if (extensionHost.isLocal) { + if (code === 55) { + this._notificationService.prompt( + Severity.Error, + nls.localize('extensionService.versionMismatchCrash', "Extension host cannot start: version mismatch."), + [{ + label: nls.localize('relaunch', "Relaunch VS Code"), + run: () => { + this._instantiationService.invokeFunction((accessor) => { + const windowsService = accessor.get(IWindowsService); + windowsService.relaunch({}); + }); + } + }] + ); + return; } - } - return result; - } - public getInspectPort(): number { - if (this._extensionHostProcessManagers.length > 0) { - return this._extensionHostProcessManagers[0].getInspectPort(); + this._notificationService.prompt(Severity.Error, nls.localize('extensionService.crash', "Extension host terminated unexpectedly."), + [{ + label: nls.localize('devTools', "Open Developer Tools"), + run: () => this._windowService.openDevTools() + }, + { + label: nls.localize('restart', "Restart Extension Host"), + run: () => this.startExtensionHost() + }] + ); } - return 0; } - // ---- end IExtensionService - // --- impl private createLogger(): Logger { @@ -590,252 +409,131 @@ export class ExtensionService extends Disposable implements IExtensionService { }); } - private async _scanAndHandleExtensions(): Promise { - this._extensionScanner.startScanningExtensions(this.createLogger()); - - const extensionHost = this._extensionHostProcessManagers[0]; - const extensions = await this._extensionScanner.scannedExtensions; - const enabledExtensions = await this._getRuntimeExtensions(extensions); - - this._handleExtensionPoints(enabledExtensions); - extensionHost.start(enabledExtensions.map(extension => extension.identifier).filter(id => this._registry.containsExtension(id))); - this._releaseBarrier(); - } - - private _handleExtensionPoints(allExtensions: IExtensionDescription[]): void { - const result = this._registry.deltaExtensions(allExtensions, []); - if (result.removedDueToLooping.length > 0) { - this._logOrShowMessage(Severity.Error, nls.localize('looping', "The following extensions contain dependency loops and have been disabled: {0}", result.removedDueToLooping.map(e => `'${e.identifier.value}'`).join(', '))); + private async _resolveAuthorityAgain(): Promise { + const remoteAuthority = this._environmentService.configuration.remoteAuthority; + if (!remoteAuthority) { + return; } - let availableExtensions = this._registry.getAllExtensionDescriptions(); - let extensionPoints = ExtensionsRegistry.getExtensionPoints(); - - let messageHandler = (msg: IMessage) => this._handleExtensionPointMessage(msg); - - for (let i = 0, len = extensionPoints.length; i < len; i++) { - ExtensionService._handleExtensionPoint(extensionPoints[i], availableExtensions, messageHandler); + const extensionHost = this._extensionHostProcessManagers[0]; + this._remoteAuthorityResolverService.clearResolvedAuthority(remoteAuthority); + try { + const result = await extensionHost.resolveAuthority(remoteAuthority); + this._remoteAuthorityResolverService.setResolvedAuthority(result.authority, result.options); + } catch (err) { + this._remoteAuthorityResolverService.setResolvedAuthorityError(remoteAuthority, err); } } - private _releaseBarrier(): void { - perf.mark('extensionHostReady'); - this._installedExtensionsReady.open(); - this._onDidRegisterExtensions.fire(undefined); - this._onDidChangeExtensionsStatus.fire(this._registry.getAllExtensionDescriptions().map(e => e.identifier)); - } + protected async _scanAndHandleExtensions(): Promise { + this._extensionScanner.startScanningExtensions(this.createLogger()); - private isExtensionUnderDevelopment(extension: IExtensionDescription): boolean { - if (this._environmentService.isExtensionDevelopment) { - const extDevLocs = this._environmentService.extensionDevelopmentLocationURI; - if (extDevLocs) { - const extLocation = extension.extensionLocation; - for (let p of extDevLocs) { - if (isEqualOrParent(extLocation, p)) { - return true; - } - } - } - } - return false; - } + const remoteAuthority = this._environmentService.configuration.remoteAuthority; + const extensionHost = this._extensionHostProcessManagers[0]; - private async _getRuntimeExtensions(allExtensions: IExtensionDescription[]): Promise { + let localExtensions = await this._extensionScanner.scannedExtensions; - const runtimeExtensions: IExtensionDescription[] = []; - const extensionsToDisable: IExtensionDescription[] = []; - const userMigratedSystemExtensions: IExtensionIdentifier[] = [{ id: BetterMergeId }]; + // enable or disable proposed API per extension + this._checkEnableProposedApi(localExtensions); - let enableProposedApiFor: string | string[] = this._environmentService.args['enable-proposed-api'] || []; + // remove disabled extensions + localExtensions = localExtensions.filter(extension => this._isEnabled(extension)); - const notFound = (id: string) => nls.localize('notFound', "Extension \`{0}\` cannot use PROPOSED API as it cannot be found", id); + if (remoteAuthority) { + let resolvedAuthority: ResolverResult; - if (enableProposedApiFor.length) { - let allProposed = (enableProposedApiFor instanceof Array ? enableProposedApiFor : [enableProposedApiFor]); - allProposed.forEach(id => { - if (!allExtensions.some(description => ExtensionIdentifier.equals(description.identifier, id))) { - console.error(notFound(id)); + try { + resolvedAuthority = await extensionHost.resolveAuthority(remoteAuthority); + } catch (err) { + console.error(err); + const plusIndex = remoteAuthority.indexOf('+'); + const authorityFriendlyName = plusIndex > 0 ? remoteAuthority.substr(0, plusIndex) : remoteAuthority; + if (!RemoteAuthorityResolverError.isHandledNotAvailable(err)) { + this._notificationService.notify({ severity: Severity.Error, message: nls.localize('resolveAuthorityFailure', "Resolving the authority `{0}` failed", authorityFriendlyName) }); + } else { + console.log(`Not showing a notification for the error`); } - }); - // Make enabled proposed API be lowercase for case insensitive comparison - if (Array.isArray(enableProposedApiFor)) { - enableProposedApiFor = enableProposedApiFor.map(id => id.toLowerCase()); - } else { - enableProposedApiFor = enableProposedApiFor.toLowerCase(); - } - } - const enableProposedApiForAll = !this._environmentService.isBuilt || - (!!this._environmentService.extensionDevelopmentLocationURI && product.nameLong !== 'Visual Studio Code') || - (enableProposedApiFor.length === 0 && 'enable-proposed-api' in this._environmentService.args); + this._remoteAuthorityResolverService.setResolvedAuthorityError(remoteAuthority, err); - - for (const extension of allExtensions) { - - // Do not disable extensions under development - if (!this.isExtensionUnderDevelopment(extension)) { - if (!this._extensionEnablementService.isEnabled(toExtension(extension))) { - continue; - } + // Proceed with the local extension host + await this._startLocalExtensionHost(extensionHost, localExtensions); + return; } - if (!extension.isBuiltin) { - // Check if the extension is changed to system extension - const userMigratedSystemExtension = userMigratedSystemExtensions.filter(userMigratedSystemExtension => areSameExtensions(userMigratedSystemExtension, { id: extension.identifier.value }))[0]; - if (userMigratedSystemExtension) { - extensionsToDisable.push(extension); - continue; - } - } - runtimeExtensions.push(this._updateEnableProposedApi(extension, enableProposedApiForAll, enableProposedApiFor)); - } + // set the resolved authority + this._remoteAuthorityResolverService.setResolvedAuthority(resolvedAuthority.authority, resolvedAuthority.options); - this._telemetryService.publicLog('extensionsScanned', { - totalCount: runtimeExtensions.length, - disabledCount: allExtensions.length - runtimeExtensions.length - }); - - if (extensionsToDisable.length) { - return this._extensionEnablementService.setEnablement(extensionsToDisable.map(e => toExtension(e)), EnablementState.Disabled) - .then(() => runtimeExtensions); - } else { - return runtimeExtensions; - } - } - - private _updateEnableProposedApi(extension: IExtensionDescription, enableProposedApiForAll: boolean, enableProposedApiFor: string | string[]): IExtensionDescription { - if (allowProposedApiFromProduct(extension.identifier)) { - // fast lane -> proposed api is available to all extensions - // that are listed in product.json-files - extension.enableProposedApi = true; - - } else if (extension.enableProposedApi && !extension.isBuiltin) { - if ( - !enableProposedApiForAll && - enableProposedApiFor.indexOf(extension.identifier.value.toLowerCase()) < 0 - ) { - extension.enableProposedApi = false; - console.error(`Extension '${extension.identifier.value} cannot use PROPOSED API (must started out of dev or enabled via --enable-proposed-api)`); - - } else { - // proposed api is available when developing or when an extension was explicitly - // spelled out via a command line argument - console.warn(`Extension '${extension.identifier.value}' uses PROPOSED API which is subject to change and removal without notice.`); + // monitor for breakage + const connection = this._remoteAgentService.getConnection(); + if (connection) { + connection.onDidStateChange(async (e) => { + const remoteAuthority = this._environmentService.configuration.remoteAuthority; + if (!remoteAuthority) { + return; + } + if (e.type === PersistentConnectionEventType.ConnectionLost) { + this._remoteAuthorityResolverService.clearResolvedAuthority(remoteAuthority); + } + }); + connection.onReconnecting(() => this._resolveAuthorityAgain()); } - } - return extension; - } - - private _handleExtensionPointMessage(msg: IMessage) { - const extensionKey = ExtensionIdentifier.toKey(msg.extensionId); - if (!this._extensionsMessages.has(extensionKey)) { - this._extensionsMessages.set(extensionKey, []); - } - this._extensionsMessages.get(extensionKey)!.push(msg); + // fetch the remote environment + const remoteEnv = (await this._remoteAgentService.getEnvironment())!; - const extension = this._registry.getExtensionDescription(msg.extensionId); - const strMsg = `[${msg.extensionId.value}]: ${msg.message}`; - if (extension && extension.isUnderDevelopment) { - // This message is about the extension currently being developed - this._showMessageToUser(msg.type, strMsg); - } else { - this._logMessageInConsole(msg.type, strMsg); - } + // enable or disable proposed API per extension + this._checkEnableProposedApi(remoteEnv.extensions); - if (!this._isDev && msg.extensionId) { - const { type, extensionId, extensionPointId, message } = msg; - /* __GDPR__ - "extensionsMessage" : { - "type" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "extensionId": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, - "extensionPointId": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, - "message": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } - } - */ - this._telemetryService.publicLog('extensionsMessage', { - type, extensionId: extensionId.value, extensionPointId, message - }); - } - } + // remove disabled extensions + remoteEnv.extensions = remoteEnv.extensions.filter(extension => this._isEnabled(extension)); - private static _handleExtensionPoint(extensionPoint: ExtensionPoint, availableExtensions: IExtensionDescription[], messageHandler: (msg: IMessage) => void): void { - let users: IExtensionPointUser[] = [], usersLen = 0; - for (let i = 0, len = availableExtensions.length; i < len; i++) { - let desc = availableExtensions[i]; - - if (desc.contributes && hasOwnProperty.call(desc.contributes, extensionPoint.name)) { - users[usersLen++] = { - description: desc, - value: desc.contributes[extensionPoint.name], - collector: new ExtensionMessageCollector(messageHandler, desc, extensionPoint.name) - }; - } - } + // remove UI extensions from the remote extensions + remoteEnv.extensions = remoteEnv.extensions.filter(extension => !isUIExtension(extension, this._productService, this._configurationService)); - extensionPoint.acceptUsers(users); - } + // remove non-UI extensions from the local extensions + localExtensions = localExtensions.filter(extension => extension.isBuiltin || isUIExtension(extension, this._productService, this._configurationService)); - private _showMessageToUser(severity: Severity, msg: string): void { - if (severity === Severity.Error || severity === Severity.Warning) { - this._notificationService.notify({ severity, message: msg }); - } else { - this._logMessageInConsole(severity, msg); - } - } + // in case of overlap, the remote wins + const isRemoteExtension = new Set(); + remoteEnv.extensions.forEach(extension => isRemoteExtension.add(ExtensionIdentifier.toKey(extension.identifier))); + localExtensions = localExtensions.filter(extension => !isRemoteExtension.has(ExtensionIdentifier.toKey(extension.identifier))); - private _logMessageInConsole(severity: Severity, msg: string): void { - if (severity === Severity.Error) { - console.error(msg); - } else if (severity === Severity.Warning) { - console.warn(msg); - } else { - console.log(msg); - } - } + // save for remote extension's init data + this._remoteExtensionsEnvironmentData.set(remoteAuthority, remoteEnv); - // -- called by extension host + this._handleExtensionPoints(([]).concat(remoteEnv.extensions).concat(localExtensions)); + extensionHost.start(localExtensions.map(extension => extension.identifier)); - public _logOrShowMessage(severity: Severity, msg: string): void { - if (this._isDev) { - this._showMessageToUser(severity, msg); } else { - this._logMessageInConsole(severity, msg); + await this._startLocalExtensionHost(extensionHost, localExtensions); } } - public async _activateById(extensionId: ExtensionIdentifier, activationEvent: string): Promise { - const results = await Promise.all( - this._extensionHostProcessManagers.map(manager => manager.activate(extensionId, activationEvent)) - ); - const activated = results.some(e => e); - if (!activated) { - throw new Error(`Unknown extension ${extensionId.value}`); - } + private async _startLocalExtensionHost(extensionHost: ExtensionHostProcessManager, localExtensions: IExtensionDescription[]): Promise { + this._handleExtensionPoints(localExtensions); + extensionHost.start(localExtensions.map(extension => extension.identifier).filter(id => this._registry.containsExtension(id))); } - public _onWillActivateExtension(extensionId: ExtensionIdentifier): void { - this._extensionHostActiveExtensions.set(ExtensionIdentifier.toKey(extensionId), extensionId); - } + private _handleExtensionPoints(allExtensions: IExtensionDescription[]): void { + const result = this._registry.deltaExtensions(allExtensions, []); + if (result.removedDueToLooping.length > 0) { + this._logOrShowMessage(Severity.Error, nls.localize('looping', "The following extensions contain dependency loops and have been disabled: {0}", result.removedDueToLooping.map(e => `'${e.identifier.value}'`).join(', '))); + } - public _onDidActivateExtension(extensionId: ExtensionIdentifier, startup: boolean, codeLoadingTime: number, activateCallTime: number, activateResolvedTime: number, activationEvent: string): void { - this._extensionHostProcessActivationTimes.set(ExtensionIdentifier.toKey(extensionId), new ActivationTimes(startup, codeLoadingTime, activateCallTime, activateResolvedTime, activationEvent)); - this._onDidChangeExtensionsStatus.fire([extensionId]); + this._doHandleExtensionPoints(this._registry.getAllExtensionDescriptions()); } - public _onExtensionRuntimeError(extensionId: ExtensionIdentifier, err: Error): void { - const extensionKey = ExtensionIdentifier.toKey(extensionId); - if (!this._extensionHostExtensionRuntimeErrors.has(extensionKey)) { - this._extensionHostExtensionRuntimeErrors.set(extensionKey, []); + public getInspectPort(): number { + if (this._extensionHostProcessManagers.length > 0) { + return this._extensionHostProcessManagers[0].getInspectPort(); } - this._extensionHostExtensionRuntimeErrors.get(extensionKey)!.push(err); - this._onDidChangeExtensionsStatus.fire([extensionId]); + return 0; } public _onExtensionHostExit(code: number): void { // Expected development extension termination: When the extension host goes down we also shutdown the window - const devOpts = parseExtensionDevOptions(this._environmentService); - if (!devOpts.isExtensionDevTestFromCli) { + if (!this._isExtensionDevTestFromCli) { this._windowService.closeWindow(); } diff --git a/src/vs/workbench/services/extensions/electron-browser/remoteExtensionManagementIpc.ts b/src/vs/workbench/services/extensions/electron-browser/remoteExtensionManagementIpc.ts new file mode 100644 index 000000000..84ec145c4 --- /dev/null +++ b/src/vs/workbench/services/extensions/electron-browser/remoteExtensionManagementIpc.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 { tmpdir } from 'os'; +import { IChannel } from 'vs/base/parts/ipc/common/ipc'; +import { IExtensionManagementService, ILocalExtension, IGalleryExtension, IExtensionGalleryService, InstallOperation } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { URI } from 'vs/base/common/uri'; +import { ExtensionType, IExtensionManifest } from 'vs/platform/extensions/common/extensions'; +import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { ILogService } from 'vs/platform/log/common/log'; +import { toErrorMessage } from 'vs/base/common/errorMessage'; +import { isUIExtension } from 'vs/workbench/services/extensions/common/extensionsUtil'; +import { isNonEmptyArray } from 'vs/base/common/arrays'; +import { values } from 'vs/base/common/map'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { localize } from 'vs/nls'; +import { IProductService } from 'vs/platform/product/common/product'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { ExtensionManagementChannelClient } from 'vs/platform/extensionManagement/common/extensionManagementIpc'; + +export class RemoteExtensionManagementChannelClient extends ExtensionManagementChannelClient { + + _serviceBrand: any; + + constructor( + channel: IChannel, + private readonly localExtensionManagementService: IExtensionManagementService, + private readonly galleryService: IExtensionGalleryService, + private readonly logService: ILogService, + private readonly configurationService: IConfigurationService, + private readonly productService: IProductService + ) { + super(channel); + } + + async install(vsix: URI): Promise { + const local = await super.install(vsix); + await this.installUIDependenciesAndPackedExtensions(local); + return local; + } + + async installFromGallery(extension: IGalleryExtension): Promise { + const local = await this.doInstallFromGallery(extension); + await this.installUIDependenciesAndPackedExtensions(local); + return local; + } + + private async doInstallFromGallery(extension: IGalleryExtension): Promise { + try { + const local = await super.installFromGallery(extension); + return local; + } catch (error) { + try { + this.logService.error(`Error while installing '${extension.identifier.id}' extension in the remote server.`, toErrorMessage(error)); + this.logService.info(`Trying to download '${extension.identifier.id}' extension locally and install`); + const local = await this.downloadCompatibleAndInstall(extension); + this.logService.info(`Successfully installed '${extension.identifier.id}' extension`); + return local; + } catch (e) { + this.logService.error(e); + throw error; + } + } + } + + private async downloadCompatibleAndInstall(extension: IGalleryExtension): Promise { + const installed = await this.getInstalled(ExtensionType.User); + const compatible = await this.galleryService.getCompatibleExtension(extension); + if (!compatible) { + return Promise.reject(new Error(localize('incompatible', "Unable to install extension '{0}' as it is not compatible with VS Code '{1}'.", extension.identifier.id, this.productService.version))); + } + const manifest = await this.galleryService.getManifest(compatible, CancellationToken.None); + if (manifest) { + const workspaceExtensions = await this.getAllWorkspaceDependenciesAndPackedExtensions(manifest, CancellationToken.None); + await Promise.all(workspaceExtensions.map(e => this.downloadAndInstall(e, installed))); + } + return this.downloadAndInstall(extension, installed); + } + + private async downloadAndInstall(extension: IGalleryExtension, installed: ILocalExtension[]): Promise { + const location = await this.galleryService.download(extension, URI.file(tmpdir()), installed.filter(i => areSameExtensions(i.identifier, extension.identifier))[0] ? InstallOperation.Update : InstallOperation.Install); + return super.install(location); + } + + private async installUIDependenciesAndPackedExtensions(local: ILocalExtension): Promise { + const uiExtensions = await this.getAllUIDependenciesAndPackedExtensions(local.manifest, CancellationToken.None); + const installed = await this.localExtensionManagementService.getInstalled(); + const toInstall = uiExtensions.filter(e => installed.every(i => !areSameExtensions(i.identifier, e.identifier))); + await Promise.all(toInstall.map(d => this.localExtensionManagementService.installFromGallery(d))); + } + + private async getAllUIDependenciesAndPackedExtensions(manifest: IExtensionManifest, token: CancellationToken): Promise { + const result = new Map(); + const extensions = [...(manifest.extensionPack || []), ...(manifest.extensionDependencies || [])]; + await this.getDependenciesAndPackedExtensionsRecursively(extensions, result, true, token); + return values(result); + } + + private async getAllWorkspaceDependenciesAndPackedExtensions(manifest: IExtensionManifest, token: CancellationToken): Promise { + const result = new Map(); + const extensions = [...(manifest.extensionPack || []), ...(manifest.extensionDependencies || [])]; + await this.getDependenciesAndPackedExtensionsRecursively(extensions, result, false, token); + return values(result); + } + + private async getDependenciesAndPackedExtensionsRecursively(toGet: string[], result: Map, uiExtension: boolean, token: CancellationToken): Promise { + if (toGet.length === 0) { + return Promise.resolve(); + } + + const extensions = (await this.galleryService.query({ names: toGet, pageSize: toGet.length }, token)).firstPage; + const manifests = await Promise.all(extensions.map(e => this.galleryService.getManifest(e, token))); + const extensionsManifests: IExtensionManifest[] = []; + for (let idx = 0; idx < extensions.length; idx++) { + const extension = extensions[idx]; + const manifest = manifests[idx]; + if (manifest && isUIExtension(manifest, this.productService, this.configurationService) === uiExtension) { + result.set(extension.identifier.id.toLowerCase(), extension); + extensionsManifests.push(manifest); + } + } + toGet = []; + for (const extensionManifest of extensionsManifests) { + if (isNonEmptyArray(extensionManifest.extensionDependencies)) { + for (const id of extensionManifest.extensionDependencies) { + if (!result.has(id.toLowerCase())) { + toGet.push(id); + } + } + } + if (isNonEmptyArray(extensionManifest.extensionPack)) { + for (const id of extensionManifest.extensionPack) { + if (!result.has(id.toLowerCase())) { + toGet.push(id); + } + } + } + } + return this.getDependenciesAndPackedExtensionsRecursively(toGet, result, uiExtension, token); + } +} \ No newline at end of file diff --git a/src/vs/workbench/services/extensions/node/extensionHostMain.ts b/src/vs/workbench/services/extensions/node/extensionHostMain.ts index 67d2ba56a..9e58237b6 100644 --- a/src/vs/workbench/services/extensions/node/extensionHostMain.ts +++ b/src/vs/workbench/services/extensions/node/extensionHostMain.ts @@ -19,7 +19,6 @@ import { RPCProtocol } from 'vs/workbench/services/extensions/common/rpcProtocol import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { withNullAsUndefined } from 'vs/base/common/types'; import { ILogService } from 'vs/platform/log/common/log'; -import { ISchemeTransformer } from 'vs/workbench/api/common/extHostLanguageFeatures'; // we don't (yet) throw when extensions parse // uris that have no scheme @@ -53,9 +52,7 @@ export class ExtensionHostMain { hostUtils: IHostUtils, consolePatchFn: IConsolePatchFn, logServiceFn: ILogServiceFn, - uriTransformer: IURITransformer | null, - schemeTransformer: ISchemeTransformer | null, - outputChannelName: string, + uriTransformer: IURITransformer | null ) { this._isTerminating = false; this._hostUtils = hostUtils; @@ -86,8 +83,7 @@ export class ExtensionHostMain { extHostConfiguraiton, initData.environment, this._extHostLogService, - schemeTransformer, - outputChannelName + uriTransformer ); // error forwarding and stack trace scanning diff --git a/src/vs/workbench/services/extensions/node/extensionHostProcess.ts b/src/vs/workbench/services/extensions/node/extensionHostProcess.ts index c7227dcdd..4c890beb6 100644 --- a/src/vs/workbench/services/extensions/node/extensionHostProcess.ts +++ b/src/vs/workbench/services/extensions/node/extensionHostProcess.ts @@ -3,11 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls from 'vs/nls'; import { startExtensionHostProcess } from 'vs/workbench/services/extensions/node/extensionHostProcessSetup'; -startExtensionHostProcess( - _ => null, - _ => null, - _ => nls.localize('extension host Log', "Extension Host") -).catch((err) => console.log(err)); +startExtensionHostProcess().catch((err) => console.log(err)); diff --git a/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts b/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts index cd9d907c6..1a5822e64 100644 --- a/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts +++ b/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts @@ -5,23 +5,33 @@ import * as nativeWatchdog from 'native-watchdog'; import * as net from 'net'; +import * as minimist from 'minimist'; import { onUnexpectedError } from 'vs/base/common/errors'; -import { Event } from 'vs/base/common/event'; +import { Event, Emitter } from 'vs/base/common/event'; import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc'; -import { PersistentProtocol, ProtocolConstants } from 'vs/base/parts/ipc/common/ipc.net'; -import { NodeSocket } from 'vs/base/parts/ipc/node/ipc.net'; +import { PersistentProtocol, ProtocolConstants, createBufferedEvent } from 'vs/base/parts/ipc/common/ipc.net'; +import { NodeSocket, WebSocketNodeSocket } from 'vs/base/parts/ipc/node/ipc.net'; import product from 'vs/platform/product/node/product'; import { IInitData, MainThreadConsoleShape } from 'vs/workbench/api/common/extHost.protocol'; import { MessageType, createMessageOfType, isMessageOfType, IExtHostSocketMessage, IExtHostReadyMessage } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; import { ExtensionHostMain, IExitFn, ILogServiceFn } from 'vs/workbench/services/extensions/node/extensionHostMain'; import { VSBuffer } from 'vs/base/common/buffer'; -import { createSpdLogService } from 'vs/platform/log/node/spdlogService'; import { ExtensionHostLogFileName } from 'vs/workbench/services/extensions/common/extensions'; -import { ISchemeTransformer } from 'vs/workbench/api/common/extHostLanguageFeatures'; -import { IURITransformer } from 'vs/base/common/uriIpc'; +import { IURITransformer, URITransformer, IRawURITransformer } from 'vs/base/common/uriIpc'; import { exists } from 'vs/base/node/pfs'; import { realpath } from 'vs/base/node/extpath'; import { IHostUtils } from 'vs/workbench/api/node/extHostExtensionService'; +import { SpdLogService } from 'vs/platform/log/node/spdlogService'; + +interface ParsedExtHostArgs { + uriTransformerPath?: string; +} + +const args = minimist(process.argv.slice(2), { + string: [ + 'uriTransformerPath' + ] +}) as ParsedExtHostArgs; // With Electron 2.x and node.js 8.x the "natives" module // can cause a native crash (see https://github.com/nodejs/node/issues/19891 and @@ -72,7 +82,7 @@ function patchPatchedConsole(mainThreadConsole: MainThreadConsoleShape): void { }; } -const createLogService: ILogServiceFn = initData => createSpdLogService(ExtensionHostLogFileName, initData.logLevel, initData.logsLocation.fsPath); +const createLogService: ILogServiceFn = initData => new SpdLogService(ExtensionHostLogFileName, initData.logsLocation.fsPath, initData.logLevel); interface IRendererConnection { protocol: IMessagePassingProtocol; @@ -101,27 +111,41 @@ function _createExtHostProtocol(): Promise { process.on('message', (msg: IExtHostSocketMessage, handle: net.Socket) => { if (msg && msg.type === 'VSCODE_EXTHOST_IPC_SOCKET') { const initialDataChunk = VSBuffer.wrap(Buffer.from(msg.initialDataChunk, 'base64')); + let socket: NodeSocket | WebSocketNodeSocket; + if (msg.skipWebSocketFrames) { + socket = new NodeSocket(handle); + } else { + socket = new WebSocketNodeSocket(new NodeSocket(handle)); + } if (protocol) { // reconnection case if (disconnectWaitTimer) { clearTimeout(disconnectWaitTimer); disconnectWaitTimer = null; } - protocol.beginAcceptReconnection(new NodeSocket(handle), initialDataChunk); + protocol.beginAcceptReconnection(socket, initialDataChunk); protocol.endAcceptReconnection(); } else { clearTimeout(timer); - protocol = new PersistentProtocol(new NodeSocket(handle), initialDataChunk); + protocol = new PersistentProtocol(socket, initialDataChunk); protocol.onClose(() => onTerminate()); resolve(protocol); - protocol.onSocketClose(() => { - // The socket has closed, let's give the renderer a certain amount of time to reconnect - disconnectWaitTimer = setTimeout(() => { - disconnectWaitTimer = null; + if (msg.skipWebSocketFrames) { + // Wait for rich client to reconnect + protocol.onSocketClose(() => { + // The socket has closed, let's give the renderer a certain amount of time to reconnect + disconnectWaitTimer = setTimeout(() => { + disconnectWaitTimer = null; + onTerminate(); + }, ProtocolConstants.ReconnectionGraceTime); + }); + } else { + // Do not wait for web companion to reconnect + protocol.onSocketClose(() => { onTerminate(); - }, ProtocolConstants.ReconnectionGraceTime); - }); + }); + } } } }); @@ -155,16 +179,22 @@ async function createExtHostProtocol(): Promise { return new class implements IMessagePassingProtocol { - private _terminating = false; + private readonly _onMessage = new Emitter(); + readonly onMessage: Event = createBufferedEvent(this._onMessage.event); - readonly onMessage: Event = Event.filter(protocol.onMessage, msg => { - if (!isMessageOfType(msg, MessageType.Terminate)) { - return true; - } - this._terminating = true; - onTerminate(); - return false; - }); + private _terminating: boolean; + + constructor() { + this._terminating = false; + protocol.onMessage((msg) => { + if (isMessageOfType(msg, MessageType.Terminate)) { + this._terminating = true; + onTerminate(); + } else { + this._onMessage.fire(msg); + } + }); + } send(msg: any): void { if (!this._terminating) { @@ -272,11 +302,7 @@ function connectToRenderer(protocol: IMessagePassingProtocol): Promise IURITransformer | null, - schemeTransformerFn: (initData: IInitData) => ISchemeTransformer | null, - outputChannelNameFn: (initData: IInitData) => string, -): Promise { +export async function startExtensionHostProcess(): Promise { const protocol = await createExtHostProtocol(); const renderer = await connectToRenderer(protocol); @@ -291,6 +317,17 @@ export async function startExtensionHostProcess( realpath(path: string) { return realpath(path); } }; + // Attempt to load uri transformer + let uriTransformer: IURITransformer | null = null; + if (initData.remote.authority && args.uriTransformerPath) { + try { + const rawURITransformerFactory = require.__$__nodeRequire(args.uriTransformerPath); + const rawURITransformer = rawURITransformerFactory(initData.remote.authority); + uriTransformer = new URITransformer(rawURITransformer); + } catch (e) { + console.error(e); + } + } const extensionHostMain = new ExtensionHostMain( renderer.protocol, @@ -298,9 +335,7 @@ export async function startExtensionHostProcess( hostUtils, patchPatchedConsole, createLogService, - uriTransformerFn(initData), - schemeTransformerFn(initData), - outputChannelNameFn(initData) + uriTransformer ); // rewrite onTerminate-function to be a proper shutdown diff --git a/src/vs/workbench/services/extensions/node/extensionPoints.ts b/src/vs/workbench/services/extensions/node/extensionPoints.ts index 6e2179ddd..5a7efd146 100644 --- a/src/vs/workbench/services/extensions/node/extensionPoints.ts +++ b/src/vs/workbench/services/extensions/node/extensionPoints.ts @@ -5,47 +5,20 @@ import * as nls from 'vs/nls'; import * as path from 'vs/base/common/path'; -import * as semver from 'semver'; +import * as semver from 'semver-umd'; import * as json from 'vs/base/common/json'; import * as arrays from 'vs/base/common/arrays'; import { getParseErrorMessage } from 'vs/base/common/jsonErrorMessages'; import * as types from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; import * as pfs from 'vs/base/node/pfs'; -import { getGalleryExtensionId, groupByExtension } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; -import { isValidExtensionVersion } from 'vs/platform/extensions/node/extensionValidator'; -import { ExtensionIdentifier, ExtensionIdentifierWithVersion, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { getGalleryExtensionId, groupByExtension, ExtensionIdentifierWithVersion } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { isValidExtensionVersion } from 'vs/platform/extensions/common/extensionValidator'; +import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { Translations, ILog } from 'vs/workbench/services/extensions/common/extensionPoints'; const MANIFEST_FILE = 'package.json'; -export interface Translations { - [id: string]: string; -} - -namespace Translations { - export function equals(a: Translations, b: Translations): boolean { - if (a === b) { - return true; - } - let aKeys = Object.keys(a); - let bKeys: Set = new Set(); - for (let key of Object.keys(b)) { - bKeys.add(key); - } - if (aKeys.length !== bKeys.size) { - return false; - } - - for (let key of aKeys) { - if (a[key] !== b[key]) { - return false; - } - bKeys.delete(key); - } - return bKeys.size === 0; - } -} - export interface NlsConfiguration { readonly devMode: boolean; readonly locale: string | undefined; @@ -53,12 +26,6 @@ export interface NlsConfiguration { readonly translations: Translations; } -export interface ILog { - error(source: string, message: string): void; - warn(source: string, message: string): void; - info(source: string, message: string): void; -} - abstract class ExtensionManifestHandler { protected readonly _ourVersion: string; @@ -251,7 +218,7 @@ class ExtensionManifestNLSReplacer extends ExtensionManifestHandler { * This routine makes the following assumptions: * The root element is an object literal */ - private static _replaceNLStrings(nlsConfig: NlsConfiguration, literal: T, messages: { [key: string]: string; }, originalMessages: { [key: string]: string } | null, log: ILog, messageScope: string): void { + private static _replaceNLStrings(nlsConfig: NlsConfiguration, literal: T, messages: { [key: string]: string; }, originalMessages: { [key: string]: string } | null, log: ILog, messageScope: string): void { function processEntry(obj: any, key: string | number, command?: boolean) { let value = obj[key]; if (types.isString(value)) { diff --git a/src/vs/workbench/services/extensions/node/extensionsUtil.ts b/src/vs/workbench/services/extensions/node/extensionsUtil.ts deleted file mode 100644 index d37b3f0f7..000000000 --- a/src/vs/workbench/services/extensions/node/extensionsUtil.ts +++ /dev/null @@ -1,14 +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 { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IExtensionManifest } from 'vs/platform/extensions/common/extensions'; -import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; -import { isUIExtension as _isUIExtension } from 'vs/platform/extensions/node/extensionsUtil'; - -export function isUIExtension(manifest: IExtensionManifest, configurationService: IConfigurationService): boolean { - const uiExtensionPoints = ExtensionsRegistry.getExtensionPoints().filter(e => e.defaultExtensionKind !== 'workspace').map(e => e.name); - return _isUIExtension(manifest, uiExtensionPoints, configurationService); -} diff --git a/src/vs/workbench/services/extensions/node/multiExtensionManagement.ts b/src/vs/workbench/services/extensions/node/multiExtensionManagement.ts deleted file mode 100644 index c430a811a..000000000 --- a/src/vs/workbench/services/extensions/node/multiExtensionManagement.ts +++ /dev/null @@ -1,201 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { Event, EventMultiplexer } from 'vs/base/common/event'; -import { - IExtensionManagementService, ILocalExtension, IGalleryExtension, InstallExtensionEvent, DidInstallExtensionEvent, IExtensionIdentifier, DidUninstallExtensionEvent, IReportedExtension, IGalleryMetadata, - IExtensionManagementServerService, IExtensionManagementServer, IExtensionGalleryService -} from 'vs/platform/extensionManagement/common/extensionManagement'; -import { ExtensionType, IExtensionManifest, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions'; -import { URI } from 'vs/base/common/uri'; -import { Disposable } from 'vs/base/common/lifecycle'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { CancellationToken } from 'vs/base/common/cancellation'; -import { getManifest } from 'vs/platform/extensionManagement/node/extensionManagementUtil'; -import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; -import { localize } from 'vs/nls'; -import { isUIExtension } from 'vs/workbench/services/extensions/node/extensionsUtil'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; - -export class MultiExtensionManagementService extends Disposable implements IExtensionManagementService { - - _serviceBrand: any; - - readonly onInstallExtension: Event; - readonly onDidInstallExtension: Event; - readonly onUninstallExtension: Event; - readonly onDidUninstallExtension: Event; - - private readonly servers: IExtensionManagementServer[]; - - constructor( - @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService, - @IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService, - @IConfigurationService private readonly configurationService: IConfigurationService - ) { - super(); - this.servers = this.extensionManagementServerService.remoteExtensionManagementServer ? [this.extensionManagementServerService.localExtensionManagementServer, this.extensionManagementServerService.remoteExtensionManagementServer] : [this.extensionManagementServerService.localExtensionManagementServer]; - - this.onInstallExtension = this._register(this.servers.reduce((emitter: EventMultiplexer, server) => { emitter.add(server.extensionManagementService.onInstallExtension); return emitter; }, new EventMultiplexer())).event; - this.onDidInstallExtension = this._register(this.servers.reduce((emitter: EventMultiplexer, server) => { emitter.add(server.extensionManagementService.onDidInstallExtension); return emitter; }, new EventMultiplexer())).event; - this.onUninstallExtension = this._register(this.servers.reduce((emitter: EventMultiplexer, server) => { emitter.add(server.extensionManagementService.onUninstallExtension); return emitter; }, new EventMultiplexer())).event; - this.onDidUninstallExtension = this._register(this.servers.reduce((emitter: EventMultiplexer, server) => { emitter.add(server.extensionManagementService.onDidUninstallExtension); return emitter; }, new EventMultiplexer())).event; - } - - getInstalled(type?: ExtensionType): Promise { - const installedExtensions: ILocalExtension[] = []; - return Promise.all(this.servers.map(({ extensionManagementService }) => extensionManagementService.getInstalled(type).then(extensions => installedExtensions.push(...extensions)))) - .then(_ => installedExtensions) - .catch(e => installedExtensions); - } - - async uninstall(extension: ILocalExtension, force?: boolean): Promise { - if (this.extensionManagementServerService.remoteExtensionManagementServer) { - const server = this.getServer(extension); - if (!server) { - return Promise.reject(`Invalid location ${extension.location.toString()}`); - } - if (isLanguagePackExtension(extension.manifest)) { - return this.uninstallEverywhere(extension, force); - } - return this.uninstallInServer(extension, server, force); - } - return this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.uninstall(extension, force); - } - - private async uninstallEverywhere(extension: ILocalExtension, force?: boolean): Promise { - const server = this.getServer(extension); - if (!server) { - return Promise.reject(`Invalid location ${extension.location.toString()}`); - } - const promise = server.extensionManagementService.uninstall(extension); - const anotherServer: IExtensionManagementServer = server === this.extensionManagementServerService.localExtensionManagementServer ? this.extensionManagementServerService.remoteExtensionManagementServer! : this.extensionManagementServerService.localExtensionManagementServer; - const installed = await anotherServer.extensionManagementService.getInstalled(ExtensionType.User); - extension = installed.filter(i => areSameExtensions(i.identifier, extension.identifier))[0]; - if (extension) { - await anotherServer.extensionManagementService.uninstall(extension); - } - return promise; - } - - private async uninstallInServer(extension: ILocalExtension, server: IExtensionManagementServer, force?: boolean): Promise { - if (server === this.extensionManagementServerService.localExtensionManagementServer) { - const installedExtensions = await this.extensionManagementServerService.remoteExtensionManagementServer!.extensionManagementService.getInstalled(ExtensionType.User); - const dependentNonUIExtensions = installedExtensions.filter(i => !isUIExtension(i.manifest, this.configurationService) - && i.manifest.extensionDependencies && i.manifest.extensionDependencies.some(id => areSameExtensions({ id }, extension.identifier))); - if (dependentNonUIExtensions.length) { - return Promise.reject(new Error(this.getDependentsErrorMessage(extension, dependentNonUIExtensions))); - } - } - return server.extensionManagementService.uninstall(extension, force); - } - - private getDependentsErrorMessage(extension: ILocalExtension, dependents: ILocalExtension[]): string { - if (dependents.length === 1) { - return localize('singleDependentError', "Cannot uninstall extension '{0}'. Extension '{1}' depends on this.", - extension.manifest.displayName || extension.manifest.name, dependents[0].manifest.displayName || dependents[0].manifest.name); - } - if (dependents.length === 2) { - return localize('twoDependentsError', "Cannot uninstall extension '{0}'. Extensions '{1}' and '{2}' depend on this.", - extension.manifest.displayName || extension.manifest.name, dependents[0].manifest.displayName || dependents[0].manifest.name, dependents[1].manifest.displayName || dependents[1].manifest.name); - } - return localize('multipleDependentsError', "Cannot uninstall extension '{0}'. Extensions '{1}', '{2}' and others depend on this.", - extension.manifest.displayName || extension.manifest.name, dependents[0].manifest.displayName || dependents[0].manifest.name, dependents[1].manifest.displayName || dependents[1].manifest.name); - - } - - reinstallFromGallery(extension: ILocalExtension): Promise { - const server = this.getServer(extension); - if (server) { - return server.extensionManagementService.reinstallFromGallery(extension); - } - return Promise.reject(`Invalid location ${extension.location.toString()}`); - } - - updateMetadata(extension: ILocalExtension, metadata: IGalleryMetadata): Promise { - const server = this.getServer(extension); - if (server) { - return server.extensionManagementService.updateMetadata(extension, metadata); - } - return Promise.reject(`Invalid location ${extension.location.toString()}`); - } - - zip(extension: ILocalExtension): Promise { - throw new Error('Not Supported'); - } - - unzip(zipLocation: URI, type: ExtensionType): Promise { - return Promise.all(this.servers.map(({ extensionManagementService }) => extensionManagementService.unzip(zipLocation, type))).then(([extensionIdentifier]) => extensionIdentifier); - } - - async install(vsix: URI): Promise { - if (this.extensionManagementServerService.remoteExtensionManagementServer) { - const manifest = await getManifest(vsix.fsPath); - if (isLanguagePackExtension(manifest)) { - // Install on both servers - const [extensionIdentifier] = await Promise.all(this.servers.map(server => server.extensionManagementService.install(vsix))); - return extensionIdentifier; - } - if (isUIExtension(manifest, this.configurationService)) { - // Install only on local server - return this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.install(vsix); - } - // Install only on remote server - const promise = this.extensionManagementServerService.remoteExtensionManagementServer.extensionManagementService.install(vsix); - // Install UI Dependencies on local server - await this.installUIDependencies(manifest); - return promise; - } - return this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.install(vsix); - } - - async installFromGallery(gallery: IGalleryExtension): Promise { - if (this.extensionManagementServerService.remoteExtensionManagementServer) { - const manifest = await this.extensionGalleryService.getManifest(gallery, CancellationToken.None); - if (manifest) { - if (isLanguagePackExtension(manifest)) { - // Install on both servers - return Promise.all(this.servers.map(server => server.extensionManagementService.installFromGallery(gallery))).then(() => undefined); - } - if (isUIExtension(manifest, this.configurationService)) { - // Install only on local server - return this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.installFromGallery(gallery); - } - // Install only on remote server - const promise = this.extensionManagementServerService.remoteExtensionManagementServer.extensionManagementService.installFromGallery(gallery); - // Install UI Dependencies on local server - await this.installUIDependencies(manifest); - return promise; - } else { - return Promise.reject(localize('Manifest is not found', "Installing Extension {0} failed: Manifest is not found.", gallery.displayName || gallery.name)); - } - } - return this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.installFromGallery(gallery); - } - - private async installUIDependencies(manifest: IExtensionManifest): Promise { - if (manifest.extensionDependencies && manifest.extensionDependencies.length) { - const dependencies = await this.extensionGalleryService.loadAllDependencies(manifest.extensionDependencies.map(id => ({ id })), CancellationToken.None); - if (dependencies.length) { - await Promise.all(dependencies.map(async d => { - const manifest = await this.extensionGalleryService.getManifest(d, CancellationToken.None); - if (manifest && isUIExtension(manifest, this.configurationService)) { - await this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.installFromGallery(d); - } - })); - } - } - } - - getExtensionsReport(): Promise { - return this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.getExtensionsReport(); - } - - private getServer(extension: ILocalExtension): IExtensionManagementServer | null { - return this.extensionManagementServerService.getExtensionManagementServer(extension.location); - } -} - -registerSingleton(IExtensionManagementService, MultiExtensionManagementService); \ No newline at end of file diff --git a/src/vs/workbench/services/extensions/node/proxyResolver.ts b/src/vs/workbench/services/extensions/node/proxyResolver.ts index d85ae8c07..6aa6ba1e6 100644 --- a/src/vs/workbench/services/extensions/node/proxyResolver.ts +++ b/src/vs/workbench/services/extensions/node/proxyResolver.ts @@ -103,22 +103,33 @@ function setupProxyResolution( let results: ConnectionResult[] = []; function logEvent() { timeout = undefined; - /* __GDPR__ - "resolveProxy" : { - "count": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "duration": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "errorCount": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "cacheCount": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "cacheSize": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "cacheRolls": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "envCount": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "settingsCount": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "localhostCount": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "envNoProxyCount": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "results": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } - } - */ - mainThreadTelemetry.$publicLog('resolveProxy', { count, duration, errorCount, cacheCount, cacheSize: cache.size, cacheRolls, envCount, settingsCount, localhostCount, envNoProxyCount, results }); + type ResolveProxyClassification = { + count: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; + duration: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; + errorCount: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; + cacheCount: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; + cacheSize: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; + cacheRolls: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; + envCount: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; + settingsCount: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; + localhostCount: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; + envNoProxyCount: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; + results: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth' }; + }; + type ResolveProxyEvent = { + count: number; + duration: number; + errorCount: number; + cacheCount: number; + cacheSize: number; + cacheRolls: number; + envCount: number; + settingsCount: number; + localhostCount: number; + envNoProxyCount: number; + results: ConnectionResult[]; + }; + mainThreadTelemetry.$publicLog2('resolveProxy', { count, duration, errorCount, cacheCount, cacheSize: cache.size, cacheRolls, envCount, settingsCount, localhostCount, envNoProxyCount, results }); count = duration = errorCount = cacheCount = envCount = settingsCount = localhostCount = envNoProxyCount = 0; results = []; } @@ -403,7 +414,7 @@ function configureModuleLoading(extensionService: ExtHostExtensionService, looku const modules = lookup[request]; const ext = extensionPaths.findSubstr(URI.file(parent.filename).fsPath); if (ext && ext.enableProposedApi) { - return modules[(ext).proxySupport] || modules.onRequest; + return (modules as any)[(ext).proxySupport] || modules.onRequest; } return modules.default; }; @@ -457,8 +468,8 @@ async function readCaCertificates() { return undefined; } -function readWindowsCaCertificates() { - const winCA = require.__$__nodeRequire('vscode-windows-ca-certs'); +async function readWindowsCaCertificates() { + const winCA = await import('vscode-windows-ca-certs'); let ders: any[] = []; const store = winCA(); @@ -471,22 +482,26 @@ function readWindowsCaCertificates() { store.done(); } - const seen = {}; - const certs = ders.map(derToPem) - .filter(pem => !seen[pem] && (seen[pem] = true)); + const certs = new Set(ders.map(derToPem)); return { - certs, + certs: Array.from(certs), append: true }; } async function readMacCaCertificates() { - const stdout = (await promisify(cp.execFile)('/usr/bin/security', ['find-certificate', '-a', '-p'], { encoding: 'utf8', maxBuffer: 1024 * 1024 })).stdout; - const seen = {}; - const certs = stdout.split(/(?=-----BEGIN CERTIFICATE-----)/g) - .filter(pem => !!pem.length && !seen[pem] && (seen[pem] = true)); + const stdout = await new Promise((resolve, reject) => { + const child = cp.spawn('/usr/bin/security', ['find-certificate', '-a', '-p']); + const stdout: string[] = []; + child.stdout.setEncoding('utf8'); + child.stdout.on('data', str => stdout.push(str)); + child.on('error', reject); + child.on('exit', code => code ? reject(code) : resolve(stdout.join(''))); + }); + const certs = new Set(stdout.split(/(?=-----BEGIN CERTIFICATE-----)/g) + .filter(pem => !!pem.length)); return { - certs, + certs: Array.from(certs), append: true }; } @@ -500,11 +515,10 @@ async function readLinuxCaCertificates() { for (const certPath of linuxCaCertificatePaths) { try { const content = await promisify(fs.readFile)(certPath, { encoding: 'utf8' }); - const seen = {}; - const certs = content.split(/(?=-----BEGIN CERTIFICATE-----)/g) - .filter(pem => !!pem.length && !seen[pem] && (seen[pem] = true)); + const certs = new Set(content.split(/(?=-----BEGIN CERTIFICATE-----)/g) + .filter(pem => !!pem.length)); return { - certs, + certs: Array.from(certs), append: false }; } catch (err) { diff --git a/src/vs/workbench/services/files/common/workspaceWatcher.ts b/src/vs/workbench/services/files/common/workspaceWatcher.ts index a16c82e35..7aa7ef157 100644 --- a/src/vs/workbench/services/files/common/workspaceWatcher.ts +++ b/src/vs/workbench/services/files/common/workspaceWatcher.ts @@ -16,7 +16,7 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { StorageScope, IStorageService } from 'vs/platform/storage/common/storage'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { localize } from 'vs/nls'; -import { FileService } from 'vs/workbench/services/files/common/fileService'; +import { FileService } from 'vs/platform/files/common/fileService'; export class WorkspaceWatcher extends Disposable { diff --git a/src/vs/workbench/services/files/electron-browser/diskFileSystemProvider.ts b/src/vs/workbench/services/files/electron-browser/diskFileSystemProvider.ts deleted file mode 100644 index 118eb6c76..000000000 --- a/src/vs/workbench/services/files/electron-browser/diskFileSystemProvider.ts +++ /dev/null @@ -1,38 +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 { shell } from 'electron'; -import { DiskFileSystemProvider as NodeDiskFileSystemProvider } from 'vs/workbench/services/files/node/diskFileSystemProvider'; -import { FileDeleteOptions, FileSystemProviderCapabilities } from 'vs/platform/files/common/files'; -import { isWindows } from 'vs/base/common/platform'; -import { localize } from 'vs/nls'; -import { basename } from 'vs/base/common/path'; -import { ILogService } from 'vs/platform/log/common/log'; - -export class DiskFileSystemProvider extends NodeDiskFileSystemProvider { - - constructor(logService: ILogService) { - super(logService); - } - - get capabilities(): FileSystemProviderCapabilities { - if (!this._capabilities) { - this._capabilities = super.capabilities | FileSystemProviderCapabilities.Trash; - } - - return this._capabilities; - } - - protected async doDelete(filePath: string, opts: FileDeleteOptions): Promise { - if (!opts.useTrash) { - return super.doDelete(filePath, opts); - } - - const result = shell.moveItemToTrash(filePath); - if (!result) { - throw new Error(isWindows ? localize('binFailed', "Failed to move '{0}' to the recycle bin", basename(filePath)) : localize('trashFailed', "Failed to move '{0}' to the trash", basename(filePath))); - } - } -} \ No newline at end of file diff --git a/src/vs/workbench/services/files/node/diskFileSystemProvider.ts b/src/vs/workbench/services/files/node/diskFileSystemProvider.ts deleted file mode 100644 index 174a7502f..000000000 --- a/src/vs/workbench/services/files/node/diskFileSystemProvider.ts +++ /dev/null @@ -1,492 +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 { mkdir, open, close, read, write, fdatasync } from 'fs'; -import { promisify } from 'util'; -import { IDisposable, Disposable, toDisposable, dispose } from 'vs/base/common/lifecycle'; -import { IFileSystemProvider, FileSystemProviderCapabilities, IFileChange, IWatchOptions, IStat, FileType, FileDeleteOptions, FileOverwriteOptions, FileWriteOptions, FileOpenOptions, FileSystemProviderErrorCode, createFileSystemProviderError, FileSystemProviderError } from 'vs/platform/files/common/files'; -import { URI } from 'vs/base/common/uri'; -import { Event, Emitter } from 'vs/base/common/event'; -import { isLinux, isWindows } from 'vs/base/common/platform'; -import { statLink, readdir, unlink, move, copy, readFile, truncate, rimraf, RimRafMode, exists } from 'vs/base/node/pfs'; -import { normalize, basename, dirname } from 'vs/base/common/path'; -import { joinPath } from 'vs/base/common/resources'; -import { isEqual } from 'vs/base/common/extpath'; -import { retry, ThrottledDelayer } from 'vs/base/common/async'; -import { ILogService, LogLevel } from 'vs/platform/log/common/log'; -import { localize } from 'vs/nls'; -import { IDiskFileChange, toFileChanges } from 'vs/workbench/services/files/node/watcher/watcher'; -import { FileWatcher as UnixWatcherService } from 'vs/workbench/services/files/node/watcher/unix/watcherService'; -import { FileWatcher as WindowsWatcherService } from 'vs/workbench/services/files/node/watcher/win32/watcherService'; -import { FileWatcher as NsfwWatcherService } from 'vs/workbench/services/files/node/watcher/nsfw/watcherService'; -import { FileWatcher as NodeJSWatcherService } from 'vs/workbench/services/files/node/watcher/nodejs/watcherService'; - -export class DiskFileSystemProvider extends Disposable implements IFileSystemProvider { - - constructor(private logService: ILogService) { - super(); - } - - //#region File Capabilities - - onDidChangeCapabilities: Event = Event.None; - - protected _capabilities: FileSystemProviderCapabilities; - get capabilities(): FileSystemProviderCapabilities { - if (!this._capabilities) { - this._capabilities = - FileSystemProviderCapabilities.FileReadWrite | - FileSystemProviderCapabilities.FileOpenReadWriteClose | - FileSystemProviderCapabilities.FileFolderCopy; - - if (isLinux) { - this._capabilities |= FileSystemProviderCapabilities.PathCaseSensitive; - } - } - - return this._capabilities; - } - - //#endregion - - //#region File Metadata Resolving - - async stat(resource: URI): Promise { - try { - const { stat, isSymbolicLink } = await statLink(this.toFilePath(resource)); // cannot use fs.stat() here to support links properly - - let type: number; - if (isSymbolicLink) { - type = FileType.SymbolicLink | (stat.isDirectory() ? FileType.Directory : FileType.File); - } else { - type = stat.isFile() ? FileType.File : stat.isDirectory() ? FileType.Directory : FileType.Unknown; - } - - return { - type, - ctime: stat.ctime.getTime(), - mtime: stat.mtime.getTime(), - size: stat.size - }; - } catch (error) { - throw this.toFileSystemProviderError(error); - } - } - - async readdir(resource: URI): Promise<[string, FileType][]> { - try { - const children = await readdir(this.toFilePath(resource)); - - const result: [string, FileType][] = []; - for (let i = 0; i < children.length; i++) { - const child = children[i]; - - try { - const stat = await this.stat(joinPath(resource, child)); - result.push([child, stat.type]); - } catch (error) { - this.logService.trace(error); // ignore errors for individual entries that can arise from permission denied - } - } - - return result; - } catch (error) { - throw this.toFileSystemProviderError(error); - } - } - - //#endregion - - //#region File Reading/Writing - - async readFile(resource: URI): Promise { - try { - const filePath = this.toFilePath(resource); - - return await readFile(filePath); - } catch (error) { - throw this.toFileSystemProviderError(error); - } - } - - async writeFile(resource: URI, content: Uint8Array, opts: FileWriteOptions): Promise { - let handle: number | undefined = undefined; - try { - const filePath = this.toFilePath(resource); - - // Validate target - const fileExists = await exists(filePath); - if (fileExists && !opts.overwrite) { - throw createFileSystemProviderError(new Error(localize('fileExists', "File already exists")), FileSystemProviderErrorCode.FileExists); - } else if (!fileExists && !opts.create) { - throw createFileSystemProviderError(new Error(localize('fileNotExists', "File does not exist")), FileSystemProviderErrorCode.FileNotFound); - } - - // Open - handle = await this.open(resource, { create: true }); - - // Write content at once - await this.write(handle, 0, content, 0, content.byteLength); - } catch (error) { - throw this.toFileSystemProviderError(error); - } finally { - if (typeof handle === 'number') { - await this.close(handle); - } - } - } - - private writeHandles: Set = new Set(); - private canFlush: boolean = true; - - async open(resource: URI, opts: FileOpenOptions): Promise { - try { - const filePath = this.toFilePath(resource); - - let flags: string | undefined = undefined; - if (opts.create) { - if (isWindows && await exists(filePath)) { - try { - // On Windows and if the file exists, we use a different strategy of saving the file - // by first truncating the file and then writing with r+ flag. This helps to save hidden files on Windows - // (see https://github.com/Microsoft/vscode/issues/931) and prevent removing alternate data streams - // (see https://github.com/Microsoft/vscode/issues/6363) - await truncate(filePath, 0); - - // After a successful truncate() the flag can be set to 'r+' which will not truncate. - flags = 'r+'; - } catch (error) { - this.logService.trace(error); - } - } - - // we take opts.create as a hint that the file is opened for writing - // as such we use 'w' to truncate an existing or create the - // file otherwise. we do not allow reading. - if (!flags) { - flags = 'w'; - } - } else { - // otherwise we assume the file is opened for reading - // as such we use 'r' to neither truncate, nor create - // the file. - flags = 'r'; - } - - const handle = await promisify(open)(filePath, flags); - - // remember that this handle was used for writing - if (opts.create) { - this.writeHandles.add(handle); - } - - return handle; - } catch (error) { - throw this.toFileSystemProviderError(error); - } - } - - async close(fd: number): Promise { - try { - // if a handle is closed that was used for writing, ensure - // to flush the contents to disk if possible. - if (this.writeHandles.delete(fd) && this.canFlush) { - try { - await promisify(fdatasync)(fd); - } catch (error) { - // In some exotic setups it is well possible that node fails to sync - // In that case we disable flushing and log the error to our logger - this.canFlush = false; - this.logService.error(error); - } - } - - return await promisify(close)(fd); - } catch (error) { - throw this.toFileSystemProviderError(error); - } - } - - async read(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise { - try { - const result = await promisify(read)(fd, data, offset, length, pos); - if (typeof result === 'number') { - return result; // node.d.ts fail - } - - return result.bytesRead; - } catch (error) { - throw this.toFileSystemProviderError(error); - } - } - - async write(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise { - // we know at this point that the file to write to is truncated and thus empty - // if the write now fails, the file remains empty. as such we really try hard - // to ensure the write succeeds by retrying up to three times. - return retry(() => this.doWrite(fd, pos, data, offset, length), 100 /* ms delay */, 3 /* retries */); - } - - private async doWrite(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise { - try { - const result = await promisify(write)(fd, data, offset, length, pos); - if (typeof result === 'number') { - return result; // node.d.ts fail - } - - return result.bytesWritten; - } catch (error) { - throw this.toFileSystemProviderError(error); - } - } - - //#endregion - - //#region Move/Copy/Delete/Create Folder - - async mkdir(resource: URI): Promise { - try { - await promisify(mkdir)(this.toFilePath(resource)); - } catch (error) { - throw this.toFileSystemProviderError(error); - } - } - - async delete(resource: URI, opts: FileDeleteOptions): Promise { - try { - const filePath = this.toFilePath(resource); - - await this.doDelete(filePath, opts); - } catch (error) { - throw this.toFileSystemProviderError(error); - } - } - - protected async doDelete(filePath: string, opts: FileDeleteOptions): Promise { - if (opts.recursive) { - await rimraf(filePath, RimRafMode.MOVE); - } else { - await unlink(filePath); - } - } - - async rename(from: URI, to: URI, opts: FileOverwriteOptions): Promise { - const fromFilePath = this.toFilePath(from); - const toFilePath = this.toFilePath(to); - - try { - - // Ensure target does not exist - await this.validateTargetDeleted(from, to, opts && opts.overwrite); - - // Move - await move(fromFilePath, toFilePath); - } catch (error) { - - // rewrite some typical errors that can happen especially around symlinks - // to something the user can better understand - if (error.code === 'EINVAL' || error.code === 'EBUSY' || error.code === 'ENAMETOOLONG') { - error = new Error(localize('moveError', "Unable to move '{0}' into '{1}' ({2}).", basename(fromFilePath), basename(dirname(toFilePath)), error.toString())); - } - - throw this.toFileSystemProviderError(error); - } - } - - async copy(from: URI, to: URI, opts: FileOverwriteOptions): Promise { - const fromFilePath = this.toFilePath(from); - const toFilePath = this.toFilePath(to); - - try { - - // Ensure target does not exist - await this.validateTargetDeleted(from, to, opts && opts.overwrite); - - // Copy - await copy(fromFilePath, toFilePath); - } catch (error) { - - // rewrite some typical errors that can happen especially around symlinks - // to something the user can better understand - if (error.code === 'EINVAL' || error.code === 'EBUSY' || error.code === 'ENAMETOOLONG') { - error = new Error(localize('copyError', "Unable to copy '{0}' into '{1}' ({2}).", basename(fromFilePath), basename(dirname(toFilePath)), error.toString())); - } - - throw this.toFileSystemProviderError(error); - } - } - - private async validateTargetDeleted(from: URI, to: URI, overwrite?: boolean): Promise { - const fromFilePath = this.toFilePath(from); - const toFilePath = this.toFilePath(to); - - const isPathCaseSensitive = !!(this.capabilities & FileSystemProviderCapabilities.PathCaseSensitive); - const isCaseChange = isPathCaseSensitive ? false : isEqual(fromFilePath, toFilePath, true /* ignore case */); - - // handle existing target (unless this is a case change) - if (!isCaseChange && await exists(toFilePath)) { - if (!overwrite) { - throw createFileSystemProviderError(new Error('File at target already exists'), FileSystemProviderErrorCode.FileExists); - } - - await this.delete(to, { recursive: true, useTrash: false }); - } - } - - //#endregion - - //#region File Watching - - private _onDidWatchErrorOccur: Emitter = this._register(new Emitter()); - get onDidErrorOccur(): Event { return this._onDidWatchErrorOccur.event; } - - private _onDidChangeFile: Emitter = this._register(new Emitter()); - get onDidChangeFile(): Event { return this._onDidChangeFile.event; } - - private recursiveWatcher: WindowsWatcherService | UnixWatcherService | NsfwWatcherService | undefined; - private recursiveFoldersToWatch: { path: string, excludes: string[] }[] = []; - private recursiveWatchRequestDelayer: ThrottledDelayer = this._register(new ThrottledDelayer(0)); - - watch(resource: URI, opts: IWatchOptions): IDisposable { - if (opts.recursive) { - return this.watchRecursive(resource, opts.excludes); - } - - return this.watchNonRecursive(resource); // TODO@ben ideally the same watcher can be used in both cases - } - - private watchRecursive(resource: URI, excludes: string[]): IDisposable { - - // Add to list of folders to watch recursively - const folderToWatch = { path: this.toFilePath(resource), excludes }; - this.recursiveFoldersToWatch.push(folderToWatch); - - // Trigger update - this.refreshRecursiveWatchers(); - - return toDisposable(() => { - - // Remove from list of folders to watch recursively - this.recursiveFoldersToWatch.splice(this.recursiveFoldersToWatch.indexOf(folderToWatch), 1); - - // Trigger update - this.refreshRecursiveWatchers(); - }); - } - - private refreshRecursiveWatchers(): void { - - // Buffer requests for recursive watching to decide on right watcher - // that supports potentially watching more than one folder at once - this.recursiveWatchRequestDelayer.trigger(() => { - this.doRefreshRecursiveWatchers(); - - return Promise.resolve(); - }); - } - - private doRefreshRecursiveWatchers(): void { - - // Reuse existing - if (this.recursiveWatcher instanceof NsfwWatcherService) { - this.recursiveWatcher.setFolders(this.recursiveFoldersToWatch); - } - - // Create new - else { - - // Dispose old - dispose(this.recursiveWatcher); - - // Create new if we actually have folders to watch - if (this.recursiveFoldersToWatch.length > 0) { - let watcherImpl: { - new( - folders: { path: string, excludes: string[] }[], - onChange: (changes: IDiskFileChange[]) => void, - onError: (msg: string) => void, - verboseLogging: boolean - ): WindowsWatcherService | UnixWatcherService | NsfwWatcherService - }; - - // Single Folder Watcher - if (this.recursiveFoldersToWatch.length === 1) { - if (isWindows) { - watcherImpl = WindowsWatcherService; - } else { - watcherImpl = UnixWatcherService; - } - } - - // Multi Folder Watcher - else { - watcherImpl = NsfwWatcherService; - } - - // Create and start watching - this.recursiveWatcher = new watcherImpl( - this.recursiveFoldersToWatch, - event => this._onDidChangeFile.fire(toFileChanges(event)), - error => this._onDidWatchErrorOccur.fire(new Error(error)), - this.logService.getLevel() === LogLevel.Trace - ); - } - } - } - - private watchNonRecursive(resource: URI): IDisposable { - return new NodeJSWatcherService( - this.toFilePath(resource), - changes => this._onDidChangeFile.fire(toFileChanges(changes)), - error => this._onDidWatchErrorOccur.fire(new Error(error)), - info => this.logService.trace(info), - this.logService.getLevel() === LogLevel.Trace - ); - } - - //#endregion - - //#region Helpers - - protected toFilePath(resource: URI): string { - return normalize(resource.fsPath); - } - - private toFileSystemProviderError(error: NodeJS.ErrnoException): FileSystemProviderError { - if (error instanceof FileSystemProviderError) { - return error; // avoid double conversion - } - - let code: FileSystemProviderErrorCode; - switch (error.code) { - case 'ENOENT': - code = FileSystemProviderErrorCode.FileNotFound; - break; - case 'EISDIR': - code = FileSystemProviderErrorCode.FileIsADirectory; - break; - case 'EEXIST': - code = FileSystemProviderErrorCode.FileExists; - break; - case 'EPERM': - case 'EACCES': - code = FileSystemProviderErrorCode.NoPermissions; - break; - default: - code = FileSystemProviderErrorCode.Unknown; - } - - return createFileSystemProviderError(error, code); - } - - //#endregion - - dispose(): void { - super.dispose(); - - dispose(this.recursiveWatcher); - this.recursiveWatcher = undefined; - } -} diff --git a/src/vs/workbench/services/files/node/watcher/nodejs/watcherService.ts b/src/vs/workbench/services/files/node/watcher/nodejs/watcherService.ts deleted file mode 100644 index d3fe85520..000000000 --- a/src/vs/workbench/services/files/node/watcher/nodejs/watcherService.ts +++ /dev/null @@ -1,124 +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 { IDiskFileChange, normalizeFileChanges } from 'vs/workbench/services/files/node/watcher/watcher'; -import { Disposable } from 'vs/base/common/lifecycle'; -import { statLink, readlink } from 'vs/base/node/pfs'; -import { watchFolder, watchFile, CHANGE_BUFFER_DELAY } from 'vs/base/node/watcher'; -import { FileChangeType } from 'vs/platform/files/common/files'; -import { ThrottledDelayer } from 'vs/base/common/async'; -import { join, basename } from 'vs/base/common/path'; - -export class FileWatcher extends Disposable { - private isDisposed: boolean; - - private fileChangesDelayer: ThrottledDelayer = this._register(new ThrottledDelayer(CHANGE_BUFFER_DELAY * 2 /* sync on delay from underlying library */)); - private fileChangesBuffer: IDiskFileChange[] = []; - - constructor( - private path: string, - private onFileChanges: (changes: IDiskFileChange[]) => void, - private errorLogger: (msg: string) => void, - private verboseLogger: (msg: string) => void, - private verboseLogging: boolean - ) { - super(); - - this.startWatching(); - } - - private async startWatching(): Promise { - try { - const { stat, isSymbolicLink } = await statLink(this.path); - - if (this.isDisposed) { - return; - } - - let pathToWatch = this.path; - if (isSymbolicLink) { - try { - pathToWatch = await readlink(pathToWatch); - } catch (error) { - this.onError(error); - } - } - - // Watch Folder - if (stat.isDirectory()) { - this._register(watchFolder(pathToWatch, (eventType, path) => { - this.onFileChange({ - type: eventType === 'changed' ? FileChangeType.UPDATED : eventType === 'added' ? FileChangeType.ADDED : FileChangeType.DELETED, - path: join(this.path, basename(path)) // ensure path is identical with what was passed in - }); - }, error => this.onError(error))); - } - - // Watch File - else { - this._register(watchFile(pathToWatch, eventType => { - this.onFileChange({ - type: eventType === 'changed' ? FileChangeType.UPDATED : FileChangeType.DELETED, - path: this.path // ensure path is identical with what was passed in - }); - }, error => this.onError(error))); - } - } catch (error) { - this.onError(error); - } - } - - private onFileChange(event: IDiskFileChange): void { - - // Add to buffer - this.fileChangesBuffer.push(event); - - // Logging - if (this.verboseLogging) { - this.onVerbose(`[File Watcher (node.js)] ${event.type === FileChangeType.ADDED ? '[ADDED]' : event.type === FileChangeType.DELETED ? '[DELETED]' : '[CHANGED]'} ${event.path}`); - } - - // Handle emit through delayer to accommodate for bulk changes and thus reduce spam - this.fileChangesDelayer.trigger(() => { - const fileChanges = this.fileChangesBuffer; - this.fileChangesBuffer = []; - - // Event normalization - const normalizedFileChanges = normalizeFileChanges(fileChanges); - - // Logging - if (this.verboseLogging) { - normalizedFileChanges.forEach(event => { - this.onVerbose(`[File Watcher (node.js)] >> normalized ${event.type === FileChangeType.ADDED ? '[ADDED]' : event.type === FileChangeType.DELETED ? '[DELETED]' : '[CHANGED]'} ${event.path}`); - }); - } - - // Fire - if (normalizedFileChanges.length > 0) { - this.onFileChanges(normalizedFileChanges); - } - - return Promise.resolve(); - }); - } - - private onError(error: string): void { - if (!this.isDisposed) { - this.errorLogger(error); - } - } - - private onVerbose(msg: string): void { - if (!this.isDisposed) { - this.verboseLogger(msg); - } - } - - dispose(): void { - this.isDisposed = true; - - super.dispose(); - } -} \ No newline at end of file diff --git a/src/vs/workbench/services/files/node/watcher/nsfw/watcher.ts b/src/vs/workbench/services/files/node/watcher/nsfw/watcher.ts deleted file mode 100644 index 3e1fb0fdb..000000000 --- a/src/vs/workbench/services/files/node/watcher/nsfw/watcher.ts +++ /dev/null @@ -1,27 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { Event } from 'vs/base/common/event'; -import { IDiskFileChange } from 'vs/workbench/services/files/node/watcher/watcher'; - -export interface IWatcherRequest { - path: string; - excludes: string[]; -} - -export interface IWatcherOptions { - verboseLogging: boolean; -} - -export interface IWatchError { - message: string; -} - -export interface IWatcherService { - watch(options: IWatcherOptions): Event; - setRoots(roots: IWatcherRequest[]): Promise; - setVerboseLogging(enabled: boolean): Promise; - stop(): Promise; -} \ No newline at end of file diff --git a/src/vs/workbench/services/files/node/watcher/nsfw/watcherApp.ts b/src/vs/workbench/services/files/node/watcher/nsfw/watcherApp.ts deleted file mode 100644 index 49c892fb5..000000000 --- a/src/vs/workbench/services/files/node/watcher/nsfw/watcherApp.ts +++ /dev/null @@ -1,13 +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 { Server } from 'vs/base/parts/ipc/node/ipc.cp'; -import { WatcherChannel } from 'vs/workbench/services/files/node/watcher/nsfw/watcherIpc'; -import { NsfwWatcherService } from 'vs/workbench/services/files/node/watcher/nsfw/nsfwWatcherService'; - -const server = new Server('watcher'); -const service = new NsfwWatcherService(); -const channel = new WatcherChannel(service); -server.registerChannel('watcher', channel); \ No newline at end of file diff --git a/src/vs/workbench/services/files/node/watcher/nsfw/watcherIpc.ts b/src/vs/workbench/services/files/node/watcher/nsfw/watcherIpc.ts deleted file mode 100644 index c073759b1..000000000 --- a/src/vs/workbench/services/files/node/watcher/nsfw/watcherIpc.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 { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; -import { IWatcherRequest, IWatcherService, IWatcherOptions, IWatchError } from './watcher'; -import { Event } from 'vs/base/common/event'; -import { IDiskFileChange } from 'vs/workbench/services/files/node/watcher/watcher'; - -export class WatcherChannel implements IServerChannel { - - constructor(private service: IWatcherService) { } - - listen(_: unknown, event: string, arg?: any): Event { - switch (event) { - case 'watch': return this.service.watch(arg); - } - - throw new Error(`Event not found: ${event}`); - } - - call(_: unknown, command: string, arg?: any): Promise { - switch (command) { - case 'setRoots': return this.service.setRoots(arg); - case 'setVerboseLogging': return this.service.setVerboseLogging(arg); - case 'stop': return this.service.stop(); - } - - throw new Error(`Call not found: ${command}`); - } -} - -export class WatcherChannelClient implements IWatcherService { - - constructor(private channel: IChannel) { } - - watch(options: IWatcherOptions): Event { - return this.channel.listen('watch', options); - } - - setVerboseLogging(enable: boolean): Promise { - return this.channel.call('setVerboseLogging', enable); - } - - setRoots(roots: IWatcherRequest[]): Promise { - return this.channel.call('setRoots', roots); - } - - stop(): Promise { - return this.channel.call('stop'); - } -} \ No newline at end of file diff --git a/src/vs/workbench/services/files/node/watcher/nsfw/watcherService.ts b/src/vs/workbench/services/files/node/watcher/nsfw/watcherService.ts deleted file mode 100644 index 8924e1216..000000000 --- a/src/vs/workbench/services/files/node/watcher/nsfw/watcherService.ts +++ /dev/null @@ -1,92 +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 { getNextTickChannel } from 'vs/base/parts/ipc/common/ipc'; -import { Client } from 'vs/base/parts/ipc/node/ipc.cp'; -import { IDiskFileChange } from 'vs/workbench/services/files/node/watcher/watcher'; -import { WatcherChannelClient } from 'vs/workbench/services/files/node/watcher/nsfw/watcherIpc'; -import { Disposable } from 'vs/base/common/lifecycle'; -import { Event } from 'vs/base/common/event'; -import { IWatchError, IWatcherRequest } from 'vs/workbench/services/files/node/watcher/nsfw/watcher'; -import { getPathFromAmdModule } from 'vs/base/common/amd'; - -export class FileWatcher extends Disposable { - private static readonly MAX_RESTARTS = 5; - - private service: WatcherChannelClient; - private isDisposed: boolean; - private restartCounter: number; - - constructor( - private folders: IWatcherRequest[], - private onFileChanges: (changes: IDiskFileChange[]) => void, - private errorLogger: (msg: string) => void, - private verboseLogging: boolean, - ) { - super(); - - this.isDisposed = false; - this.restartCounter = 0; - - this.startWatching(); - } - - private startWatching(): void { - const client = this._register(new Client( - getPathFromAmdModule(require, 'bootstrap-fork'), - { - serverName: 'File Watcher (nsfw)', - args: ['--type=watcherService'], - env: { - AMD_ENTRYPOINT: 'vs/workbench/services/files/node/watcher/nsfw/watcherApp', - PIPE_LOGGING: 'true', - VERBOSE_LOGGING: this.verboseLogging - } - } - )); - - this._register(client.onDidProcessExit(() => { - // our watcher app should never be completed because it keeps on watching. being in here indicates - // that the watcher process died and we want to restart it here. we only do it a max number of times - if (!this.isDisposed) { - if (this.restartCounter <= FileWatcher.MAX_RESTARTS) { - this.errorLogger('[File Watcher (nsfw)] terminated unexpectedly and is restarted again...'); - this.restartCounter++; - this.startWatching(); - } else { - this.errorLogger('[File Watcher (nsfw)] failed to start after retrying for some time, giving up. Please report this as a bug report!'); - } - } - })); - - // Initialize watcher - const channel = getNextTickChannel(client.getChannel('watcher')); - this.service = new WatcherChannelClient(channel); - - const options = { verboseLogging: this.verboseLogging }; - const onWatchEvent = Event.filter(this.service.watch(options), () => !this.isDisposed); - - const onError = Event.filter(onWatchEvent, (e): e is IWatchError => typeof e.message === 'string'); - this._register(onError(err => this.errorLogger(`[File Watcher (nsfw)] ${err.message}`))); - - const onFileChanges = Event.filter(onWatchEvent, (e): e is IDiskFileChange[] => Array.isArray(e) && e.length > 0); - this._register(onFileChanges(e => this.onFileChanges(e))); - - // Start watching - this.setFolders(this.folders); - } - - setFolders(folders: IWatcherRequest[]): void { - this.folders = folders; - - this.service.setRoots(folders); - } - - dispose(): void { - this.isDisposed = true; - - super.dispose(); - } -} diff --git a/src/vs/workbench/services/files/node/watcher/unix/watcher.ts b/src/vs/workbench/services/files/node/watcher/unix/watcher.ts deleted file mode 100644 index 3e1fb0fdb..000000000 --- a/src/vs/workbench/services/files/node/watcher/unix/watcher.ts +++ /dev/null @@ -1,27 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { Event } from 'vs/base/common/event'; -import { IDiskFileChange } from 'vs/workbench/services/files/node/watcher/watcher'; - -export interface IWatcherRequest { - path: string; - excludes: string[]; -} - -export interface IWatcherOptions { - verboseLogging: boolean; -} - -export interface IWatchError { - message: string; -} - -export interface IWatcherService { - watch(options: IWatcherOptions): Event; - setRoots(roots: IWatcherRequest[]): Promise; - setVerboseLogging(enabled: boolean): Promise; - stop(): Promise; -} \ No newline at end of file diff --git a/src/vs/workbench/services/files/node/watcher/unix/watcherApp.ts b/src/vs/workbench/services/files/node/watcher/unix/watcherApp.ts deleted file mode 100644 index 01473fb5c..000000000 --- a/src/vs/workbench/services/files/node/watcher/unix/watcherApp.ts +++ /dev/null @@ -1,13 +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 { Server } from 'vs/base/parts/ipc/node/ipc.cp'; -import { WatcherChannel } from 'vs/workbench/services/files/node/watcher/unix/watcherIpc'; -import { ChokidarWatcherService } from 'vs/workbench/services/files/node/watcher/unix/chokidarWatcherService'; - -const server = new Server('watcher'); -const service = new ChokidarWatcherService(); -const channel = new WatcherChannel(service); -server.registerChannel('watcher', channel); \ No newline at end of file diff --git a/src/vs/workbench/services/files/node/watcher/unix/watcherIpc.ts b/src/vs/workbench/services/files/node/watcher/unix/watcherIpc.ts deleted file mode 100644 index c073759b1..000000000 --- a/src/vs/workbench/services/files/node/watcher/unix/watcherIpc.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 { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; -import { IWatcherRequest, IWatcherService, IWatcherOptions, IWatchError } from './watcher'; -import { Event } from 'vs/base/common/event'; -import { IDiskFileChange } from 'vs/workbench/services/files/node/watcher/watcher'; - -export class WatcherChannel implements IServerChannel { - - constructor(private service: IWatcherService) { } - - listen(_: unknown, event: string, arg?: any): Event { - switch (event) { - case 'watch': return this.service.watch(arg); - } - - throw new Error(`Event not found: ${event}`); - } - - call(_: unknown, command: string, arg?: any): Promise { - switch (command) { - case 'setRoots': return this.service.setRoots(arg); - case 'setVerboseLogging': return this.service.setVerboseLogging(arg); - case 'stop': return this.service.stop(); - } - - throw new Error(`Call not found: ${command}`); - } -} - -export class WatcherChannelClient implements IWatcherService { - - constructor(private channel: IChannel) { } - - watch(options: IWatcherOptions): Event { - return this.channel.listen('watch', options); - } - - setVerboseLogging(enable: boolean): Promise { - return this.channel.call('setVerboseLogging', enable); - } - - setRoots(roots: IWatcherRequest[]): Promise { - return this.channel.call('setRoots', roots); - } - - stop(): Promise { - return this.channel.call('stop'); - } -} \ No newline at end of file diff --git a/src/vs/workbench/services/files/node/watcher/unix/watcherService.ts b/src/vs/workbench/services/files/node/watcher/unix/watcherService.ts deleted file mode 100644 index 04ce4808a..000000000 --- a/src/vs/workbench/services/files/node/watcher/unix/watcherService.ts +++ /dev/null @@ -1,92 +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 { getNextTickChannel } from 'vs/base/parts/ipc/common/ipc'; -import { Client } from 'vs/base/parts/ipc/node/ipc.cp'; -import { IDiskFileChange } from 'vs/workbench/services/files/node/watcher/watcher'; -import { WatcherChannelClient } from 'vs/workbench/services/files/node/watcher/unix/watcherIpc'; -import { Disposable } from 'vs/base/common/lifecycle'; -import { Event } from 'vs/base/common/event'; -import { IWatchError, IWatcherRequest } from 'vs/workbench/services/files/node/watcher/unix/watcher'; -import { getPathFromAmdModule } from 'vs/base/common/amd'; - -export class FileWatcher extends Disposable { - private static readonly MAX_RESTARTS = 5; - - private isDisposed: boolean; - private restartCounter: number; - private service: WatcherChannelClient; - - constructor( - private folders: IWatcherRequest[], - private onFileChanges: (changes: IDiskFileChange[]) => void, - private errorLogger: (msg: string) => void, - private verboseLogging: boolean - ) { - super(); - - this.isDisposed = false; - this.restartCounter = 0; - - this.startWatching(); - } - - private startWatching(): void { - const client = this._register(new Client( - getPathFromAmdModule(require, 'bootstrap-fork'), - { - serverName: 'File Watcher (chokidar)', - args: ['--type=watcherService'], - env: { - AMD_ENTRYPOINT: 'vs/workbench/services/files/node/watcher/unix/watcherApp', - PIPE_LOGGING: 'true', - VERBOSE_LOGGING: this.verboseLogging - } - } - )); - - this._register(client.onDidProcessExit(() => { - // our watcher app should never be completed because it keeps on watching. being in here indicates - // that the watcher process died and we want to restart it here. we only do it a max number of times - if (!this.isDisposed) { - if (this.restartCounter <= FileWatcher.MAX_RESTARTS) { - this.errorLogger('[File Watcher (chokidar)] terminated unexpectedly and is restarted again...'); - this.restartCounter++; - this.startWatching(); - } else { - this.errorLogger('[File Watcher (chokidar)] failed to start after retrying for some time, giving up. Please report this as a bug report!'); - } - } - })); - - // Initialize watcher - const channel = getNextTickChannel(client.getChannel('watcher')); - this.service = new WatcherChannelClient(channel); - - const options = { verboseLogging: this.verboseLogging }; - const onWatchEvent = Event.filter(this.service.watch(options), () => !this.isDisposed); - - const onError = Event.filter(onWatchEvent, (e): e is IWatchError => typeof e.message === 'string'); - this._register(onError(err => this.errorLogger(`[File Watcher (chokidar)] ${err.message}`))); - - const onFileChanges = Event.filter(onWatchEvent, (e): e is IDiskFileChange[] => Array.isArray(e) && e.length > 0); - this._register(onFileChanges(e => this.onFileChanges(e))); - - // Start watching - this.service.setRoots(this.folders); - } - - setFolders(folders: IWatcherRequest[]): void { - this.folders = folders; - - this.service.setRoots(folders); - } - - dispose(): void { - this.isDisposed = true; - - super.dispose(); - } -} diff --git a/src/vs/workbench/services/files/node/watcher/watcher.ts b/src/vs/workbench/services/files/node/watcher/watcher.ts deleted file mode 100644 index cfe12d13f..000000000 --- a/src/vs/workbench/services/files/node/watcher/watcher.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. - *--------------------------------------------------------------------------------------------*/ - -import { URI as uri } from 'vs/base/common/uri'; -import { FileChangeType, isParent, IFileChange } from 'vs/platform/files/common/files'; -import { isLinux } from 'vs/base/common/platform'; - -export interface IDiskFileChange { - type: FileChangeType; - path: string; -} - -export function toFileChanges(changes: IDiskFileChange[]): IFileChange[] { - return changes.map(change => ({ - type: change.type, - resource: uri.file(change.path) - })); -} - -export function normalizeFileChanges(changes: IDiskFileChange[]): IDiskFileChange[] { - - // Build deltas - const normalizer = new EventNormalizer(); - for (const event of changes) { - normalizer.processEvent(event); - } - - return normalizer.normalize(); -} - -class EventNormalizer { - private normalized: IDiskFileChange[] = []; - private mapPathToChange: Map = new Map(); - - processEvent(event: IDiskFileChange): void { - const existingEvent = this.mapPathToChange.get(event.path); - - // Event path already exists - if (existingEvent) { - const currentChangeType = existingEvent.type; - const newChangeType = event.type; - - // ignore CREATE followed by DELETE in one go - if (currentChangeType === FileChangeType.ADDED && newChangeType === FileChangeType.DELETED) { - this.mapPathToChange.delete(event.path); - this.normalized.splice(this.normalized.indexOf(existingEvent), 1); - } - - // flatten DELETE followed by CREATE into CHANGE - else if (currentChangeType === FileChangeType.DELETED && newChangeType === FileChangeType.ADDED) { - existingEvent.type = FileChangeType.UPDATED; - } - - // Do nothing. Keep the created event - else if (currentChangeType === FileChangeType.ADDED && newChangeType === FileChangeType.UPDATED) { } - - // Otherwise apply change type - else { - existingEvent.type = newChangeType; - } - } - - // Otherwise store new - else { - this.normalized.push(event); - this.mapPathToChange.set(event.path, event); - } - } - - normalize(): IDiskFileChange[] { - const addedChangeEvents: IDiskFileChange[] = []; - const deletedPaths: string[] = []; - - // This algorithm will remove all DELETE events up to the root folder - // that got deleted if any. This ensures that we are not producing - // DELETE events for each file inside a folder that gets deleted. - // - // 1.) split ADD/CHANGE and DELETED events - // 2.) sort short deleted paths to the top - // 3.) for each DELETE, check if there is a deleted parent and ignore the event in that case - return this.normalized.filter(e => { - if (e.type !== FileChangeType.DELETED) { - addedChangeEvents.push(e); - - return false; // remove ADD / CHANGE - } - - return true; // keep DELETE - }).sort((e1, e2) => { - return e1.path.length - e2.path.length; // shortest path first - }).filter(e => { - if (deletedPaths.some(d => isParent(e.path, d, !isLinux /* ignorecase */))) { - return false; // DELETE is ignored if parent is deleted already - } - - // otherwise mark as deleted - deletedPaths.push(e.path); - - return true; - }).concat(addedChangeEvents); - } -} diff --git a/src/vs/workbench/services/files/node/watcher/win32/watcherService.ts b/src/vs/workbench/services/files/node/watcher/win32/watcherService.ts deleted file mode 100644 index 0d27d6831..000000000 --- a/src/vs/workbench/services/files/node/watcher/win32/watcherService.ts +++ /dev/null @@ -1,69 +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 { IDiskFileChange } from 'vs/workbench/services/files/node/watcher/watcher'; -import { OutOfProcessWin32FolderWatcher } from 'vs/workbench/services/files/node/watcher/win32/csharpWatcherService'; -import { posix } from 'vs/base/common/path'; -import { rtrim, endsWith } from 'vs/base/common/strings'; -import { Disposable } from 'vs/base/common/lifecycle'; - -export class FileWatcher extends Disposable { - private isDisposed: boolean; - private folder: { path: string, excludes: string[] }; - - constructor( - folders: { path: string, excludes: string[] }[], - private onFileChanges: (changes: IDiskFileChange[]) => void, - private errorLogger: (msg: string) => void, - private verboseLogging: boolean - ) { - super(); - - this.folder = folders[0]; - - if (this.folder.path.indexOf('\\\\') === 0 && endsWith(this.folder.path, posix.sep)) { - // for some weird reason, node adds a trailing slash to UNC paths - // we never ever want trailing slashes as our base path unless - // someone opens root ("/"). - // See also https://github.com/nodejs/io.js/issues/1765 - this.folder.path = rtrim(this.folder.path, posix.sep); - } - - this.startWatching(); - } - - private startWatching(): void { - this._register(new OutOfProcessWin32FolderWatcher( - this.folder.path, - this.folder.excludes, - events => this.onFileEvents(events), - error => this.onError(error), - this.verboseLogging - )); - } - - private onFileEvents(events: IDiskFileChange[]): void { - if (this.isDisposed) { - return; - } - - // Emit through event emitter - if (events.length > 0) { - this.onFileChanges(events); - } - } - - private onError(error: string): void { - if (!this.isDisposed) { - this.errorLogger(error); - } - } - - dispose(): void { - this.isDisposed = true; - - super.dispose(); - } -} \ No newline at end of file diff --git a/src/vs/workbench/services/heap/common/heap.ts b/src/vs/workbench/services/heap/common/heap.ts deleted file mode 100644 index 4aa4cc0ec..000000000 --- a/src/vs/workbench/services/heap/common/heap.ts +++ /dev/null @@ -1,33 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - - -import { Event } from 'vs/base/common/event'; -import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; - -export const IHeapService = createDecorator('heapService'); - -export interface ObjectIdentifier { - $ident?: number; -} - -export interface IHeapService { - _serviceBrand: any; - - readonly onGarbageCollection: Event; - - /** - * Track gc-collection for the given object - */ - trackObject(obj: ObjectIdentifier | undefined): void; -} - - - -export class NullHeapService implements IHeapService { - _serviceBrand: any; - onGarbageCollection = Event.None; - trackObject() { } -} diff --git a/src/vs/workbench/services/heap/node/heap.ts b/src/vs/workbench/services/heap/node/heap.ts deleted file mode 100644 index 8f627bace..000000000 --- a/src/vs/workbench/services/heap/node/heap.ts +++ /dev/null @@ -1,80 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { Event, Emitter } from 'vs/base/common/event'; -import { GCSignal } from 'gc-signals'; -import { IHeapService, ObjectIdentifier } from 'vs/workbench/services/heap/common/heap'; - -export class HeapService implements IHeapService { - - _serviceBrand: any; - - private readonly _onGarbageCollection: Emitter = new Emitter(); - public readonly onGarbageCollection: Event = this._onGarbageCollection.event; - - private _activeSignals = new WeakMap(); - private _activeIds = new Set(); - - private _consumeHandle: any; - private _ctor: { new(id: number): GCSignal }; - private _ctorInit: Promise; - - constructor() { - // - } - - dispose() { - clearInterval(this._consumeHandle); - } - - trackObject(obj: ObjectIdentifier | undefined | null): void { - if (!obj) { - return; - } - - const ident = obj.$ident; - if (typeof ident !== 'number') { - return; - } - - if (this._activeIds.has(ident)) { - return; - } - - if (this._ctor) { - // track and leave - this._activeIds.add(ident); - this._activeSignals.set(obj, new this._ctor(ident)); - - } else { - // make sure to load gc-signals, then track and leave - if (!this._ctorInit) { - this._ctorInit = import('gc-signals').then(({ GCSignal, consumeSignals }) => { - this._ctor = GCSignal; - this._consumeHandle = setInterval(() => { - const ids = consumeSignals(); - - if (ids.length > 0) { - // local book-keeping - for (const id of ids) { - this._activeIds.delete(id); - } - // fire event - this._onGarbageCollection.fire(ids); - } - }, 15 * 1000); - }); - } - - this._ctorInit.then(() => { - this._activeIds.add(ident); - this._activeSignals.set(obj, new this._ctor(ident)); - }); - } - } -} - -registerSingleton(IHeapService, HeapService, true); diff --git a/src/vs/workbench/services/history/browser/history.ts b/src/vs/workbench/services/history/browser/history.ts index 74ef7b968..91e3136b5 100644 --- a/src/vs/workbench/services/history/browser/history.ts +++ b/src/vs/workbench/services/history/browser/history.ts @@ -13,13 +13,13 @@ import { IHistoryService } from 'vs/workbench/services/history/common/history'; 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, Disposable } from 'vs/base/common/lifecycle'; +import { dispose, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { Registry } from 'vs/platform/registry/common/platform'; import { Event } from 'vs/base/common/event'; import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; import { IEditorGroupsService, IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; -import { IWindowsService } from 'vs/platform/windows/common/windows'; +import { IWindowService } from 'vs/platform/windows/common/windows'; import { getCodeEditor, ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { getExcludes, ISearchConfiguration } from 'vs/workbench/services/search/common/search'; import { IExpression } from 'vs/base/common/glob'; @@ -32,6 +32,7 @@ import { IContextKeyService, RawContextKey, IContextKey } from 'vs/platform/cont import { coalesce } from 'vs/base/common/arrays'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { withNullAsUndefined } from 'vs/base/common/types'; +import { addDisposableListener, EventType, EventHelper } from 'vs/base/browser/dom'; /** * Stores the selection & view state of an editor and allows to compare it to other selection states. @@ -105,11 +106,11 @@ export class HistoryService extends Disposable implements IHistoryService { private static readonly MAX_STACK_ITEMS = 50; private static readonly MAX_RECENTLY_CLOSED_EDITORS = 20; - private activeEditorListeners: IDisposable[]; + private readonly activeEditorListeners = this._register(new DisposableStore()); private lastActiveEditor?: IEditorIdentifier; - private editorHistoryListeners: Map = new Map(); - private editorStackListeners: Map = new Map(); + private readonly editorHistoryListeners: Map = new Map(); + private readonly editorStackListeners: Map = new Map(); private stack: IStackEntry[]; private index: number; @@ -137,15 +138,13 @@ export class HistoryService extends Disposable implements IHistoryService { @IStorageService private readonly storageService: IStorageService, @IConfigurationService private readonly configurationService: IConfigurationService, @IFileService private readonly fileService: IFileService, - @IWindowsService private readonly windowService: IWindowsService, + @IWindowService private readonly windowService: IWindowService, @IInstantiationService private readonly instantiationService: IInstantiationService, @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService, - @IContextKeyService private readonly contextKeyService: IContextKeyService + @IContextKeyService private readonly contextKeyService: IContextKeyService, ) { super(); - this.activeEditorListeners = []; - this.canNavigateBackContextKey = (new RawContextKey('canNavigateBack', false)).bindTo(this.contextKeyService); this.canNavigateForwardContextKey = (new RawContextKey('canNavigateForward', false)).bindTo(this.contextKeyService); this.canNavigateToLastEditLocationContextKey = (new RawContextKey('canNavigateToLastEditLocation', false)).bindTo(this.contextKeyService); @@ -186,6 +185,39 @@ export class HistoryService extends Disposable implements IHistoryService { if (this.editorService.activeControl) { this.onActiveEditorChanged(); } + + // Mouse back/forward support + const mouseBackForwardSupportListener = this._register(new DisposableStore()); + const handleMouseBackForwardSupport = () => { + mouseBackForwardSupportListener.clear(); + + if (this.configurationService.getValue('workbench.editor.mouseBackForwardToNavigate')) { + mouseBackForwardSupportListener.add(addDisposableListener(this.layoutService.getWorkbenchElement(), EventType.MOUSE_DOWN, e => this.onMouseDown(e))); + } + }; + + this._register(this.configurationService.onDidChangeConfiguration(event => { + if (event.affectsConfiguration('workbench.editor.mouseBackForwardToNavigate')) { + handleMouseBackForwardSupport(); + } + })); + + handleMouseBackForwardSupport(); + } + + private onMouseDown(e: MouseEvent): void { + + // Support to navigate in history when mouse buttons 4/5 are pressed + switch (e.button) { + case 3: + EventHelper.stop(e); + this.back(); + break; + case 4: + EventHelper.stop(e); + this.forward(); + break; + } } private onActiveEditorChanged(): void { @@ -198,8 +230,7 @@ export class HistoryService extends Disposable implements IHistoryService { this.lastActiveEditor = activeControl && activeControl.input && activeControl.group ? { editor: activeControl.input, groupId: activeControl.group.id } : undefined; // Dispose old listeners - dispose(this.activeEditorListeners); - this.activeEditorListeners = []; + this.activeEditorListeners.clear(); // Propagate to history this.handleActiveEditorChange(activeControl); @@ -212,14 +243,14 @@ export class HistoryService extends Disposable implements IHistoryService { // 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(Event.debounce(activeTextEditorWidget.onDidChangeCursorPosition, (last, event) => event, 0)((event => { + this.activeEditorListeners.add(Event.debounce(activeTextEditorWidget.onDidChangeCursorPosition, (last, event) => event, 0)((event => { this.handleEditorSelectionChangeEvent(activeControl, event); }))); // Track the last edit location by tracking model content change events // Use a debouncer to make sure to capture the correct cursor position // after the model content has changed. - this.activeEditorListeners.push(Event.debounce(activeTextEditorWidget.onDidChangeModelContent, (last, event) => event, 0)((event => this.rememberLastEditLocation(activeEditor!, activeTextEditorWidget)))); + this.activeEditorListeners.add(Event.debounce(activeTextEditorWidget.onDidChangeModelContent, (last, event) => event, 0)((event => this.rememberLastEditLocation(activeEditor!, activeTextEditorWidget)))); } } @@ -478,19 +509,19 @@ export class HistoryService extends Disposable implements IHistoryService { } } - private onEditorDispose(editor: EditorInput, listener: Function, mapEditorToDispose: Map): void { + private onEditorDispose(editor: EditorInput, listener: Function, mapEditorToDispose: Map): void { const toDispose = Event.once(editor.onDispose)(() => listener()); let disposables = mapEditorToDispose.get(editor); if (!disposables) { - disposables = []; + disposables = new DisposableStore(); mapEditorToDispose.set(editor, disposables); } - disposables.push(toDispose); + disposables.add(toDispose); } - private clearOnEditorDispose(editor: IEditorInput | IResourceInput | FileChangesEvent, mapEditorToDispose: Map): void { + private clearOnEditorDispose(editor: IEditorInput | IResourceInput | FileChangesEvent, mapEditorToDispose: Map): void { if (editor instanceof EditorInput) { const disposables = mapEditorToDispose.get(editor); if (disposables) { @@ -958,7 +989,7 @@ export class HistoryService extends Disposable implements IHistoryService { getLastActiveFile(filterByScheme: string): URI | undefined { const history = this.getHistory(); for (const input of history) { - let resource: URI | null; + let resource: URI | undefined; if (input instanceof EditorInput) { resource = toResource(input, { filterByScheme }); } else { diff --git a/src/vs/workbench/services/integrity/node/integrityService.ts b/src/vs/workbench/services/integrity/node/integrityService.ts index 56b5d19f0..00e083a9b 100644 --- a/src/vs/workbench/services/integrity/node/integrityService.ts +++ b/src/vs/workbench/services/integrity/node/integrityService.ts @@ -71,9 +71,9 @@ export class IntegrityServiceImpl implements IIntegrityService { this.isPure().then(r => { if (r.isPure) { - // all is good - return; + return; // all is good } + this._prompt(); }); } @@ -106,29 +106,25 @@ export class IntegrityServiceImpl implements IIntegrityService { return this._isPurePromise; } - private _isPure(): Promise { + private async _isPure(): Promise { const expectedChecksums = product.checksums || {}; - return this.lifecycleService.when(LifecyclePhase.Eventually).then(() => { - let asyncResults: Promise[] = Object.keys(expectedChecksums).map((filename) => { - return this._resolve(filename, expectedChecksums[filename]); - }); + await this.lifecycleService.when(LifecyclePhase.Eventually); - return Promise.all(asyncResults).then((allResults) => { - let isPure = true; - for (let i = 0, len = allResults.length; i < len; i++) { - if (!allResults[i].isPure) { - isPure = false; - break; - } - } + const allResults = await Promise.all(Object.keys(expectedChecksums).map(filename => this._resolve(filename, expectedChecksums[filename]))); - return { - isPure: isPure, - proof: allResults - }; - }); - }); + let isPure = true; + for (let i = 0, len = allResults.length; i < len; i++) { + if (!allResults[i].isPure) { + isPure = false; + break; + } + } + + return { + isPure: isPure, + proof: allResults + }; } private _resolve(filename: string, expected: string): Promise { diff --git a/src/vs/workbench/services/keybinding/browser/keybindingService.ts b/src/vs/workbench/services/keybinding/browser/keybindingService.ts new file mode 100644 index 000000000..dec59cfca --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keybindingService.ts @@ -0,0 +1,734 @@ +/*--------------------------------------------------------------------------------------------- + * 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 browser from 'vs/base/browser/browser'; +import * as dom from 'vs/base/browser/dom'; +import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; +import { Emitter, Event } from 'vs/base/common/event'; +import { IJSONSchema } from 'vs/base/common/jsonSchema'; +import { Keybinding, ResolvedKeybinding, KeyCode, KeyMod } from 'vs/base/common/keyCodes'; +import { KeybindingParser } from 'vs/base/common/keybindingParser'; +import { OS, OperatingSystem, isWeb } from 'vs/base/common/platform'; +import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/commands'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { Extensions as ConfigExtensions, IConfigurationNode, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; +import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { Extensions, IJSONContributionRegistry } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; +import { AbstractKeybindingService } from 'vs/platform/keybinding/common/abstractKeybindingService'; +import { IKeyboardEvent, IUserFriendlyKeybinding, KeybindingSource, IKeybindingService, IKeybindingEvent } from 'vs/platform/keybinding/common/keybinding'; +import { KeybindingResolver } from 'vs/platform/keybinding/common/keybindingResolver'; +import { IKeybindingItem, IKeybindingRule2, KeybindingWeight, KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; +import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; +import { INotificationService } from 'vs/platform/notification/common/notification'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { keybindingsTelemetry } from 'vs/platform/telemetry/common/telemetryUtils'; +import { ExtensionMessageCollector, ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; +import { IUserKeybindingItem, KeybindingIO, OutputBuilder } from 'vs/workbench/services/keybinding/common/keybindingIO'; +import { IKeyboardMapper } from 'vs/workbench/services/keybinding/common/keyboardMapper'; +import { IWindowService } from 'vs/platform/windows/common/windows'; +import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; +import { MenuRegistry } from 'vs/platform/actions/common/actions'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +// tslint:disable-next-line: import-patterns +import { commandsExtensionPoint } from 'vs/workbench/api/common/menusExtensionPoint'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { RunOnceScheduler } from 'vs/base/common/async'; +import { URI } from 'vs/base/common/uri'; +import { IFileService } from 'vs/platform/files/common/files'; +import { parse } from 'vs/base/common/json'; +import * as objects from 'vs/base/common/objects'; +import { IKeymapService } from 'vs/workbench/services/keybinding/common/keymapInfo'; +import { getDispatchConfig } from 'vs/workbench/services/keybinding/common/dispatchConfig'; +import { isArray } from 'vs/base/common/types'; +import { INavigatorWithKeyboard } from 'vs/workbench/services/keybinding/common/navigatorKeyboard'; +import { ScanCodeUtils, IMMUTABLE_CODE_TO_KEY_CODE } from 'vs/base/common/scanCode'; + +interface ContributedKeyBinding { + command: string; + args?: any; + key: string; + when?: string; + mac?: string; + linux?: string; + win?: string; +} + +function isContributedKeyBindingsArray(thing: ContributedKeyBinding | ContributedKeyBinding[]): thing is ContributedKeyBinding[] { + return Array.isArray(thing); +} + +function isValidContributedKeyBinding(keyBinding: ContributedKeyBinding, rejects: string[]): boolean { + if (!keyBinding) { + rejects.push(nls.localize('nonempty', "expected non-empty value.")); + return false; + } + if (typeof keyBinding.command !== 'string') { + rejects.push(nls.localize('requirestring', "property `{0}` is mandatory and must be of type `string`", 'command')); + return false; + } + if (keyBinding.key && typeof keyBinding.key !== 'string') { + rejects.push(nls.localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'key')); + return false; + } + if (keyBinding.when && typeof keyBinding.when !== 'string') { + rejects.push(nls.localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'when')); + return false; + } + if (keyBinding.mac && typeof keyBinding.mac !== 'string') { + rejects.push(nls.localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'mac')); + return false; + } + if (keyBinding.linux && typeof keyBinding.linux !== 'string') { + rejects.push(nls.localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'linux')); + return false; + } + if (keyBinding.win && typeof keyBinding.win !== 'string') { + rejects.push(nls.localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'win')); + return false; + } + return true; +} + +let keybindingType: IJSONSchema = { + type: 'object', + default: { command: '', key: '' }, + properties: { + command: { + description: nls.localize('vscode.extension.contributes.keybindings.command', 'Identifier of the command to run when keybinding is triggered.'), + type: 'string' + }, + args: { + description: nls.localize('vscode.extension.contributes.keybindings.args', "Arguments to pass to the command to execute.") + }, + key: { + description: nls.localize('vscode.extension.contributes.keybindings.key', 'Key or key sequence (separate keys with plus-sign and sequences with space, e.g. Ctrl+O and Ctrl+L L for a chord).'), + type: 'string' + }, + mac: { + description: nls.localize('vscode.extension.contributes.keybindings.mac', 'Mac specific key or key sequence.'), + type: 'string' + }, + linux: { + description: nls.localize('vscode.extension.contributes.keybindings.linux', 'Linux specific key or key sequence.'), + type: 'string' + }, + win: { + description: nls.localize('vscode.extension.contributes.keybindings.win', 'Windows specific key or key sequence.'), + type: 'string' + }, + when: { + description: nls.localize('vscode.extension.contributes.keybindings.when', 'Condition when the key is active.'), + type: 'string' + }, + } +}; + +const keybindingsExtPoint = ExtensionsRegistry.registerExtensionPoint({ + extensionPoint: 'keybindings', + deps: [commandsExtensionPoint], + jsonSchema: { + description: nls.localize('vscode.extension.contributes.keybindings', "Contributes keybindings."), + oneOf: [ + keybindingType, + { + type: 'array', + items: keybindingType + } + ] + } +}); + +export class WorkbenchKeybindingService extends AbstractKeybindingService { + + private _keyboardMapper: IKeyboardMapper; + private _cachedResolver: KeybindingResolver | null; + private userKeybindings: UserKeybindings; + + constructor( + @IContextKeyService contextKeyService: IContextKeyService, + @ICommandService commandService: ICommandService, + @ITelemetryService telemetryService: ITelemetryService, + @INotificationService notificationService: INotificationService, + @IEnvironmentService environmentService: IEnvironmentService, + @IConfigurationService configurationService: IConfigurationService, + @IWindowService private readonly windowService: IWindowService, + @IExtensionService extensionService: IExtensionService, + @IFileService fileService: IFileService, + @IKeymapService private readonly keymapService: IKeymapService + ) { + super(contextKeyService, commandService, telemetryService, notificationService); + + updateSchema(); + + let dispatchConfig = getDispatchConfig(configurationService); + configurationService.onDidChangeConfiguration((e) => { + let newDispatchConfig = getDispatchConfig(configurationService); + if (dispatchConfig === newDispatchConfig) { + return; + } + + dispatchConfig = newDispatchConfig; + this._keyboardMapper = this.keymapService.getKeyboardMapper(dispatchConfig); + this.updateResolver({ source: KeybindingSource.Default }); + }); + + this._keyboardMapper = this.keymapService.getKeyboardMapper(dispatchConfig); + this.keymapService.onDidChangeKeyboardMapper(() => { + this._keyboardMapper = this.keymapService.getKeyboardMapper(dispatchConfig); + this.updateResolver({ source: KeybindingSource.Default }); + }); + + this._cachedResolver = null; + + this.userKeybindings = this._register(new UserKeybindings(environmentService.keybindingsResource, fileService)); + this.userKeybindings.initialize().then(() => { + if (this.userKeybindings.keybindings.length) { + this.updateResolver({ source: KeybindingSource.User }); + } + }); + this._register(this.userKeybindings.onDidChange(() => { + type CustomKeybindingsChangedClassification = { + keyCount: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true } + }; + + this._telemetryService.publicLog2<{ keyCount: number }, CustomKeybindingsChangedClassification>('customKeybindingsChanged', { + keyCount: this.userKeybindings.keybindings.length + }); + this.updateResolver({ + source: KeybindingSource.User, + keybindings: this.userKeybindings.keybindings + }); + })); + + keybindingsExtPoint.setHandler((extensions) => { + + let keybindings: IKeybindingRule2[] = []; + for (let extension of extensions) { + this._handleKeybindingsExtensionPointUser(extension.description.isBuiltin, extension.value, extension.collector, keybindings); + } + + KeybindingsRegistry.setExtensionKeybindings(keybindings); + this.updateResolver({ source: KeybindingSource.Default }); + }); + + updateSchema(); + this._register(extensionService.onDidRegisterExtensions(() => updateSchema())); + + this._register(dom.addDisposableListener(window, dom.EventType.KEY_DOWN, (e: KeyboardEvent) => { + let keyEvent = new StandardKeyboardEvent(e); + let shouldPreventDefault = this._dispatch(keyEvent, keyEvent.target); + if (shouldPreventDefault) { + keyEvent.preventDefault(); + } + })); + + keybindingsTelemetry(telemetryService, this); + let data = this.keymapService.getCurrentKeyboardLayout(); + /* __GDPR__ + "keyboardLayout" : { + "currentKeyboardLayout": { "${inline}": [ "${IKeyboardLayoutInfo}" ] } + } + */ + telemetryService.publicLog('keyboardLayout', { + currentKeyboardLayout: data + }); + + this._register(browser.onDidChangeFullscreen(() => { + const keyboard = (navigator).keyboard; + + if (!keyboard) { + return; + } + + if (browser.isFullscreen()) { + keyboard.lock(['Escape']); + } else { + keyboard.unlock(); + } + + // update resolver which will bring back all unbound keyboard shortcuts + this._cachedResolver = null; + this._onDidUpdateKeybindings.fire({ source: KeybindingSource.User }); + })); + } + + public _dumpDebugInfo(): string { + const layoutInfo = JSON.stringify(this.keymapService.getCurrentKeyboardLayout(), null, '\t'); + const mapperInfo = this._keyboardMapper.dumpDebugInfo(); + const rawMapping = JSON.stringify(this.keymapService.getRawKeyboardMapping(), null, '\t'); + return `Layout info:\n${layoutInfo}\n${mapperInfo}\n\nRaw mapping:\n${rawMapping}`; + } + + public _dumpDebugInfoJSON(): string { + const info = { + layout: this.keymapService.getCurrentKeyboardLayout(), + rawMapping: this.keymapService.getRawKeyboardMapping() + }; + return JSON.stringify(info, null, '\t'); + } + + public customKeybindingsCount(): number { + return this.userKeybindings.keybindings.length; + } + + private updateResolver(event: IKeybindingEvent): void { + this._cachedResolver = null; + this._onDidUpdateKeybindings.fire(event); + } + + protected _getResolver(): KeybindingResolver { + if (!this._cachedResolver) { + const defaults = this._resolveKeybindingItems(KeybindingsRegistry.getDefaultKeybindings(), true); + const overrides = this._resolveUserKeybindingItems(this.userKeybindings.keybindings.map((k) => KeybindingIO.readUserKeybindingItem(k)), false); + this._cachedResolver = new KeybindingResolver(defaults, overrides); + } + return this._cachedResolver; + } + + protected _documentHasFocus(): boolean { + // it is possible that the document has lost focus, but the + // window is still focused, e.g. when a element + // has focus + return this.windowService.hasFocus; + } + + private _resolveKeybindingItems(items: IKeybindingItem[], isDefault: boolean): ResolvedKeybindingItem[] { + let result: ResolvedKeybindingItem[] = [], resultLen = 0; + for (const item of items) { + const when = item.when || undefined; + const keybinding = item.keybinding; + if (!keybinding) { + // This might be a removal keybinding item in user settings => accept it + result[resultLen++] = new ResolvedKeybindingItem(undefined, item.command, item.commandArgs, when, isDefault); + } else { + if (this._assertBrowserConflicts(keybinding, item.command)) { + continue; + } + + const resolvedKeybindings = this.resolveKeybinding(keybinding); + for (const resolvedKeybinding of resolvedKeybindings) { + result[resultLen++] = new ResolvedKeybindingItem(resolvedKeybinding, item.command, item.commandArgs, when, isDefault); + } + } + } + + return result; + } + + private _resolveUserKeybindingItems(items: IUserKeybindingItem[], isDefault: boolean): ResolvedKeybindingItem[] { + let result: ResolvedKeybindingItem[] = [], resultLen = 0; + for (const item of items) { + const when = item.when || undefined; + const parts = item.parts; + if (parts.length === 0) { + // This might be a removal keybinding item in user settings => accept it + result[resultLen++] = new ResolvedKeybindingItem(undefined, item.command, item.commandArgs, when, isDefault); + } else { + const resolvedKeybindings = this._keyboardMapper.resolveUserBinding(parts); + for (const resolvedKeybinding of resolvedKeybindings) { + result[resultLen++] = new ResolvedKeybindingItem(resolvedKeybinding, item.command, item.commandArgs, when, isDefault); + } + } + } + + return result; + } + + private _assertBrowserConflicts(kb: Keybinding, commandId: string): boolean { + if (!isWeb) { + return false; + } + + if (browser.isStandalone) { + return false; + } + + if (browser.isFullscreen() && (navigator).keyboard) { + return false; + } + + for (let part of kb.parts) { + if (!part.metaKey && !part.altKey && !part.ctrlKey && !part.shiftKey) { + continue; + } + + const modifiersMask = KeyMod.CtrlCmd | KeyMod.Alt | KeyMod.Shift; + + let partModifiersMask = 0; + if (part.metaKey) { + partModifiersMask |= KeyMod.CtrlCmd; + } + + if (part.shiftKey) { + partModifiersMask |= KeyMod.Shift; + } + + if (part.altKey) { + partModifiersMask |= KeyMod.Alt; + } + + if (part.ctrlKey && OS === OperatingSystem.Macintosh) { + partModifiersMask |= KeyMod.WinCtrl; + } + + if ((partModifiersMask & modifiersMask) === KeyMod.CtrlCmd && part.keyCode === KeyCode.KEY_W) { + // console.warn('Ctrl/Cmd+W keybindings should not be used by default in web. Offender: ', kb.getHashCode(), ' for ', commandId); + + return true; + } + + if ((partModifiersMask & modifiersMask) === KeyMod.CtrlCmd && part.keyCode === KeyCode.KEY_N) { + // console.warn('Ctrl/Cmd+N keybindings should not be used by default in web. Offender: ', kb.getHashCode(), ' for ', commandId); + + return true; + } + + if ((partModifiersMask & modifiersMask) === KeyMod.CtrlCmd && part.keyCode === KeyCode.KEY_T) { + // console.warn('Ctrl/Cmd+T keybindings should not be used by default in web. Offender: ', kb.getHashCode(), ' for ', commandId); + + return true; + } + + if ((partModifiersMask & modifiersMask) === (KeyMod.CtrlCmd | KeyMod.Alt) && (part.keyCode === KeyCode.LeftArrow || part.keyCode === KeyCode.RightArrow)) { + // console.warn('Ctrl/Cmd+Arrow keybindings should not be used by default in web. Offender: ', kb.getHashCode(), ' for ', commandId); + + return true; + } + + if ((partModifiersMask & modifiersMask) === KeyMod.CtrlCmd && part.keyCode >= KeyCode.KEY_0 && part.keyCode <= KeyCode.KEY_9) { + // console.warn('Ctrl/Cmd+Num keybindings should not be used by default in web. Offender: ', kb.getHashCode(), ' for ', commandId); + + return true; + } + } + + return false; + } + + public resolveKeybinding(kb: Keybinding): ResolvedKeybinding[] { + return this._keyboardMapper.resolveKeybinding(kb); + } + + public resolveKeyboardEvent(keyboardEvent: IKeyboardEvent): ResolvedKeybinding { + this.keymapService.validateCurrentKeyboardMapping(keyboardEvent); + return this._keyboardMapper.resolveKeyboardEvent(keyboardEvent); + } + + public resolveUserBinding(userBinding: string): ResolvedKeybinding[] { + const parts = KeybindingParser.parseUserBinding(userBinding); + return this._keyboardMapper.resolveUserBinding(parts); + } + + private _handleKeybindingsExtensionPointUser(isBuiltin: boolean, keybindings: ContributedKeyBinding | ContributedKeyBinding[], collector: ExtensionMessageCollector, result: IKeybindingRule2[]): void { + if (isContributedKeyBindingsArray(keybindings)) { + for (let i = 0, len = keybindings.length; i < len; i++) { + this._handleKeybinding(isBuiltin, i + 1, keybindings[i], collector, result); + } + } else { + this._handleKeybinding(isBuiltin, 1, keybindings, collector, result); + } + } + + private _handleKeybinding(isBuiltin: boolean, idx: number, keybindings: ContributedKeyBinding, collector: ExtensionMessageCollector, result: IKeybindingRule2[]): void { + + let rejects: string[] = []; + + if (isValidContributedKeyBinding(keybindings, rejects)) { + let rule = this._asCommandRule(isBuiltin, idx++, keybindings); + if (rule) { + result.push(rule); + } + } + + if (rejects.length > 0) { + collector.error(nls.localize( + 'invalid.keybindings', + "Invalid `contributes.{0}`: {1}", + keybindingsExtPoint.name, + rejects.join('\n') + )); + } + } + + private _asCommandRule(isBuiltin: boolean, idx: number, binding: ContributedKeyBinding): IKeybindingRule2 | undefined { + + let { command, args, when, key, mac, linux, win } = binding; + + let weight: number; + if (isBuiltin) { + weight = KeybindingWeight.BuiltinExtension + idx; + } else { + weight = KeybindingWeight.ExternalExtension + idx; + } + + let commandAction = MenuRegistry.getCommand(command); + let precondition = commandAction && commandAction.precondition; + let fullWhen: ContextKeyExpr | undefined; + if (when && precondition) { + fullWhen = ContextKeyExpr.and(precondition, ContextKeyExpr.deserialize(when)); + } else if (when) { + fullWhen = ContextKeyExpr.deserialize(when); + } else if (precondition) { + fullWhen = precondition; + } + + let desc: IKeybindingRule2 = { + id: command, + args, + when: fullWhen, + weight: weight, + primary: KeybindingParser.parseKeybinding(key, OS), + mac: mac ? { primary: KeybindingParser.parseKeybinding(mac, OS) } : null, + linux: linux ? { primary: KeybindingParser.parseKeybinding(linux, OS) } : null, + win: win ? { primary: KeybindingParser.parseKeybinding(win, OS) } : null + }; + + if (!desc.primary && !desc.mac && !desc.linux && !desc.win) { + return undefined; + } + + return desc; + } + + public getDefaultKeybindingsContent(): string { + const resolver = this._getResolver(); + const defaultKeybindings = resolver.getDefaultKeybindings(); + const boundCommands = resolver.getDefaultBoundCommands(); + return ( + WorkbenchKeybindingService._getDefaultKeybindings(defaultKeybindings) + + '\n\n' + + WorkbenchKeybindingService._getAllCommandsAsComment(boundCommands) + ); + } + + private static _getDefaultKeybindings(defaultKeybindings: ResolvedKeybindingItem[]): string { + let out = new OutputBuilder(); + out.writeLine('['); + + let lastIndex = defaultKeybindings.length - 1; + defaultKeybindings.forEach((k, index) => { + KeybindingIO.writeKeybindingItem(out, k); + if (index !== lastIndex) { + out.writeLine(','); + } else { + out.writeLine(); + } + }); + out.writeLine(']'); + return out.toString(); + } + + private static _getAllCommandsAsComment(boundCommands: Map): string { + const unboundCommands = KeybindingResolver.getAllUnboundCommands(boundCommands); + let pretty = unboundCommands.sort().join('\n// - '); + return '// ' + nls.localize('unboundCommands', "Here are other available commands: ") + '\n// - ' + pretty; + } + + mightProducePrintableCharacter(event: IKeyboardEvent): boolean { + if (event.ctrlKey || event.metaKey || event.altKey) { + // ignore ctrl/cmd/alt-combination but not shift-combinatios + return false; + } + const code = ScanCodeUtils.toEnum(event.code); + const keycode = IMMUTABLE_CODE_TO_KEY_CODE[code]; + if (keycode !== -1) { + // https://github.com/microsoft/vscode/issues/74934 + return false; + } + // consult the KeyboardMapperFactory to check the given event for + // a printable value. + const mapping = this.keymapService.getRawKeyboardMapping(); + if (!mapping) { + return false; + } + const keyInfo = mapping[event.code]; + if (!keyInfo) { + return false; + } + if (!keyInfo.value || /\s/.test(keyInfo.value)) { + return false; + } + return true; + } +} + +class UserKeybindings extends Disposable { + + private _keybindings: IUserFriendlyKeybinding[] = []; + get keybindings(): IUserFriendlyKeybinding[] { return this._keybindings; } + + private readonly reloadConfigurationScheduler: RunOnceScheduler; + + private readonly _onDidChange: Emitter = this._register(new Emitter()); + readonly onDidChange: Event = this._onDidChange.event; + + constructor( + private readonly keybindingsResource: URI, + private readonly fileService: IFileService + ) { + super(); + + this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this.reload().then(changed => { + if (changed) { + this._onDidChange.fire(); + } + }), 50)); + this._register(Event.filter(this.fileService.onFileChanges, e => e.contains(this.keybindingsResource))(() => this.reloadConfigurationScheduler.schedule())); + } + + async initialize(): Promise { + await this.reload(); + } + + private async reload(): Promise { + const existing = this._keybindings; + try { + const content = await this.fileService.readFile(this.keybindingsResource); + const value = parse(content.value.toString()); + this._keybindings = isArray(value) ? value : []; + } catch (e) { + this._keybindings = []; + } + return existing ? !objects.equals(existing, this._keybindings) : true; + } +} + +let schemaId = 'vscode://schemas/keybindings'; +let commandsSchemas: IJSONSchema[] = []; +let commandsEnum: string[] = []; +let commandsEnumDescriptions: (string | undefined)[] = []; +let schema: IJSONSchema = { + 'id': schemaId, + 'type': 'array', + 'title': nls.localize('keybindings.json.title', "Keybindings configuration"), + 'definitions': { + 'editorGroupsSchema': { + 'type': 'array', + 'items': { + 'type': 'object', + 'properties': { + 'groups': { + '$ref': '#/definitions/editorGroupsSchema', + 'default': [{}, {}] + }, + 'size': { + 'type': 'number', + 'default': 0.5 + } + } + } + } + }, + 'items': { + 'required': ['key'], + 'type': 'object', + 'defaultSnippets': [{ 'body': { 'key': '$1', 'command': '$2', 'when': '$3' } }], + 'properties': { + 'key': { + 'type': 'string', + 'description': nls.localize('keybindings.json.key', "Key or key sequence (separated by space)"), + }, + 'command': { + 'type': 'string', + 'enum': commandsEnum, + 'enumDescriptions': commandsEnumDescriptions, + 'description': nls.localize('keybindings.json.command', "Name of the command to execute"), + }, + 'when': { + 'type': 'string', + 'description': nls.localize('keybindings.json.when', "Condition when the key is active.") + }, + 'args': { + 'description': nls.localize('keybindings.json.args', "Arguments to pass to the command to execute.") + } + }, + 'allOf': commandsSchemas + } +}; + +let schemaRegistry = Registry.as(Extensions.JSONContribution); +schemaRegistry.registerSchema(schemaId, schema); + +function updateSchema() { + commandsSchemas.length = 0; + commandsEnum.length = 0; + commandsEnumDescriptions.length = 0; + + const knownCommands = new Set(); + const addKnownCommand = (commandId: string, description?: string | undefined) => { + if (!/^_/.test(commandId)) { + if (!knownCommands.has(commandId)) { + knownCommands.add(commandId); + + commandsEnum.push(commandId); + commandsEnumDescriptions.push(description); + + // Also add the negative form for keybinding removal + commandsEnum.push(`-${commandId}`); + commandsEnumDescriptions.push(description); + } + } + }; + + const allCommands = CommandsRegistry.getCommands(); + for (const [commandId, command] of allCommands) { + const commandDescription = command.description; + + addKnownCommand(commandId, commandDescription ? commandDescription.description : undefined); + + if (!commandDescription || !commandDescription.args || commandDescription.args.length !== 1 || !commandDescription.args[0].schema) { + continue; + } + + const argsSchema = commandDescription.args[0].schema; + const argsRequired = Array.isArray(argsSchema.required) && argsSchema.required.length > 0; + const addition = { + 'if': { + 'properties': { + 'command': { 'const': commandId } + } + }, + 'then': { + 'required': ([]).concat(argsRequired ? ['args'] : []), + 'properties': { + 'args': argsSchema + } + } + }; + + commandsSchemas.push(addition); + } + + const menuCommands = MenuRegistry.getCommands(); + for (const commandId of menuCommands.keys()) { + addKnownCommand(commandId); + } +} + +const configurationRegistry = Registry.as(ConfigExtensions.Configuration); +const keyboardConfiguration: IConfigurationNode = { + 'id': 'keyboard', + 'order': 15, + 'type': 'object', + 'title': nls.localize('keyboardConfigurationTitle', "Keyboard"), + 'overridable': true, + 'properties': { + 'keyboard.dispatch': { + 'type': 'string', + 'enum': ['code', 'keyCode'], + 'default': 'code', + 'markdownDescription': nls.localize('dispatch', "Controls the dispatching logic for key presses to use either `code` (recommended) or `keyCode`."), + 'included': OS === OperatingSystem.Macintosh || OS === OperatingSystem.Linux + } + // no touch bar support + } +}; + +configurationRegistry.registerConfiguration(keyboardConfiguration); + +registerSingleton(IKeybindingService, WorkbenchKeybindingService); diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution.ts new file mode 100644 index 000000000..89ef89204 --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution.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. + *--------------------------------------------------------------------------------------------*/ + +import { IKeymapInfo } from 'vs/workbench/services/keybinding/common/keymapInfo'; + +export class KeyboardLayoutContribution { + public static readonly INSTANCE: KeyboardLayoutContribution = new KeyboardLayoutContribution(); + + private _layoutInfos: IKeymapInfo[] = []; + + get layoutInfos() { + return this._layoutInfos; + } + + private constructor() { + } + + registerKeyboardLayout(layout: IKeymapInfo) { + this._layoutInfos.push(layout); + } +} \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/cz.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/cz.win.ts new file mode 100644 index 000000000..c187c923c --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/cz.win.ts @@ -0,0 +1,168 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { name: '00000405', id: '', text: 'Czech' }, + secondaryLayouts: [], + mapping: { + Sleep: [], + WakeUp: [], + KeyA: ['a', 'A', '', '', 0, 'VK_A'], + KeyB: ['b', 'B', '{', '', 0, 'VK_B'], + KeyC: ['c', 'C', '&', '', 0, 'VK_C'], + KeyD: ['d', 'D', 'Đ', '', 0, 'VK_D'], + KeyE: ['e', 'E', '€', '', 0, 'VK_E'], + KeyF: ['f', 'F', '[', '', 0, 'VK_F'], + KeyG: ['g', 'G', ']', '', 0, 'VK_G'], + KeyH: ['h', 'H', '', '', 0, 'VK_H'], + KeyI: ['i', 'I', '', '', 0, 'VK_I'], + KeyJ: ['j', 'J', '', '', 0, 'VK_J'], + KeyK: ['k', 'K', 'ł', '', 0, 'VK_K'], + KeyL: ['l', 'L', 'Ł', '', 0, 'VK_L'], + KeyM: ['m', 'M', '', '', 0, 'VK_M'], + KeyN: ['n', 'N', '}', '', 0, 'VK_N'], + KeyO: ['o', 'O', '', '', 0, 'VK_O'], + KeyP: ['p', 'P', '', '', 0, 'VK_P'], + KeyQ: ['q', 'Q', '\\', '', 0, 'VK_Q'], + KeyR: ['r', 'R', '', '', 0, 'VK_R'], + KeyS: ['s', 'S', 'đ', '', 0, 'VK_S'], + KeyT: ['t', 'T', '', '', 0, 'VK_T'], + KeyU: ['u', 'U', '', '', 0, 'VK_U'], + KeyV: ['v', 'V', '@', '', 0, 'VK_V'], + KeyW: ['w', 'W', '|', '', 0, 'VK_W'], + KeyX: ['x', 'X', '#', '', 0, 'VK_X'], + KeyY: ['z', 'Z', '', '', 0, 'VK_Z'], + KeyZ: ['y', 'Y', '', '', 0, 'VK_Y'], + Digit1: ['+', '1', '~', '', 0, 'VK_1'], + Digit2: ['ě', '2', 'ˇ', '', 0, 'VK_2'], + Digit3: ['š', '3', '^', '', 0, 'VK_3'], + Digit4: ['č', '4', '˘', '', 0, 'VK_4'], + Digit5: ['ř', '5', '°', '', 0, 'VK_5'], + Digit6: ['ž', '6', '˛', '', 0, 'VK_6'], + Digit7: ['ý', '7', '`', '', 0, 'VK_7'], + Digit8: ['á', '8', '˙', '', 0, 'VK_8'], + Digit9: ['í', '9', '´', '', 0, 'VK_9'], + Digit0: ['é', '0', '˝', '', 0, 'VK_0'], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', '', '', 0, 'VK_SPACE'], + Minus: ['=', '%', '¨', '', 0, 'VK_OEM_PLUS'], + Equal: ['´', 'ˇ', '¸', '', 0, 'VK_OEM_2'], + BracketLeft: ['ú', '/', '÷', '', 0, 'VK_OEM_4'], + BracketRight: [')', '(', '×', '', 0, 'VK_OEM_6'], + Backslash: ['¨', '\'', '¤', '', 0, 'VK_OEM_5'], + Semicolon: ['ů', '"', '$', '', 0, 'VK_OEM_1'], + Quote: ['§', '!', 'ß', '', 0, 'VK_OEM_7'], + Backquote: [';', '°', '', '', 0, 'VK_OEM_3'], + Comma: [',', '?', '<', '', 0, 'VK_OEM_COMMA'], + Period: ['.', ':', '>', '', 0, 'VK_OEM_PERIOD'], + Slash: ['-', '_', '*', '', 0, 'VK_OEM_MINUS'], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + PrintScreen: [], + ScrollLock: [], + Pause: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '', '', 0, 'VK_DIVIDE'], + NumpadMultiply: ['*', '*', '', '', 0, 'VK_MULTIPLY'], + NumpadSubtract: ['-', '-', '', '', 0, 'VK_SUBTRACT'], + NumpadAdd: ['+', '+', '', '', 0, 'VK_ADD'], + NumpadEnter: [], + Numpad1: [], + Numpad2: [], + Numpad3: [], + Numpad4: [], + Numpad5: [], + Numpad6: [], + Numpad7: [], + Numpad8: [], + Numpad9: [], + Numpad0: [], + NumpadDecimal: [], + IntlBackslash: ['\\', '|', '', '', 0, 'VK_OEM_102'], + ContextMenu: [], + Power: [], + NumpadEqual: [], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + F21: [], + F22: [], + F23: [], + F24: [], + Help: [], + Undo: [], + Cut: [], + Copy: [], + Paste: [], + AudioVolumeMute: [], + AudioVolumeUp: [], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + Convert: [], + NonConvert: [], + Lang1: [], + Lang2: [], + Lang3: [], + Lang4: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [], + MediaTrackNext: [], + MediaTrackPrevious: [], + MediaStop: [], + Eject: [], + MediaPlayPause: [], + MediaSelect: [], + LaunchMail: [], + LaunchApp2: [], + LaunchApp1: [], + BrowserSearch: [], + BrowserHome: [], + BrowserBack: [], + BrowserForward: [], + BrowserStop: [], + BrowserRefresh: [], + BrowserFavorites: [] + } +}); diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/de-swiss.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/de-swiss.win.ts new file mode 100644 index 000000000..b19d2935e --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/de-swiss.win.ts @@ -0,0 +1,169 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { name: '00000807', id: '', text: 'Swiss German' }, + secondaryLayouts: [], + mapping: { + Sleep: [], + WakeUp: [], + KeyA: ['a', 'A', '', '', 0, 'VK_A'], + KeyB: ['b', 'B', '', '', 0, 'VK_B'], + KeyC: ['c', 'C', '', '', 0, 'VK_C'], + KeyD: ['d', 'D', '', '', 0, 'VK_D'], + KeyE: ['e', 'E', '€', '', 0, 'VK_E'], + KeyF: ['f', 'F', '', '', 0, 'VK_F'], + KeyG: ['g', 'G', '', '', 0, 'VK_G'], + KeyH: ['h', 'H', '', '', 0, 'VK_H'], + KeyI: ['i', 'I', '', '', 0, 'VK_I'], + KeyJ: ['j', 'J', '', '', 0, 'VK_J'], + KeyK: ['k', 'K', '', '', 0, 'VK_K'], + KeyL: ['l', 'L', '', '', 0, 'VK_L'], + KeyM: ['m', 'M', '', '', 0, 'VK_M'], + KeyN: ['n', 'N', '', '', 0, 'VK_N'], + KeyO: ['o', 'O', '', '', 0, 'VK_O'], + KeyP: ['p', 'P', '', '', 0, 'VK_P'], + KeyQ: ['q', 'Q', '', '', 0, 'VK_Q'], + KeyR: ['r', 'R', '', '', 0, 'VK_R'], + KeyS: ['s', 'S', '', '', 0, 'VK_S'], + KeyT: ['t', 'T', '', '', 0, 'VK_T'], + KeyU: ['u', 'U', '', '', 0, 'VK_U'], + KeyV: ['v', 'V', '', '', 0, 'VK_V'], + KeyW: ['w', 'W', '', '', 0, 'VK_W'], + KeyX: ['x', 'X', '', '', 0, 'VK_X'], + KeyY: ['z', 'Z', '', '', 0, 'VK_Z'], + KeyZ: ['y', 'Y', '', '', 0, 'VK_Y'], + Digit1: ['1', '+', '¦', '', 0, 'VK_1'], + Digit2: ['2', '"', '@', '', 0, 'VK_2'], + Digit3: ['3', '*', '#', '', 0, 'VK_3'], + Digit4: ['4', 'ç', '°', '', 0, 'VK_4'], + Digit5: ['5', '%', '§', '', 0, 'VK_5'], + Digit6: ['6', '&', '¬', '', 0, 'VK_6'], + Digit7: ['7', '/', '|', '', 0, 'VK_7'], + Digit8: ['8', '(', '¢', '', 0, 'VK_8'], + Digit9: ['9', ')', '', '', 0, 'VK_9'], + Digit0: ['0', '=', '', '', 0, 'VK_0'], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', '', '', 0, 'VK_SPACE'], + Minus: ['\'', '?', '´', '', 0, 'VK_OEM_4'], + Equal: ['^', '`', '~', '', 0, 'VK_OEM_6'], + BracketLeft: ['ü', 'è', '[', '', 0, 'VK_OEM_1'], + BracketRight: ['¨', '!', ']', '', 0, 'VK_OEM_3'], + Backslash: ['$', '£', '}', '', 0, 'VK_OEM_8'], + Semicolon: ['ö', 'é', '', '', 0, 'VK_OEM_7'], + Quote: ['ä', 'à', '{', '', 0, 'VK_OEM_5'], + Backquote: ['§', '°', '', '', 0, 'VK_OEM_2'], + Comma: [',', ';', '', '', 0, 'VK_OEM_COMMA'], + Period: ['.', ':', '', '', 0, 'VK_OEM_PERIOD'], + Slash: ['-', '_', '', '', 0, 'VK_OEM_MINUS'], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + PrintScreen: [], + ScrollLock: [], + Pause: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '', '', 0, 'VK_DIVIDE'], + NumpadMultiply: ['*', '*', '', '', 0, 'VK_MULTIPLY'], + NumpadSubtract: ['-', '-', '', '', 0, 'VK_SUBTRACT'], + NumpadAdd: ['+', '+', '', '', 0, 'VK_ADD'], + NumpadEnter: [], + Numpad1: [], + Numpad2: [], + Numpad3: [], + Numpad4: [], + Numpad5: [], + Numpad6: [], + Numpad7: [], + Numpad8: [], + Numpad9: [], + Numpad0: [], + NumpadDecimal: [], + IntlBackslash: ['<', '>', '\\', '', 0, 'VK_OEM_102'], + ContextMenu: [], + Power: [], + NumpadEqual: [], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + F21: [], + F22: [], + F23: [], + F24: [], + Help: [], + Undo: [], + Cut: [], + Copy: [], + Paste: [], + AudioVolumeMute: [], + AudioVolumeUp: [], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + Convert: [], + NonConvert: [], + Lang1: [], + Lang2: [], + Lang3: [], + Lang4: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [], + MediaTrackNext: [], + MediaTrackPrevious: [], + MediaStop: [], + Eject: [], + MediaPlayPause: [], + MediaSelect: [], + LaunchMail: [], + LaunchApp2: [], + LaunchApp1: [], + BrowserSearch: [], + BrowserHome: [], + BrowserBack: [], + BrowserForward: [], + BrowserStop: [], + BrowserRefresh: [], + BrowserFavorites: [] + } +}); diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/de.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/de.darwin.ts new file mode 100644 index 000000000..33d2f5d5e --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/de.darwin.ts @@ -0,0 +1,132 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { id: 'com.apple.keylayout.German', lang: 'de', localizedName: 'German' }, + secondaryLayouts: [], + mapping: { + KeyA: ['a', 'A', 'å', 'Å', 0], + KeyB: ['b', 'B', '∫', '‹', 0], + KeyC: ['c', 'C', 'ç', 'Ç', 0], + KeyD: ['d', 'D', '∂', '™', 0], + KeyE: ['e', 'E', '€', '‰', 0], + KeyF: ['f', 'F', 'ƒ', 'Ï', 0], + KeyG: ['g', 'G', '©', 'Ì', 0], + KeyH: ['h', 'H', 'ª', 'Ó', 0], + KeyI: ['i', 'I', '⁄', 'Û', 0], + KeyJ: ['j', 'J', 'º', 'ı', 0], + KeyK: ['k', 'K', '∆', 'ˆ', 0], + KeyL: ['l', 'L', '@', 'fl', 0], + KeyM: ['m', 'M', 'µ', '˘', 0], + KeyN: ['n', 'N', '~', '›', 4], + KeyO: ['o', 'O', 'ø', 'Ø', 0], + KeyP: ['p', 'P', 'π', '∏', 0], + KeyQ: ['q', 'Q', '«', '»', 0], + KeyR: ['r', 'R', '®', '¸', 0], + KeyS: ['s', 'S', '‚', 'Í', 0], + KeyT: ['t', 'T', '†', '˝', 0], + KeyU: ['u', 'U', '¨', 'Á', 4], + KeyV: ['v', 'V', '√', '◊', 0], + KeyW: ['w', 'W', '∑', '„', 0], + KeyX: ['x', 'X', '≈', 'Ù', 0], + KeyY: ['z', 'Z', 'Ω', 'ˇ', 0], + KeyZ: ['y', 'Y', '¥', '‡', 0], + Digit1: ['1', '!', '¡', '¬', 0], + Digit2: ['2', '"', '“', '”', 0], + Digit3: ['3', '§', '¶', '#', 0], + Digit4: ['4', '$', '¢', '£', 0], + Digit5: ['5', '%', '[', 'fi', 0], + Digit6: ['6', '&', ']', '^', 8], + Digit7: ['7', '/', '|', '\\', 0], + Digit8: ['8', '(', '{', '˜', 0], + Digit9: ['9', ')', '}', '·', 0], + Digit0: ['0', '=', '≠', '¯', 0], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', ' ', ' ', 0], + Minus: ['ß', '?', '¿', '˙', 0], + Equal: ['´', '`', '\'', '˚', 3], + BracketLeft: ['ü', 'Ü', '•', '°', 0], + BracketRight: ['+', '*', '±', '', 0], + Backslash: ['#', '\'', '‘', '’', 0], + Semicolon: ['ö', 'Ö', 'œ', 'Œ', 0], + Quote: ['ä', 'Ä', 'æ', 'Æ', 0], + Backquote: ['<', '>', '≤', '≥', 0], + Comma: [',', ';', '∞', '˛', 0], + Period: ['.', ':', '…', '÷', 0], + Slash: ['-', '_', '–', '—', 0], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '/', '/', 0], + NumpadMultiply: ['*', '*', '*', '*', 0], + NumpadSubtract: ['-', '-', '-', '-', 0], + NumpadAdd: ['+', '+', '+', '+', 0], + NumpadEnter: [], + Numpad1: ['1', '1', '1', '1', 0], + Numpad2: ['2', '2', '2', '2', 0], + Numpad3: ['3', '3', '3', '3', 0], + Numpad4: ['4', '4', '4', '4', 0], + Numpad5: ['5', '5', '5', '5', 0], + Numpad6: ['6', '6', '6', '6', 0], + Numpad7: ['7', '7', '7', '7', 0], + Numpad8: ['8', '8', '8', '8', 0], + Numpad9: ['9', '9', '9', '9', 0], + Numpad0: ['0', '0', '0', '0', 0], + NumpadDecimal: [',', ',', '.', '.', 0], + IntlBackslash: ['^', '°', '„', '“', 1], + ContextMenu: [], + NumpadEqual: ['=', '=', '=', '=', 0], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + AudioVolumeMute: [], + AudioVolumeUp: ['', '=', '', '=', 0], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [] + } +}); diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/de.linux.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/de.linux.ts new file mode 100644 index 000000000..b4675240e --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/de.linux.ts @@ -0,0 +1,187 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { model: 'pc104', layout: 'de', variant: '', options: '', rules: 'base' }, + secondaryLayouts: [], + mapping: { + Sleep: [], + WakeUp: [], + KeyA: ['a', 'A', 'æ', 'Æ', 0], + KeyB: ['b', 'B', '“', '‘', 0], + KeyC: ['c', 'C', '¢', '©', 0], + KeyD: ['d', 'D', 'ð', 'Ð', 0], + KeyE: ['e', 'E', '€', '€', 0], + KeyF: ['f', 'F', 'đ', 'ª', 0], + KeyG: ['g', 'G', 'ŋ', 'Ŋ', 0], + KeyH: ['h', 'H', 'ħ', 'Ħ', 0], + KeyI: ['i', 'I', '→', 'ı', 0], + KeyJ: ['j', 'J', '̣', '̇', 0], + KeyK: ['k', 'K', 'ĸ', '&', 0], + KeyL: ['l', 'L', 'ł', 'Ł', 0], + KeyM: ['m', 'M', 'µ', 'º', 0], + KeyN: ['n', 'N', '”', '’', 0], + KeyO: ['o', 'O', 'ø', 'Ø', 0], + KeyP: ['p', 'P', 'þ', 'Þ', 0], + KeyQ: ['q', 'Q', '@', 'Ω', 0], + KeyR: ['r', 'R', '¶', '®', 0], + KeyS: ['s', 'S', 'ſ', 'ẞ', 0], + KeyT: ['t', 'T', 'ŧ', 'Ŧ', 0], + KeyU: ['u', 'U', '↓', '↑', 0], + KeyV: ['v', 'V', '„', '‚', 0], + KeyW: ['w', 'W', 'ł', 'Ł', 0], + KeyX: ['x', 'X', '«', '‹', 0], + KeyY: ['z', 'Z', '←', '¥', 0], + KeyZ: ['y', 'Y', '»', '›', 0], + Digit1: ['1', '!', '¹', '¡', 0], + Digit2: ['2', '"', '²', '⅛', 0], + Digit3: ['3', '§', '³', '£', 0], + Digit4: ['4', '$', '¼', '¤', 0], + Digit5: ['5', '%', '½', '⅜', 0], + Digit6: ['6', '&', '¬', '⅝', 0], + Digit7: ['7', '/', '{', '⅞', 0], + Digit8: ['8', '(', '[', '™', 0], + Digit9: ['9', ')', ']', '±', 0], + Digit0: ['0', '=', '}', '°', 0], + Enter: ['\r', '\r', '\r', '\r', 0], + Escape: ['\u001b', '\u001b', '\u001b', '\u001b', 0], + Backspace: ['\b', '\b', '\b', '\b', 0], + Tab: ['\t', '', '\t', '', 0], + Space: [' ', ' ', ' ', ' ', 0], + Minus: ['ß', '?', '\\', '¿', 0], + Equal: ['́', '̀', '̧', '̨', 0], + BracketLeft: ['ü', 'Ü', '̈', '̊', 0], + BracketRight: ['+', '*', '~', '¯', 0], + Backslash: ['#', '\'', '’', '̆', 0], + Semicolon: ['ö', 'Ö', '̋', '̣', 0], + Quote: ['ä', 'Ä', '̂', '̌', 0], + Backquote: ['̂', '°', '′', '″', 0], + Comma: [',', ';', '·', '×', 0], + Period: ['.', ':', '…', '÷', 0], + Slash: ['-', '_', '–', '—', 0], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + PrintScreen: ['', '', '', '', 0], + ScrollLock: [], + Pause: [], + Insert: [], + Home: [], + PageUp: ['/', '/', '/', '/', 0], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: [], + NumpadMultiply: ['*', '*', '*', '*', 0], + NumpadSubtract: ['-', '-', '-', '-', 0], + NumpadAdd: ['+', '+', '+', '+', 0], + NumpadEnter: [], + Numpad1: ['', '1', '', '1', 0], + Numpad2: ['', '2', '', '2', 0], + Numpad3: ['', '3', '', '3', 0], + Numpad4: ['', '4', '', '4', 0], + Numpad5: ['', '5', '', '5', 0], + Numpad6: ['', '6', '', '6', 0], + Numpad7: ['', '7', '', '7', 0], + Numpad8: ['', '8', '', '8', 0], + Numpad9: ['', '9', '', '9', 0], + Numpad0: ['', '0', '', '0', 0], + NumpadDecimal: ['', ',', '', ',', 0], + IntlBackslash: ['<', '>', '|', '̱', 0], + ContextMenu: [], + Power: [], + NumpadEqual: [], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + F21: [], + F22: [], + F23: [], + F24: [], + Open: [], + Help: [], + Select: [], + Again: [], + Undo: [], + Cut: [], + Copy: [], + Paste: [], + Find: [], + AudioVolumeMute: [], + AudioVolumeUp: [], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + Convert: [], + NonConvert: [], + Lang1: [], + Lang2: [], + Lang3: [], + Lang4: [], + Lang5: [], + NumpadParenLeft: [], + NumpadParenRight: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: ['\r', '\r', '\r', '\r', 0], + MetaRight: ['.', '.', '.', '.', 0], + BrightnessUp: [], + BrightnessDown: [], + MediaPlay: [], + MediaRecord: [], + MediaFastForward: [], + MediaRewind: [], + MediaTrackNext: [], + MediaTrackPrevious: [], + MediaStop: [], + Eject: [], + MediaPlayPause: [], + MediaSelect: [], + LaunchMail: [], + LaunchApp2: [], + LaunchApp1: [], + SelectTask: [], + LaunchScreenSaver: [], + BrowserSearch: [], + BrowserHome: [], + BrowserBack: [], + BrowserForward: [], + BrowserStop: [], + BrowserRefresh: [], + BrowserFavorites: [], + MailReply: [], + MailForward: [], + MailSend: [] + } +}); \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/de.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/de.win.ts new file mode 100644 index 000000000..46bf5981a --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/de.win.ts @@ -0,0 +1,169 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { name: '00000407', id: '', text: 'German' }, + secondaryLayouts: [], + mapping: { + Sleep: [], + WakeUp: [], + KeyA: ['a', 'A', '', '', 0, 'VK_A'], + KeyB: ['b', 'B', '', '', 0, 'VK_B'], + KeyC: ['c', 'C', '', '', 0, 'VK_C'], + KeyD: ['d', 'D', '', '', 0, 'VK_D'], + KeyE: ['e', 'E', '€', '', 0, 'VK_E'], + KeyF: ['f', 'F', '', '', 0, 'VK_F'], + KeyG: ['g', 'G', '', '', 0, 'VK_G'], + KeyH: ['h', 'H', '', '', 0, 'VK_H'], + KeyI: ['i', 'I', '', '', 0, 'VK_I'], + KeyJ: ['j', 'J', '', '', 0, 'VK_J'], + KeyK: ['k', 'K', '', '', 0, 'VK_K'], + KeyL: ['l', 'L', '', '', 0, 'VK_L'], + KeyM: ['m', 'M', 'µ', '', 0, 'VK_M'], + KeyN: ['n', 'N', '', '', 0, 'VK_N'], + KeyO: ['o', 'O', '', '', 0, 'VK_O'], + KeyP: ['p', 'P', '', '', 0, 'VK_P'], + KeyQ: ['q', 'Q', '@', '', 0, 'VK_Q'], + KeyR: ['r', 'R', '', '', 0, 'VK_R'], + KeyS: ['s', 'S', '', '', 0, 'VK_S'], + KeyT: ['t', 'T', '', '', 0, 'VK_T'], + KeyU: ['u', 'U', '', '', 0, 'VK_U'], + KeyV: ['v', 'V', '', '', 0, 'VK_V'], + KeyW: ['w', 'W', '', '', 0, 'VK_W'], + KeyX: ['x', 'X', '', '', 0, 'VK_X'], + KeyY: ['z', 'Z', '', '', 0, 'VK_Z'], + KeyZ: ['y', 'Y', '', '', 0, 'VK_Y'], + Digit1: ['1', '!', '', '', 0, 'VK_1'], + Digit2: ['2', '"', '²', '', 0, 'VK_2'], + Digit3: ['3', '§', '³', '', 0, 'VK_3'], + Digit4: ['4', '$', '', '', 0, 'VK_4'], + Digit5: ['5', '%', '', '', 0, 'VK_5'], + Digit6: ['6', '&', '', '', 0, 'VK_6'], + Digit7: ['7', '/', '{', '', 0, 'VK_7'], + Digit8: ['8', '(', '[', '', 0, 'VK_8'], + Digit9: ['9', ')', ']', '', 0, 'VK_9'], + Digit0: ['0', '=', '}', '', 0, 'VK_0'], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', '', '', 0, 'VK_SPACE'], + Minus: ['ß', '?', '\\', 'ẞ', 0, 'VK_OEM_4'], + Equal: ['´', '`', '', '', 0, 'VK_OEM_6'], + BracketLeft: ['ü', 'Ü', '', '', 0, 'VK_OEM_1'], + BracketRight: ['+', '*', '~', '', 0, 'VK_OEM_PLUS'], + Backslash: ['#', '\'', '', '', 0, 'VK_OEM_2'], + Semicolon: ['ö', 'Ö', '', '', 0, 'VK_OEM_3'], + Quote: ['ä', 'Ä', '', '', 0, 'VK_OEM_7'], + Backquote: ['^', '°', '', '', 0, 'VK_OEM_5'], + Comma: [',', ';', '', '', 0, 'VK_OEM_COMMA'], + Period: ['.', ':', '', '', 0, 'VK_OEM_PERIOD'], + Slash: ['-', '_', '', '', 0, 'VK_OEM_MINUS'], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + PrintScreen: [], + ScrollLock: [], + Pause: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '', '', 0, 'VK_DIVIDE'], + NumpadMultiply: ['*', '*', '', '', 0, 'VK_MULTIPLY'], + NumpadSubtract: ['-', '-', '', '', 0, 'VK_SUBTRACT'], + NumpadAdd: ['+', '+', '', '', 0, 'VK_ADD'], + NumpadEnter: [], + Numpad1: [], + Numpad2: [], + Numpad3: [], + Numpad4: [], + Numpad5: [], + Numpad6: [], + Numpad7: [], + Numpad8: [], + Numpad9: [], + Numpad0: [], + NumpadDecimal: [], + IntlBackslash: ['<', '>', '|', '', 0, 'VK_OEM_102'], + ContextMenu: [], + Power: [], + NumpadEqual: [], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + F21: [], + F22: [], + F23: [], + F24: [], + Help: [], + Undo: [], + Cut: [], + Copy: [], + Paste: [], + AudioVolumeMute: [], + AudioVolumeUp: [], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + Convert: [], + NonConvert: [], + Lang1: [], + Lang2: [], + Lang3: [], + Lang4: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [], + MediaTrackNext: [], + MediaTrackPrevious: [], + MediaStop: [], + Eject: [], + MediaPlayPause: [], + MediaSelect: [], + LaunchMail: [], + LaunchApp2: [], + LaunchApp1: [], + BrowserSearch: [], + BrowserHome: [], + BrowserBack: [], + BrowserForward: [], + BrowserStop: [], + BrowserRefresh: [], + BrowserFavorites: [] + } +}); \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/dk.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/dk.win.ts new file mode 100644 index 000000000..b77462269 --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/dk.win.ts @@ -0,0 +1,170 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { name: '00000406', id: '', text: 'Danish' }, + secondaryLayouts: [], + mapping: { + Sleep: [], + WakeUp: [], + KeyA: ['a', 'A', '', '', 0, 'VK_A'], + KeyB: ['b', 'B', '', '', 0, 'VK_B'], + KeyC: ['c', 'C', '', '', 0, 'VK_C'], + KeyD: ['d', 'D', '', '', 0, 'VK_D'], + KeyE: ['e', 'E', '€', '', 0, 'VK_E'], + KeyF: ['f', 'F', '', '', 0, 'VK_F'], + KeyG: ['g', 'G', '', '', 0, 'VK_G'], + KeyH: ['h', 'H', '', '', 0, 'VK_H'], + KeyI: ['i', 'I', '', '', 0, 'VK_I'], + KeyJ: ['j', 'J', '', '', 0, 'VK_J'], + KeyK: ['k', 'K', '', '', 0, 'VK_K'], + KeyL: ['l', 'L', '', '', 0, 'VK_L'], + KeyM: ['m', 'M', 'µ', '', 0, 'VK_M'], + KeyN: ['n', 'N', '', '', 0, 'VK_N'], + KeyO: ['o', 'O', '', '', 0, 'VK_O'], + KeyP: ['p', 'P', '', '', 0, 'VK_P'], + KeyQ: ['q', 'Q', '', '', 0, 'VK_Q'], + KeyR: ['r', 'R', '', '', 0, 'VK_R'], + KeyS: ['s', 'S', '', '', 0, 'VK_S'], + KeyT: ['t', 'T', '', '', 0, 'VK_T'], + KeyU: ['u', 'U', '', '', 0, 'VK_U'], + KeyV: ['v', 'V', '', '', 0, 'VK_V'], + KeyW: ['w', 'W', '', '', 0, 'VK_W'], + KeyX: ['x', 'X', '', '', 0, 'VK_X'], + KeyY: ['y', 'Y', '', '', 0, 'VK_Y'], + KeyZ: ['z', 'Z', '', '', 0, 'VK_Z'], + Digit1: ['1', '!', '', '', 0, 'VK_1'], + Digit2: ['2', '"', '@', '', 0, 'VK_2'], + Digit3: ['3', '#', '£', '', 0, 'VK_3'], + Digit4: ['4', '¤', '$', '', 0, 'VK_4'], + Digit5: ['5', '%', '€', '', 0, 'VK_5'], + Digit6: ['6', '&', '', '', 0, 'VK_6'], + Digit7: ['7', '/', '{', '', 0, 'VK_7'], + Digit8: ['8', '(', '[', '', 0, 'VK_8'], + Digit9: ['9', ')', ']', '', 0, 'VK_9'], + Digit0: ['0', '=', '}', '', 0, 'VK_0'], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', '', '', 0, 'VK_SPACE'], + Minus: ['+', '?', '', '', 0, 'VK_OEM_PLUS'], + Equal: ['´', '`', '|', '', 0, 'VK_OEM_4'], + BracketLeft: ['å', 'Å', '', '', 0, 'VK_OEM_6'], + BracketRight: ['¨', '^', '~', '', 0, 'VK_OEM_1'], + Backslash: ['\'', '*', '', '', 0, 'VK_OEM_2'], + Semicolon: ['æ', 'Æ', '', '', 0, 'VK_OEM_3'], + Quote: ['ø', 'Ø', '', '', 0, 'VK_OEM_7'], + Backquote: ['½', '§', '', '', 0, 'VK_OEM_5'], + Comma: [',', ';', '', '', 0, 'VK_OEM_COMMA'], + Period: ['.', ':', '', '', 0, 'VK_OEM_PERIOD'], + Slash: ['-', '_', '', '', 0, 'VK_OEM_MINUS'], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + PrintScreen: [], + ScrollLock: [], + Pause: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '', '', 0, 'VK_DIVIDE'], + NumpadMultiply: ['*', '*', '', '', 0, 'VK_MULTIPLY'], + NumpadSubtract: ['-', '-', '', '', 0, 'VK_SUBTRACT'], + NumpadAdd: ['+', '+', '', '', 0, 'VK_ADD'], + NumpadEnter: [], + Numpad1: [], + Numpad2: [], + Numpad3: [], + Numpad4: [], + Numpad5: [], + Numpad6: [], + Numpad7: [], + Numpad8: [], + Numpad9: [], + Numpad0: [], + NumpadDecimal: [], + IntlBackslash: ['<', '>', '\\', '', 0, 'VK_OEM_102'], + ContextMenu: [], + Power: [], + NumpadEqual: [], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + F21: [], + F22: [], + F23: [], + F24: [], + Help: [], + Undo: [], + Cut: [], + Copy: [], + Paste: [], + AudioVolumeMute: [], + AudioVolumeUp: [], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + Convert: [], + NonConvert: [], + Lang1: [], + Lang2: [], + Lang3: [], + Lang4: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [], + MediaTrackNext: [], + MediaTrackPrevious: [], + MediaStop: [], + Eject: [], + MediaPlayPause: [], + MediaSelect: [], + LaunchMail: [], + LaunchApp2: [], + LaunchApp1: [], + BrowserSearch: [], + BrowserHome: [], + BrowserBack: [], + BrowserForward: [], + BrowserStop: [], + BrowserRefresh: [], + BrowserFavorites: [] + } + +}); \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/dvorak.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/dvorak.darwin.ts new file mode 100644 index 000000000..a29ecf334 --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/dvorak.darwin.ts @@ -0,0 +1,131 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { id: 'com.apple.keylayout.Dvorak', localizedName: 'Dvorak', lang: 'en' }, + secondaryLayouts: [], + mapping: { + KeyA: ['a', 'A', 'å', 'Å', 0], + KeyB: ['x', 'X', '≈', '˛', 0], + KeyC: ['j', 'J', '∆', 'Ô', 0], + KeyD: ['e', 'E', '´', '´', 4], + KeyE: ['.', '>', '≥', '˘', 0], + KeyF: ['u', 'U', '¨', '¨', 4], + KeyG: ['i', 'I', 'ˆ', 'ˆ', 4], + KeyH: ['d', 'D', '∂', 'Î', 0], + KeyI: ['c', 'C', 'ç', 'Ç', 0], + KeyJ: ['h', 'H', '˙', 'Ó', 0], + KeyK: ['t', 'T', '†', 'ˇ', 0], + KeyL: ['n', 'N', '˜', '˜', 4], + KeyM: ['m', 'M', 'µ', 'Â', 0], + KeyN: ['b', 'B', '∫', 'ı', 0], + KeyO: ['r', 'R', '®', '‰', 0], + KeyP: ['l', 'L', '¬', 'Ò', 0], + KeyQ: ['\'', '"', 'æ', 'Æ', 0], + KeyR: ['p', 'P', 'π', '∏', 0], + KeyS: ['o', 'O', 'ø', 'Ø', 0], + KeyT: ['y', 'Y', '¥', 'Á', 0], + KeyU: ['g', 'G', '©', '˝', 0], + KeyV: ['k', 'K', '˚', '', 0], + KeyW: [',', '<', '≤', '¯', 0], + KeyX: ['q', 'Q', 'œ', 'Œ', 0], + KeyY: ['f', 'F', 'ƒ', 'Ï', 0], + KeyZ: [';', ':', '…', 'Ú', 0], + Digit1: ['1', '!', '¡', '⁄', 0], + Digit2: ['2', '@', '™', '€', 0], + Digit3: ['3', '#', '£', '‹', 0], + Digit4: ['4', '$', '¢', '›', 0], + Digit5: ['5', '%', '∞', 'fi', 0], + Digit6: ['6', '^', '§', 'fl', 0], + Digit7: ['7', '&', '¶', '‡', 0], + Digit8: ['8', '*', '•', '°', 0], + Digit9: ['9', '(', 'ª', '·', 0], + Digit0: ['0', ')', 'º', '‚', 0], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', ' ', ' ', 0], + Minus: ['[', '{', '“', '”', 0], + Equal: [']', '}', '‘', '’', 0], + BracketLeft: ['/', '?', '÷', '¿', 0], + BracketRight: ['=', '+', '≠', '±', 0], + Backslash: ['\\', '|', '«', '»', 0], + Semicolon: ['s', 'S', 'ß', 'Í', 0], + Quote: ['-', '_', '–', '—', 0], + Backquote: ['`', '~', '`', '`', 4], + Comma: ['w', 'W', '∑', '„', 0], + Period: ['v', 'V', '√', '◊', 0], + Slash: ['z', 'Z', 'Ω', '¸', 0], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '/', '/', 0], + NumpadMultiply: ['*', '*', '*', '*', 0], + NumpadSubtract: ['-', '-', '-', '-', 0], + NumpadAdd: ['+', '+', '+', '+', 0], + NumpadEnter: [], + Numpad1: ['1', '1', '1', '1', 0], + Numpad2: ['2', '2', '2', '2', 0], + Numpad3: ['3', '3', '3', '3', 0], + Numpad4: ['4', '4', '4', '4', 0], + Numpad5: ['5', '5', '5', '5', 0], + Numpad6: ['6', '6', '6', '6', 0], + Numpad7: ['7', '7', '7', '7', 0], + Numpad8: ['8', '8', '8', '8', 0], + Numpad9: ['9', '9', '9', '9', 0], + Numpad0: ['0', '0', '0', '0', 0], + NumpadDecimal: ['.', '.', '.', '.', 0], + IntlBackslash: ['§', '±', '§', '±', 0], + ContextMenu: [], + NumpadEqual: ['=', '=', '=', '=', 0], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + AudioVolumeMute: [], + AudioVolumeUp: ['', '=', '', '=', 0], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [] + } +}); diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-belgian.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-belgian.win.ts new file mode 100644 index 000000000..89e3a2789 --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-belgian.win.ts @@ -0,0 +1,169 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { name: '00000813', id: '', text: 'Belgian (Period)' }, + secondaryLayouts: [], + mapping: { + Sleep: [], + WakeUp: [], + KeyA: ['q', 'Q', '', '', 0, 'VK_Q'], + KeyB: ['b', 'B', '', '', 0, 'VK_B'], + KeyC: ['c', 'C', '', '', 0, 'VK_C'], + KeyD: ['d', 'D', '', '', 0, 'VK_D'], + KeyE: ['e', 'E', '€', '', 0, 'VK_E'], + KeyF: ['f', 'F', '', '', 0, 'VK_F'], + KeyG: ['g', 'G', '', '', 0, 'VK_G'], + KeyH: ['h', 'H', '', '', 0, 'VK_H'], + KeyI: ['i', 'I', '', '', 0, 'VK_I'], + KeyJ: ['j', 'J', '', '', 0, 'VK_J'], + KeyK: ['k', 'K', '', '', 0, 'VK_K'], + KeyL: ['l', 'L', '', '', 0, 'VK_L'], + KeyM: [',', '?', '', '', 0, 'VK_OEM_COMMA'], + KeyN: ['n', 'N', '', '', 0, 'VK_N'], + KeyO: ['o', 'O', '', '', 0, 'VK_O'], + KeyP: ['p', 'P', '', '', 0, 'VK_P'], + KeyQ: ['a', 'A', '', '', 0, 'VK_A'], + KeyR: ['r', 'R', '', '', 0, 'VK_R'], + KeyS: ['s', 'S', '', '', 0, 'VK_S'], + KeyT: ['t', 'T', '', '', 0, 'VK_T'], + KeyU: ['u', 'U', '', '', 0, 'VK_U'], + KeyV: ['v', 'V', '', '', 0, 'VK_V'], + KeyW: ['z', 'Z', '', '', 0, 'VK_Z'], + KeyX: ['x', 'X', '', '', 0, 'VK_X'], + KeyY: ['y', 'Y', '', '', 0, 'VK_Y'], + KeyZ: ['w', 'W', '', '', 0, 'VK_W'], + Digit1: ['&', '1', '|', '', 0, 'VK_1'], + Digit2: ['é', '2', '@', '', 0, 'VK_2'], + Digit3: ['"', '3', '#', '', 0, 'VK_3'], + Digit4: ['\'', '4', '{', '', 0, 'VK_4'], + Digit5: ['(', '5', '[', '', 0, 'VK_5'], + Digit6: ['§', '6', '^', '', 0, 'VK_6'], + Digit7: ['è', '7', '', '', 0, 'VK_7'], + Digit8: ['!', '8', '', '', 0, 'VK_8'], + Digit9: ['ç', '9', '{', '', 0, 'VK_9'], + Digit0: ['à', '0', '}', '', 0, 'VK_0'], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', '', '', 0, 'VK_SPACE'], + Minus: [')', '°', '', '', 0, 'VK_OEM_4'], + Equal: ['-', '_', '', '', 0, 'VK_OEM_MINUS'], + BracketLeft: ['^', '¨', '[', '', 0, 'VK_OEM_6'], + BracketRight: ['$', '*', ']', '', 0, 'VK_OEM_1'], + Backslash: ['µ', '£', '`', '`', 0, 'VK_OEM_5'], + Semicolon: ['m', 'M', '', '', 0, 'VK_M'], + Quote: ['ù', '%', '´', '´', 0, 'VK_OEM_3'], + Backquote: ['²', '³', '', '', 0, 'VK_OEM_7'], + Comma: [';', '.', '', '', 0, 'VK_OEM_PERIOD'], + Period: [':', '/', '', '', 0, 'VK_OEM_2'], + Slash: ['=', '+', '~', '~', 0, 'VK_OEM_PLUS'], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + PrintScreen: [], + ScrollLock: [], + Pause: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '', '', 0, 'VK_DIVIDE'], + NumpadMultiply: ['*', '*', '', '', 0, 'VK_MULTIPLY'], + NumpadSubtract: ['-', '-', '', '', 0, 'VK_SUBTRACT'], + NumpadAdd: ['+', '+', '', '', 0, 'VK_ADD'], + NumpadEnter: [], + Numpad1: [], + Numpad2: [], + Numpad3: [], + Numpad4: [], + Numpad5: [], + Numpad6: [], + Numpad7: [], + Numpad8: [], + Numpad9: [], + Numpad0: [], + NumpadDecimal: [], + IntlBackslash: ['<', '>', '\\', '', 0, 'VK_OEM_102'], + ContextMenu: [], + Power: [], + NumpadEqual: [], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + F21: [], + F22: [], + F23: [], + F24: [], + Help: [], + Undo: [], + Cut: [], + Copy: [], + Paste: [], + AudioVolumeMute: [], + AudioVolumeUp: [], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + Convert: [], + NonConvert: [], + Lang1: [], + Lang2: [], + Lang3: [], + Lang4: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [], + MediaTrackNext: [], + MediaTrackPrevious: [], + MediaStop: [], + Eject: [], + MediaPlayPause: [], + MediaSelect: [], + LaunchMail: [], + LaunchApp2: [], + LaunchApp1: [], + BrowserSearch: [], + BrowserHome: [], + BrowserBack: [], + BrowserForward: [], + BrowserStop: [], + BrowserRefresh: [], + BrowserFavorites: [] + } +}); diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-ext.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-ext.darwin.ts new file mode 100644 index 000000000..a12a2338b --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-ext.darwin.ts @@ -0,0 +1,132 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { id: 'com.apple.keylayout.USExtended', lang: 'en', localizedName: 'ABC - Extended' }, + secondaryLayouts: [], + mapping: { + KeyA: ['a', 'A', '¯', '̄', 4], + KeyB: ['b', 'B', '˘', '̆', 4], + KeyC: ['c', 'C', '¸', '̧', 4], + KeyD: ['d', 'D', 'ð', 'Ð', 0], + KeyE: ['e', 'E', '´', '́', 4], + KeyF: ['f', 'F', 'ƒ', '', 0], + KeyG: ['g', 'G', '©', '‸', 8], + KeyH: ['h', 'H', 'ˍ', '̱', 4], + KeyI: ['i', 'I', 'ʼ', '̛', 4], + KeyJ: ['j', 'J', '˝', '̋', 4], + KeyK: ['k', 'K', '˚', '̊', 4], + KeyL: ['l', 'L', '-', '̵', 4], + KeyM: ['m', 'M', '˛', '̨', 4], + KeyN: ['n', 'N', '˜', '̃', 4], + KeyO: ['o', 'O', 'ø', 'Ø', 0], + KeyP: ['p', 'P', ',', '̦', 4], + KeyQ: ['q', 'Q', 'œ', 'Œ', 0], + KeyR: ['r', 'R', '®', '‰', 0], + KeyS: ['s', 'S', 'ß', '', 0], + KeyT: ['t', 'T', 'þ', 'Þ', 0], + KeyU: ['u', 'U', '¨', '̈', 4], + KeyV: ['v', 'V', 'ˇ', '̌', 4], + KeyW: ['w', 'W', '˙', '̇', 4], + KeyX: ['x', 'X', '.', '̣', 4], + KeyY: ['y', 'Y', '¥', '', 0], + KeyZ: ['z', 'Z', 'ˀ', '̉', 4], + Digit1: ['1', '!', '¡', '⁄', 0], + Digit2: ['2', '@', '™', '€', 0], + Digit3: ['3', '#', '£', '‹', 0], + Digit4: ['4', '$', '¢', '›', 0], + Digit5: ['5', '%', '§', '†', 0], + Digit6: ['6', '^', 'ˆ', '̂', 4], + Digit7: ['7', '&', '¶', '‡', 0], + Digit8: ['8', '*', '•', '°', 0], + Digit9: ['9', '(', 'ª', '·', 0], + Digit0: ['0', ')', 'º', '‚', 0], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', ' ', ' ', 0], + Minus: ['-', '_', '–', '—', 0], + Equal: ['=', '+', '≠', '±', 0], + BracketLeft: ['[', '{', '“', '”', 0], + BracketRight: [']', '}', '‘', '’', 0], + Backslash: ['\\', '|', '«', '»', 0], + Semicolon: [';', ':', '…', '№', 8], + Quote: ['\'', '"', 'æ', 'Æ', 0], + Backquote: ['`', '~', '`', '̀', 4], + Comma: [',', '<', '≤', '„', 0], + Period: ['.', '>', '≥', 'ʔ', 8], + Slash: ['/', '?', '÷', '¿', 0], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '/', '/', 0], + NumpadMultiply: ['*', '*', '*', '*', 0], + NumpadSubtract: ['-', '-', '-', '-', 0], + NumpadAdd: ['+', '+', '+', '+', 0], + NumpadEnter: [], + Numpad1: ['1', '1', '1', '1', 0], + Numpad2: ['2', '2', '2', '2', 0], + Numpad3: ['3', '3', '3', '3', 0], + Numpad4: ['4', '4', '4', '4', 0], + Numpad5: ['5', '5', '5', '5', 0], + Numpad6: ['6', '6', '6', '6', 0], + Numpad7: ['7', '7', '7', '7', 0], + Numpad8: ['8', '8', '8', '8', 0], + Numpad9: ['9', '9', '9', '9', 0], + Numpad0: ['0', '0', '0', '0', 0], + NumpadDecimal: ['.', '.', '.', '.', 0], + IntlBackslash: ['§', '±', '§', '±', 0], + ContextMenu: [], + NumpadEqual: ['=', '=', '=', '=', 0], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + AudioVolumeMute: [], + AudioVolumeUp: ['', '=', '', '=', 0], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [] + } +}); \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-in.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-in.win.ts new file mode 100644 index 000000000..a1786f420 --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-in.win.ts @@ -0,0 +1,169 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { name: '00004009', id: '', text: 'India' }, + secondaryLayouts: [], + mapping: { + Sleep: [], + WakeUp: [], + KeyA: ['a', 'A', 'ā', 'Ā', 0, 'VK_A'], + KeyB: ['b', 'B', '', '', 0, 'VK_B'], + KeyC: ['c', 'C', '', '', 0, 'VK_C'], + KeyD: ['d', 'D', 'ḍ', 'Ḍ', 0, 'VK_D'], + KeyE: ['e', 'E', 'ē', 'Ē', 0, 'VK_E'], + KeyF: ['f', 'F', '', '', 0, 'VK_F'], + KeyG: ['g', 'G', 'ṅ', 'Ṅ', 0, 'VK_G'], + KeyH: ['h', 'H', 'ḥ', 'Ḥ', 0, 'VK_H'], + KeyI: ['i', 'I', 'ī', 'Ī', 0, 'VK_I'], + KeyJ: ['j', 'J', '', '', 0, 'VK_J'], + KeyK: ['k', 'K', '', '', 0, 'VK_K'], + KeyL: ['l', 'L', 'l̥', 'L̥', 0, 'VK_L'], + KeyM: ['m', 'M', 'ṁ', 'Ṁ', 0, 'VK_M'], + KeyN: ['n', 'N', 'ṇ', 'Ṇ', 0, 'VK_N'], + KeyO: ['o', 'O', 'ō', 'Ō', 0, 'VK_O'], + KeyP: ['p', 'P', '', '', 0, 'VK_P'], + KeyQ: ['q', 'Q', 'æ', 'Æ', 0, 'VK_Q'], + KeyR: ['r', 'R', 'r̥', 'R̥', 0, 'VK_R'], + KeyS: ['s', 'S', 'ś', 'Ś', 0, 'VK_S'], + KeyT: ['t', 'T', 'ṭ', 'Ṭ', 0, 'VK_T'], + KeyU: ['u', 'U', 'ū', 'Ū', 0, 'VK_U'], + KeyV: ['v', 'V', '', '', 0, 'VK_V'], + KeyW: ['w', 'W', '', '', 0, 'VK_W'], + KeyX: ['x', 'X', 'ṣ', 'Ṣ', 0, 'VK_X'], + KeyY: ['y', 'Y', 'ñ', 'Ñ', 0, 'VK_Y'], + KeyZ: ['z', 'Z', '', '', 0, 'VK_Z'], + Digit1: ['1', '!', '', '', 0, 'VK_1'], + Digit2: ['2', '@', '', '', 0, 'VK_2'], + Digit3: ['3', '#', '', '', 0, 'VK_3'], + Digit4: ['4', '$', '₹', '', 0, 'VK_4'], + Digit5: ['5', '%', '', '', 0, 'VK_5'], + Digit6: ['6', '^', '', 'ˆ', 0, 'VK_6'], + Digit7: ['7', '&', '', '', 0, 'VK_7'], + Digit8: ['8', '*', '', '', 0, 'VK_8'], + Digit9: ['9', '(', '', '˘', 0, 'VK_9'], + Digit0: ['0', ')', '', '', 0, 'VK_0'], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', '', '', 0, 'VK_SPACE'], + Minus: ['-', '_', '-', 'ˍ', 0, 'VK_OEM_MINUS'], + Equal: ['=', '+', '', '', 0, 'VK_OEM_PLUS'], + BracketLeft: ['[', '{', '', '', 0, 'VK_OEM_4'], + BracketRight: [']', '}', '', '', 0, 'VK_OEM_6'], + Backslash: ['\\', '|', '', '', 0, 'VK_OEM_5'], + Semicolon: [';', ':', '', '', 0, 'VK_OEM_1'], + Quote: ['\'', '"', '', '', 0, 'VK_OEM_7'], + Backquote: ['`', '~', '', '~', 0, 'VK_OEM_3'], + Comma: [',', '<', ',', '<', 0, 'VK_OEM_COMMA'], + Period: ['.', '>', '.', '', 0, 'VK_OEM_PERIOD'], + Slash: ['/', '?', '', '', 0, 'VK_OEM_2'], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + PrintScreen: [], + ScrollLock: [], + Pause: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '', '', 0, 'VK_DIVIDE'], + NumpadMultiply: ['*', '*', '', '', 0, 'VK_MULTIPLY'], + NumpadSubtract: ['-', '-', '', '', 0, 'VK_SUBTRACT'], + NumpadAdd: ['+', '+', '', '', 0, 'VK_ADD'], + NumpadEnter: [], + Numpad1: [], + Numpad2: [], + Numpad3: [], + Numpad4: [], + Numpad5: [], + Numpad6: [], + Numpad7: [], + Numpad8: [], + Numpad9: [], + Numpad0: [], + NumpadDecimal: [], + IntlBackslash: ['\\', '|', '', '', 0, 'VK_OEM_102'], + ContextMenu: [], + Power: [], + NumpadEqual: [], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + F21: [], + F22: [], + F23: [], + F24: [], + Help: [], + Undo: [], + Cut: [], + Copy: [], + Paste: [], + AudioVolumeMute: [], + AudioVolumeUp: [], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + Convert: [], + NonConvert: [], + Lang1: [], + Lang2: [], + Lang3: [], + Lang4: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [], + MediaTrackNext: [], + MediaTrackPrevious: [], + MediaStop: [], + Eject: [], + MediaPlayPause: [], + MediaSelect: [], + LaunchMail: [], + LaunchApp2: [], + LaunchApp1: [], + BrowserSearch: [], + BrowserHome: [], + BrowserBack: [], + BrowserForward: [], + BrowserStop: [], + BrowserRefresh: [], + BrowserFavorites: [] + } +}); \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-intl.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-intl.darwin.ts new file mode 100644 index 000000000..ceb7b67a8 --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-intl.darwin.ts @@ -0,0 +1,132 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { id: 'com.apple.keylayout.USInternational-PC', lang: 'en', localizedName: 'U.S. International - PC' }, + secondaryLayouts: [], + mapping: { + KeyA: ['a', 'A', 'å', 'Å', 0], + KeyB: ['b', 'B', '∫', 'ı', 0], + KeyC: ['c', 'C', 'ç', 'Ç', 0], + KeyD: ['d', 'D', '∂', 'Î', 0], + KeyE: ['e', 'E', '´', '´', 4], + KeyF: ['f', 'F', 'ƒ', 'Ï', 0], + KeyG: ['g', 'G', '©', '˝', 0], + KeyH: ['h', 'H', '˙', 'Ó', 0], + KeyI: ['i', 'I', 'ˆ', 'ˆ', 4], + KeyJ: ['j', 'J', '∆', 'Ô', 0], + KeyK: ['k', 'K', '˚', '', 0], + KeyL: ['l', 'L', '¬', 'Ò', 0], + KeyM: ['m', 'M', 'µ', 'Â', 0], + KeyN: ['n', 'N', '˜', '˜', 4], + KeyO: ['o', 'O', 'ø', 'Ø', 0], + KeyP: ['p', 'P', 'π', '∏', 0], + KeyQ: ['q', 'Q', 'œ', 'Œ', 0], + KeyR: ['r', 'R', '®', '‰', 0], + KeyS: ['s', 'S', 'ß', 'Í', 0], + KeyT: ['t', 'T', '†', 'ˇ', 0], + KeyU: ['u', 'U', '¨', '¨', 4], + KeyV: ['v', 'V', '√', '◊', 0], + KeyW: ['w', 'W', '∑', '„', 0], + KeyX: ['x', 'X', '≈', '˛', 0], + KeyY: ['y', 'Y', '¥', 'Á', 0], + KeyZ: ['z', 'Z', 'Ω', '¸', 0], + Digit1: ['1', '!', '¡', '⁄', 0], + Digit2: ['2', '@', '™', '€', 0], + Digit3: ['3', '#', '£', '‹', 0], + Digit4: ['4', '$', '¢', '›', 0], + Digit5: ['5', '%', '∞', 'fi', 0], + Digit6: ['6', 'ˆ', '§', 'fl', 2], + Digit7: ['7', '&', '¶', '‡', 0], + Digit8: ['8', '*', '•', '°', 0], + Digit9: ['9', '(', 'ª', '·', 0], + Digit0: ['0', ')', 'º', '‚', 0], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', ' ', ' ', 0], + Minus: ['-', '_', '–', '—', 0], + Equal: ['=', '+', '≠', '±', 0], + BracketLeft: ['[', '{', '“', '”', 0], + BracketRight: [']', '}', '‘', '’', 0], + Backslash: ['\\', '|', '«', '»', 0], + Semicolon: [';', ':', '…', 'Ú', 0], + Quote: ['\'', '"', 'æ', 'Æ', 3], + Backquote: ['`', '˜', '`', '`', 7], + Comma: [',', '<', '≤', '¯', 0], + Period: ['.', '>', '≥', '˘', 0], + Slash: ['/', '?', '÷', '¿', 0], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '/', '/', 0], + NumpadMultiply: ['*', '*', '*', '*', 0], + NumpadSubtract: ['-', '-', '-', '-', 0], + NumpadAdd: ['+', '+', '+', '+', 0], + NumpadEnter: [], + Numpad1: ['1', '1', '1', '1', 0], + Numpad2: ['2', '2', '2', '2', 0], + Numpad3: ['3', '3', '3', '3', 0], + Numpad4: ['4', '4', '4', '4', 0], + Numpad5: ['5', '5', '5', '5', 0], + Numpad6: ['6', '6', '6', '6', 0], + Numpad7: ['7', '7', '7', '7', 0], + Numpad8: ['8', '8', '8', '8', 0], + Numpad9: ['9', '9', '9', '9', 0], + Numpad0: ['0', '0', '0', '0', 0], + NumpadDecimal: ['.', '.', '.', '.', 0], + IntlBackslash: ['§', '±', '§', '±', 0], + ContextMenu: [], + NumpadEqual: ['=', '=', '=', '=', 0], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + AudioVolumeMute: [], + AudioVolumeUp: ['', '=', '', '=', 0], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [] + } +}); \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-intl.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-intl.win.ts new file mode 100644 index 000000000..75a2a40b8 --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-intl.win.ts @@ -0,0 +1,169 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { name: '00020409', id: '0001', text: 'United States-International' }, + secondaryLayouts: [], + mapping: { + Sleep: [], + WakeUp: [], + KeyA: ['a', 'A', 'á', 'Á', 0, 'VK_A'], + KeyB: ['b', 'B', '', '', 0, 'VK_B'], + KeyC: ['c', 'C', '©', '¢', 0, 'VK_C'], + KeyD: ['d', 'D', 'ð', 'Ð', 0, 'VK_D'], + KeyE: ['e', 'E', 'é', 'É', 0, 'VK_E'], + KeyF: ['f', 'F', '', '', 0, 'VK_F'], + KeyG: ['g', 'G', '', '', 0, 'VK_G'], + KeyH: ['h', 'H', '', '', 0, 'VK_H'], + KeyI: ['i', 'I', 'í', 'Í', 0, 'VK_I'], + KeyJ: ['j', 'J', '', '', 0, 'VK_J'], + KeyK: ['k', 'K', '', '', 0, 'VK_K'], + KeyL: ['l', 'L', 'ø', 'Ø', 0, 'VK_L'], + KeyM: ['m', 'M', 'µ', '', 0, 'VK_M'], + KeyN: ['n', 'N', 'ñ', 'Ñ', 0, 'VK_N'], + KeyO: ['o', 'O', 'ó', 'Ó', 0, 'VK_O'], + KeyP: ['p', 'P', 'ö', 'Ö', 0, 'VK_P'], + KeyQ: ['q', 'Q', 'ä', 'Ä', 0, 'VK_Q'], + KeyR: ['r', 'R', '®', '', 0, 'VK_R'], + KeyS: ['s', 'S', 'ß', '§', 0, 'VK_S'], + KeyT: ['t', 'T', 'þ', 'Þ', 0, 'VK_T'], + KeyU: ['u', 'U', 'ú', 'Ú', 0, 'VK_U'], + KeyV: ['v', 'V', '', '', 0, 'VK_V'], + KeyW: ['w', 'W', 'å', 'Å', 0, 'VK_W'], + KeyX: ['x', 'X', '', '', 0, 'VK_X'], + KeyY: ['y', 'Y', 'ü', 'Ü', 0, 'VK_Y'], + KeyZ: ['z', 'Z', 'æ', 'Æ', 0, 'VK_Z'], + Digit1: ['1', '!', '¡', '¹', 0, 'VK_1'], + Digit2: ['2', '@', '²', '', 0, 'VK_2'], + Digit3: ['3', '#', '³', '', 0, 'VK_3'], + Digit4: ['4', '$', '¤', '£', 0, 'VK_4'], + Digit5: ['5', '%', '€', '', 0, 'VK_5'], + Digit6: ['6', '^', '¼', '', 0, 'VK_6'], + Digit7: ['7', '&', '½', '', 0, 'VK_7'], + Digit8: ['8', '*', '¾', '', 0, 'VK_8'], + Digit9: ['9', '(', '‘', '', 0, 'VK_9'], + Digit0: ['0', ')', '’', '', 0, 'VK_0'], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', '', '', 0, 'VK_SPACE'], + Minus: ['-', '_', '¥', '', 0, 'VK_OEM_MINUS'], + Equal: ['=', '+', '×', '÷', 0, 'VK_OEM_PLUS'], + BracketLeft: ['[', '{', '«', '', 0, 'VK_OEM_4'], + BracketRight: [']', '}', '»', '', 0, 'VK_OEM_6'], + Backslash: ['\\', '|', '¬', '¦', 0, 'VK_OEM_5'], + Semicolon: [';', ':', '¶', '°', 0, 'VK_OEM_1'], + Quote: ['\'', '"', '´', '¨', 0, 'VK_OEM_7'], + Backquote: ['`', '~', '', '', 0, 'VK_OEM_3'], + Comma: [',', '<', 'ç', 'Ç', 0, 'VK_OEM_COMMA'], + Period: ['.', '>', '', '', 0, 'VK_OEM_PERIOD'], + Slash: ['/', '?', '¿', '', 0, 'VK_OEM_2'], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + PrintScreen: [], + ScrollLock: [], + Pause: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '', '', 0, 'VK_DIVIDE'], + NumpadMultiply: ['*', '*', '', '', 0, 'VK_MULTIPLY'], + NumpadSubtract: ['-', '-', '', '', 0, 'VK_SUBTRACT'], + NumpadAdd: ['+', '+', '', '', 0, 'VK_ADD'], + NumpadEnter: [], + Numpad1: [], + Numpad2: [], + Numpad3: [], + Numpad4: [], + Numpad5: [], + Numpad6: [], + Numpad7: [], + Numpad8: [], + Numpad9: [], + Numpad0: [], + NumpadDecimal: [], + IntlBackslash: ['\\', '|', '', '', 0, 'VK_OEM_102'], + ContextMenu: [], + Power: [], + NumpadEqual: [], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + F21: [], + F22: [], + F23: [], + F24: [], + Help: [], + Undo: [], + Cut: [], + Copy: [], + Paste: [], + AudioVolumeMute: [], + AudioVolumeUp: [], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + Convert: [], + NonConvert: [], + Lang1: [], + Lang2: [], + Lang3: [], + Lang4: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [], + MediaTrackNext: [], + MediaTrackPrevious: [], + MediaStop: [], + Eject: [], + MediaPlayPause: [], + MediaSelect: [], + LaunchMail: [], + LaunchApp2: [], + LaunchApp1: [], + BrowserSearch: [], + BrowserHome: [], + BrowserBack: [], + BrowserForward: [], + BrowserStop: [], + BrowserRefresh: [], + BrowserFavorites: [] + } +}); diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-uk.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-uk.darwin.ts new file mode 100644 index 000000000..892363377 --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-uk.darwin.ts @@ -0,0 +1,131 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { id: 'com.apple.keylayout.British', lang: 'en', localizedName: 'British' }, + secondaryLayouts: [], + mapping: { + KeyA: ['a', 'A', 'å', 'Å', 0], + KeyB: ['b', 'B', '∫', 'ı', 0], + KeyC: ['c', 'C', 'ç', 'Ç', 0], + KeyD: ['d', 'D', '∂', 'Î', 0], + KeyE: ['e', 'E', '´', '‰', 4], + KeyF: ['f', 'F', 'ƒ', 'Ï', 0], + KeyG: ['g', 'G', '©', 'Ì', 0], + KeyH: ['h', 'H', '˙', 'Ó', 0], + KeyI: ['i', 'I', '^', 'È', 4], + KeyJ: ['j', 'J', '∆', 'Ô', 0], + KeyK: ['k', 'K', '˚', '', 0], + KeyL: ['l', 'L', '¬', 'Ò', 0], + KeyM: ['m', 'M', 'µ', '˜', 0], + KeyN: ['n', 'N', '~', 'ˆ', 4], + KeyO: ['o', 'O', 'ø', 'Ø', 0], + KeyP: ['p', 'P', 'π', '∏', 0], + KeyQ: ['q', 'Q', 'œ', 'Œ', 0], + KeyR: ['r', 'R', '®', 'Â', 0], + KeyS: ['s', 'S', 'ß', 'Í', 0], + KeyT: ['t', 'T', '†', 'Ê', 0], + KeyU: ['u', 'U', '¨', 'Ë', 4], + KeyV: ['v', 'V', '√', '◊', 0], + KeyW: ['w', 'W', '∑', '„', 0], + KeyX: ['x', 'X', '≈', 'Ù', 0], + KeyY: ['y', 'Y', '¥', 'Á', 0], + KeyZ: ['z', 'Z', 'Ω', 'Û', 0], + Digit1: ['1', '!', '¡', '⁄', 0], + Digit2: ['2', '@', '€', '™', 0], + Digit3: ['3', '£', '#', '‹', 0], + Digit4: ['4', '$', '¢', '›', 0], + Digit5: ['5', '%', '∞', 'fi', 0], + Digit6: ['6', '^', '§', 'fl', 0], + Digit7: ['7', '&', '¶', '‡', 0], + Digit8: ['8', '*', '•', '°', 0], + Digit9: ['9', '(', 'ª', '·', 0], + Digit0: ['0', ')', 'º', '‚', 0], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', ' ', ' ', 0], + Minus: ['-', '_', '–', '—', 0], + Equal: ['=', '+', '≠', '±', 0], + BracketLeft: ['[', '{', '“', '”', 0], + BracketRight: [']', '}', '‘', '’', 0], + Backslash: ['\\', '|', '«', '»', 0], + Semicolon: [';', ':', '…', 'Ú', 0], + Quote: ['\'', '"', 'æ', 'Æ', 0], + Backquote: ['`', '~', '`', 'Ÿ', 4], + Comma: [',', '<', '≤', '¯', 0], + Period: ['.', '>', '≥', '˘', 0], + Slash: ['/', '?', '÷', '¿', 0], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '/', '/', 0], + NumpadMultiply: ['*', '*', '*', '*', 0], + NumpadSubtract: ['-', '-', '-', '-', 0], + NumpadAdd: ['+', '+', '+', '+', 0], + NumpadEnter: [], + Numpad1: ['1', '1', '1', '1', 0], + Numpad2: ['2', '2', '2', '2', 0], + Numpad3: ['3', '3', '3', '3', 0], + Numpad4: ['4', '4', '4', '4', 0], + Numpad5: ['5', '5', '5', '5', 0], + Numpad6: ['6', '6', '6', '6', 0], + Numpad7: ['7', '7', '7', '7', 0], + Numpad8: ['8', '8', '8', '8', 0], + Numpad9: ['9', '9', '9', '9', 0], + Numpad0: ['0', '0', '0', '0', 0], + NumpadDecimal: ['.', '.', '.', '.', 0], + IntlBackslash: ['§', '±', '', '', 0], + ContextMenu: [], + NumpadEqual: ['=', '=', '=', '=', 0], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + AudioVolumeMute: [], + AudioVolumeUp: ['', '=', '', '=', 0], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [] + } +}); \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-uk.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-uk.win.ts new file mode 100644 index 000000000..0b07025fa --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en-uk.win.ts @@ -0,0 +1,170 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { name: '00000809', id: '', text: 'United Kingdom' }, + secondaryLayouts: [], + mapping: { + Sleep: [], + WakeUp: [], + KeyA: ['a', 'A', 'á', 'Á', 0, 'VK_A'], + KeyB: ['b', 'B', '', '', 0, 'VK_B'], + KeyC: ['c', 'C', '', '', 0, 'VK_C'], + KeyD: ['d', 'D', '', '', 0, 'VK_D'], + KeyE: ['e', 'E', 'é', 'É', 0, 'VK_E'], + KeyF: ['f', 'F', '', '', 0, 'VK_F'], + KeyG: ['g', 'G', '', '', 0, 'VK_G'], + KeyH: ['h', 'H', '', '', 0, 'VK_H'], + KeyI: ['i', 'I', 'í', 'Í', 0, 'VK_I'], + KeyJ: ['j', 'J', '', '', 0, 'VK_J'], + KeyK: ['k', 'K', '', '', 0, 'VK_K'], + KeyL: ['l', 'L', '', '', 0, 'VK_L'], + KeyM: ['m', 'M', '', '', 0, 'VK_M'], + KeyN: ['n', 'N', '', '', 0, 'VK_N'], + KeyO: ['o', 'O', 'ó', 'Ó', 0, 'VK_O'], + KeyP: ['p', 'P', '', '', 0, 'VK_P'], + KeyQ: ['q', 'Q', '', '', 0, 'VK_Q'], + KeyR: ['r', 'R', '', '', 0, 'VK_R'], + KeyS: ['s', 'S', '', '', 0, 'VK_S'], + KeyT: ['t', 'T', '', '', 0, 'VK_T'], + KeyU: ['u', 'U', 'ú', 'Ú', 0, 'VK_U'], + KeyV: ['v', 'V', '', '', 0, 'VK_V'], + KeyW: ['w', 'W', '', '', 0, 'VK_W'], + KeyX: ['x', 'X', '', '', 0, 'VK_X'], + KeyY: ['y', 'Y', '', '', 0, 'VK_Y'], + KeyZ: ['z', 'Z', '', '', 0, 'VK_Z'], + Digit1: ['1', '!', '', '', 0, 'VK_1'], + Digit2: ['2', '"', '', '', 0, 'VK_2'], + Digit3: ['3', '£', '', '', 0, 'VK_3'], + Digit4: ['4', '$', '€', '', 0, 'VK_4'], + Digit5: ['5', '%', '', '', 0, 'VK_5'], + Digit6: ['6', '^', '', '', 0, 'VK_6'], + Digit7: ['7', '&', '', '', 0, 'VK_7'], + Digit8: ['8', '*', '', '', 0, 'VK_8'], + Digit9: ['9', '(', '', '', 0, 'VK_9'], + Digit0: ['0', ')', '', '', 0, 'VK_0'], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', '', '', 0, 'VK_SPACE'], + Minus: ['-', '_', '', '', 0, 'VK_OEM_MINUS'], + Equal: ['=', '+', '', '', 0, 'VK_OEM_PLUS'], + BracketLeft: ['[', '{', '', '', 0, 'VK_OEM_4'], + BracketRight: [']', '}', '', '', 0, 'VK_OEM_6'], + Backslash: ['#', '~', '\\', '|', 0, 'VK_OEM_7'], + Semicolon: [';', ':', '', '', 0, 'VK_OEM_1'], + Quote: ['\'', '@', '', '', 0, 'VK_OEM_3'], + Backquote: ['`', '¬', '¦', '', 0, 'VK_OEM_8'], + Comma: [',', '<', '', '', 0, 'VK_OEM_COMMA'], + Period: ['.', '>', '', '', 0, 'VK_OEM_PERIOD'], + Slash: ['/', '?', '', '', 0, 'VK_OEM_2'], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + PrintScreen: [], + ScrollLock: [], + Pause: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '', '', 0, 'VK_DIVIDE'], + NumpadMultiply: ['*', '*', '', '', 0, 'VK_MULTIPLY'], + NumpadSubtract: ['-', '-', '', '', 0, 'VK_SUBTRACT'], + NumpadAdd: ['+', '+', '', '', 0, 'VK_ADD'], + NumpadEnter: [], + Numpad1: [], + Numpad2: [], + Numpad3: [], + Numpad4: [], + Numpad5: [], + Numpad6: [], + Numpad7: [], + Numpad8: [], + Numpad9: [], + Numpad0: [], + NumpadDecimal: [], + IntlBackslash: ['\\', '|', '', '', 0, 'VK_OEM_5'], + ContextMenu: [], + Power: [], + NumpadEqual: [], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + F21: [], + F22: [], + F23: [], + F24: [], + Help: [], + Undo: [], + Cut: [], + Copy: [], + Paste: [], + AudioVolumeMute: [], + AudioVolumeUp: [], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + Convert: [], + NonConvert: [], + Lang1: [], + Lang2: [], + Lang3: [], + Lang4: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [], + MediaTrackNext: [], + MediaTrackPrevious: [], + MediaStop: [], + Eject: [], + MediaPlayPause: [], + MediaSelect: [], + LaunchMail: [], + LaunchApp2: [], + LaunchApp1: [], + BrowserSearch: [], + BrowserHome: [], + BrowserBack: [], + BrowserForward: [], + BrowserStop: [], + BrowserRefresh: [], + BrowserFavorites: [] + } + +}); \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en.darwin.ts new file mode 100644 index 000000000..f0fca4a9d --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en.darwin.ts @@ -0,0 +1,140 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { id: 'com.apple.keylayout.US', lang: 'en', localizedName: 'U.S.', isUSStandard: true }, + secondaryLayouts: [ + { id: 'com.apple.keylayout.ABC', lang: 'en', localizedName: 'ABC' }, + { id: 'com.sogou.inputmethod.sogou.pinyin', lang: 'zh-Hans', localizedName: 'Pinyin - Simplified' }, + { id: 'com.apple.inputmethod.Kotoeri.Roman', lang: 'en', localizedName: 'Romaji' }, + { id: 'com.apple.inputmethod.Kotoeri.Japanese', lang: 'ja', localizedName: 'Hiragana' }, + { id: 'com.apple.keylayout.Australian', lang: 'en', localizedName: 'Australian' }, + { id: 'com.apple.keylayout.Canadian', lang: 'en', localizedName: 'Canadian English' }, + { id: 'com.apple.keylayout.Brazilian', lang: 'pt', localizedName: 'Brazilian' }, + ], + mapping: { + KeyA: ['a', 'A', 'å', 'Å', 0], + KeyB: ['b', 'B', '∫', 'ı', 0], + KeyC: ['c', 'C', 'ç', 'Ç', 0], + KeyD: ['d', 'D', '∂', 'Î', 0], + KeyE: ['e', 'E', '´', '´', 4], + KeyF: ['f', 'F', 'ƒ', 'Ï', 0], + KeyG: ['g', 'G', '©', '˝', 0], + KeyH: ['h', 'H', '˙', 'Ó', 0], + KeyI: ['i', 'I', 'ˆ', 'ˆ', 4], + KeyJ: ['j', 'J', '∆', 'Ô', 0], + KeyK: ['k', 'K', '˚', '', 0], + KeyL: ['l', 'L', '¬', 'Ò', 0], + KeyM: ['m', 'M', 'µ', 'Â', 0], + KeyN: ['n', 'N', '˜', '˜', 4], + KeyO: ['o', 'O', 'ø', 'Ø', 0], + KeyP: ['p', 'P', 'π', '∏', 0], + KeyQ: ['q', 'Q', 'œ', 'Œ', 0], + KeyR: ['r', 'R', '®', '‰', 0], + KeyS: ['s', 'S', 'ß', 'Í', 0], + KeyT: ['t', 'T', '†', 'ˇ', 0], + KeyU: ['u', 'U', '¨', '¨', 4], + KeyV: ['v', 'V', '√', '◊', 0], + KeyW: ['w', 'W', '∑', '„', 0], + KeyX: ['x', 'X', '≈', '˛', 0], + KeyY: ['y', 'Y', '¥', 'Á', 0], + KeyZ: ['z', 'Z', 'Ω', '¸', 0], + Digit1: ['1', '!', '¡', '⁄', 0], + Digit2: ['2', '@', '™', '€', 0], + Digit3: ['3', '#', '£', '‹', 0], + Digit4: ['4', '$', '¢', '›', 0], + Digit5: ['5', '%', '∞', 'fi', 0], + Digit6: ['6', '^', '§', 'fl', 0], + Digit7: ['7', '&', '¶', '‡', 0], + Digit8: ['8', '*', '•', '°', 0], + Digit9: ['9', '(', 'ª', '·', 0], + Digit0: ['0', ')', 'º', '‚', 0], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', ' ', ' ', 0], + Minus: ['-', '_', '–', '—', 0], + Equal: ['=', '+', '≠', '±', 0], + BracketLeft: ['[', '{', '“', '”', 0], + BracketRight: [']', '}', '‘', '’', 0], + Backslash: ['\\', '|', '«', '»', 0], + Semicolon: [';', ':', '…', 'Ú', 0], + Quote: ['\'', '"', 'æ', 'Æ', 0], + Backquote: ['`', '~', '`', '`', 4], + Comma: [',', '<', '≤', '¯', 0], + Period: ['.', '>', '≥', '˘', 0], + Slash: ['/', '?', '÷', '¿', 0], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '/', '/', 0], + NumpadMultiply: ['*', '*', '*', '*', 0], + NumpadSubtract: ['-', '-', '-', '-', 0], + NumpadAdd: ['+', '+', '+', '+', 0], + NumpadEnter: [], + Numpad1: ['1', '1', '1', '1', 0], + Numpad2: ['2', '2', '2', '2', 0], + Numpad3: ['3', '3', '3', '3', 0], + Numpad4: ['4', '4', '4', '4', 0], + Numpad5: ['5', '5', '5', '5', 0], + Numpad6: ['6', '6', '6', '6', 0], + Numpad7: ['7', '7', '7', '7', 0], + Numpad8: ['8', '8', '8', '8', 0], + Numpad9: ['9', '9', '9', '9', 0], + Numpad0: ['0', '0', '0', '0', 0], + NumpadDecimal: ['.', '.', '.', '.', 0], + IntlBackslash: ['§', '±', '§', '±', 0], + ContextMenu: [], + NumpadEqual: ['=', '=', '=', '=', 0], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + AudioVolumeMute: [], + AudioVolumeUp: ['', '=', '', '=', 0], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [] + } +}); \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en.linux.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en.linux.ts new file mode 100644 index 000000000..571e9164e --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en.linux.ts @@ -0,0 +1,190 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { model: 'pc105', layout: 'us', variant: '', options: '', rules: 'evdev', isUSStandard: true }, + secondaryLayouts: [ + { model: 'pc105', layout: 'cn', variant: '', options: '', rules: 'evdev' }, + ], + mapping: { + Sleep: [], + WakeUp: [], + KeyA: ['a', 'A', 'a', 'A', 0], + KeyB: ['b', 'B', 'b', 'B', 0], + KeyC: ['c', 'C', 'c', 'C', 0], + KeyD: ['d', 'D', 'd', 'D', 0], + KeyE: ['e', 'E', 'e', 'E', 0], + KeyF: ['f', 'F', 'f', 'F', 0], + KeyG: ['g', 'G', 'g', 'G', 0], + KeyH: ['h', 'H', 'h', 'H', 0], + KeyI: ['i', 'I', 'i', 'I', 0], + KeyJ: ['j', 'J', 'j', 'J', 0], + KeyK: ['k', 'K', 'k', 'K', 0], + KeyL: ['l', 'L', 'l', 'L', 0], + KeyM: ['m', 'M', 'm', 'M', 0], + KeyN: ['n', 'N', 'n', 'N', 0], + KeyO: ['o', 'O', 'o', 'O', 0], + KeyP: ['p', 'P', 'p', 'P', 0], + KeyQ: ['q', 'Q', 'q', 'Q', 0], + KeyR: ['r', 'R', 'r', 'R', 0], + KeyS: ['s', 'S', 's', 'S', 0], + KeyT: ['t', 'T', 't', 'T', 0], + KeyU: ['u', 'U', 'u', 'U', 0], + KeyV: ['v', 'V', 'v', 'V', 0], + KeyW: ['w', 'W', 'w', 'W', 0], + KeyX: ['x', 'X', 'x', 'X', 0], + KeyY: ['y', 'Y', 'y', 'Y', 0], + KeyZ: ['z', 'Z', 'z', 'Z', 0], + Digit1: ['1', '!', '1', '!', 0], + Digit2: ['2', '@', '2', '@', 0], + Digit3: ['3', '#', '3', '#', 0], + Digit4: ['4', '$', '4', '$', 0], + Digit5: ['5', '%', '5', '%', 0], + Digit6: ['6', '^', '6', '^', 0], + Digit7: ['7', '&', '7', '&', 0], + Digit8: ['8', '*', '8', '*', 0], + Digit9: ['9', '(', '9', '(', 0], + Digit0: ['0', ')', '0', ')', 0], + Enter: ['\r', '\r', '\r', '\r', 0], + Escape: ['\u001b', '\u001b', '\u001b', '\u001b', 0], + Backspace: ['\b', '\b', '\b', '\b', 0], + Tab: ['\t', '', '\t', '', 0], + Space: [' ', ' ', ' ', ' ', 0], + Minus: ['-', '_', '-', '_', 0], + Equal: ['=', '+', '=', '+', 0], + BracketLeft: ['[', '{', '[', '{', 0], + BracketRight: [']', '}', ']', '}', 0], + Backslash: ['\\', '|', '\\', '|', 0], + Semicolon: [';', ':', ';', ':', 0], + Quote: ['\'', '"', '\'', '"', 0], + Backquote: ['`', '~', '`', '~', 0], + Comma: [',', '<', ',', '<', 0], + Period: ['.', '>', '.', '>', 0], + Slash: ['/', '?', '/', '?', 0], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + PrintScreen: [], + ScrollLock: [], + Pause: [], + Insert: [], + Home: [], + PageUp: [], + Delete: ['', '', '', '', 0], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '/', '/', 0], + NumpadMultiply: ['*', '*', '*', '*', 0], + NumpadSubtract: ['-', '-', '-', '-', 0], + NumpadAdd: ['+', '+', '+', '+', 0], + NumpadEnter: ['\r', '\r', '\r', '\r', 0], + Numpad1: ['', '1', '', '1', 0], + Numpad2: ['', '2', '', '2', 0], + Numpad3: ['', '3', '', '3', 0], + Numpad4: ['', '4', '', '4', 0], + Numpad5: ['', '5', '', '5', 0], + Numpad6: ['', '6', '', '6', 0], + Numpad7: ['', '7', '', '7', 0], + Numpad8: ['', '8', '', '8', 0], + Numpad9: ['', '9', '', '9', 0], + Numpad0: ['', '0', '', '0', 0], + NumpadDecimal: ['', '.', '', '.', 0], + IntlBackslash: ['<', '>', '|', '¦', 0], + ContextMenu: [], + Power: [], + NumpadEqual: ['=', '=', '=', '=', 0], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + F21: [], + F22: [], + F23: [], + F24: [], + Open: [], + Help: [], + Select: [], + Again: [], + Undo: [], + Cut: [], + Copy: [], + Paste: [], + Find: [], + AudioVolumeMute: [], + AudioVolumeUp: [], + AudioVolumeDown: [], + NumpadComma: ['.', '.', '.', '.', 0], + IntlRo: [], + KanaMode: [], + IntlYen: [], + Convert: [], + NonConvert: [], + Lang1: [], + Lang2: [], + Lang3: [], + Lang4: [], + Lang5: [], + NumpadParenLeft: ['(', '(', '(', '(', 0], + NumpadParenRight: [')', ')', ')', ')', 0], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [], + BrightnessUp: [], + BrightnessDown: [], + MediaPlay: [], + MediaRecord: [], + MediaFastForward: [], + MediaRewind: [], + MediaTrackNext: [], + MediaTrackPrevious: [], + MediaStop: [], + Eject: [], + MediaPlayPause: [], + MediaSelect: [], + LaunchMail: [], + LaunchApp2: [], + LaunchApp1: [], + SelectTask: [], + LaunchScreenSaver: [], + BrowserSearch: [], + BrowserHome: [], + BrowserBack: [], + BrowserForward: [], + BrowserStop: [], + BrowserRefresh: [], + BrowserFavorites: [], + MailReply: [], + MailForward: [], + MailSend: [] + } + +}); diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en.win.ts new file mode 100644 index 000000000..3d6845dc0 --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/en.win.ts @@ -0,0 +1,174 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { name: '00000409', id: '', text: 'US', isUSStandard: true }, + secondaryLayouts: [ + { name: '00000804', id: '', text: 'Chinese (Simplified) - US Keyboard' }, + { name: '00000411', id: '', text: 'Japanese' }, + { name: '00000412', id: '', text: 'Korean' }, + { name: '00000404', id: '', text: 'Chinese (Traditional) - US Keyboard' } + ], + mapping: { + Sleep: [], + WakeUp: [], + KeyA: ['a', 'A', '', '', 0, 'VK_A'], + KeyB: ['b', 'B', '', '', 0, 'VK_B'], + KeyC: ['c', 'C', '', '', 0, 'VK_C'], + KeyD: ['d', 'D', '', '', 0, 'VK_D'], + KeyE: ['e', 'E', '', '', 0, 'VK_E'], + KeyF: ['f', 'F', '', '', 0, 'VK_F'], + KeyG: ['g', 'G', '', '', 0, 'VK_G'], + KeyH: ['h', 'H', '', '', 0, 'VK_H'], + KeyI: ['i', 'I', '', '', 0, 'VK_I'], + KeyJ: ['j', 'J', '', '', 0, 'VK_J'], + KeyK: ['k', 'K', '', '', 0, 'VK_K'], + KeyL: ['l', 'L', '', '', 0, 'VK_L'], + KeyM: ['m', 'M', '', '', 0, 'VK_M'], + KeyN: ['n', 'N', '', '', 0, 'VK_N'], + KeyO: ['o', 'O', '', '', 0, 'VK_O'], + KeyP: ['p', 'P', '', '', 0, 'VK_P'], + KeyQ: ['q', 'Q', '', '', 0, 'VK_Q'], + KeyR: ['r', 'R', '', '', 0, 'VK_R'], + KeyS: ['s', 'S', '', '', 0, 'VK_S'], + KeyT: ['t', 'T', '', '', 0, 'VK_T'], + KeyU: ['u', 'U', '', '', 0, 'VK_U'], + KeyV: ['v', 'V', '', '', 0, 'VK_V'], + KeyW: ['w', 'W', '', '', 0, 'VK_W'], + KeyX: ['x', 'X', '', '', 0, 'VK_X'], + KeyY: ['y', 'Y', '', '', 0, 'VK_Y'], + KeyZ: ['z', 'Z', '', '', 0, 'VK_Z'], + Digit1: ['1', '!', '', '', 0, 'VK_1'], + Digit2: ['2', '@', '', '', 0, 'VK_2'], + Digit3: ['3', '#', '', '', 0, 'VK_3'], + Digit4: ['4', '$', '', '', 0, 'VK_4'], + Digit5: ['5', '%', '', '', 0, 'VK_5'], + Digit6: ['6', '^', '', '', 0, 'VK_6'], + Digit7: ['7', '&', '', '', 0, 'VK_7'], + Digit8: ['8', '*', '', '', 0, 'VK_8'], + Digit9: ['9', '(', '', '', 0, 'VK_9'], + Digit0: ['0', ')', '', '', 0, 'VK_0'], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', '', '', 0, 'VK_SPACE'], + Minus: ['-', '_', '', '', 0, 'VK_OEM_MINUS'], + Equal: ['=', '+', '', '', 0, 'VK_OEM_PLUS'], + BracketLeft: ['[', '{', '', '', 0, 'VK_OEM_4'], + BracketRight: [']', '}', '', '', 0, 'VK_OEM_6'], + Backslash: ['\\', '|', '', '', 0, 'VK_OEM_5'], + Semicolon: [';', ':', '', '', 0, 'VK_OEM_1'], + Quote: ['\'', '"', '', '', 0, 'VK_OEM_7'], + Backquote: ['`', '~', '', '', 0, 'VK_OEM_3'], + Comma: [',', '<', '', '', 0, 'VK_OEM_COMMA'], + Period: ['.', '>', '', '', 0, 'VK_OEM_PERIOD'], + Slash: ['/', '?', '', '', 0, 'VK_OEM_2'], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + PrintScreen: [], + ScrollLock: [], + Pause: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '', '', 0, 'VK_DIVIDE'], + NumpadMultiply: ['*', '*', '', '', 0, 'VK_MULTIPLY'], + NumpadSubtract: ['-', '-', '', '', 0, 'VK_SUBTRACT'], + NumpadAdd: ['+', '+', '', '', 0, 'VK_ADD'], + NumpadEnter: [], + Numpad1: [], + Numpad2: [], + Numpad3: [], + Numpad4: [], + Numpad5: [], + Numpad6: [], + Numpad7: [], + Numpad8: [], + Numpad9: [], + Numpad0: [], + NumpadDecimal: [], + IntlBackslash: ['\\', '|', '', '', 0, 'VK_OEM_102'], + ContextMenu: [], + Power: [], + NumpadEqual: [], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + F21: [], + F22: [], + F23: [], + F24: [], + Help: [], + Undo: [], + Cut: [], + Copy: [], + Paste: [], + AudioVolumeMute: [], + AudioVolumeUp: [], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + Convert: [], + NonConvert: [], + Lang1: [], + Lang2: [], + Lang3: [], + Lang4: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [], + MediaTrackNext: [], + MediaTrackPrevious: [], + MediaStop: [], + Eject: [], + MediaPlayPause: [], + MediaSelect: [], + LaunchMail: [], + LaunchApp2: [], + LaunchApp1: [], + BrowserSearch: [], + BrowserHome: [], + BrowserBack: [], + BrowserForward: [], + BrowserStop: [], + BrowserRefresh: [], + BrowserFavorites: [] + } +}); \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/es-latin.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/es-latin.win.ts new file mode 100644 index 000000000..16531eda2 --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/es-latin.win.ts @@ -0,0 +1,170 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { name: '0000080A', id: '', text: 'Latin American' }, + secondaryLayouts: [], + mapping: { + Sleep: [], + WakeUp: [], + KeyA: ['a', 'A', '', '', 0, 'VK_A'], + KeyB: ['b', 'B', '', '', 0, 'VK_B'], + KeyC: ['c', 'C', '', '', 0, 'VK_C'], + KeyD: ['d', 'D', '', '', 0, 'VK_D'], + KeyE: ['e', 'E', '', '', 0, 'VK_E'], + KeyF: ['f', 'F', '', '', 0, 'VK_F'], + KeyG: ['g', 'G', '', '', 0, 'VK_G'], + KeyH: ['h', 'H', '', '', 0, 'VK_H'], + KeyI: ['i', 'I', '', '', 0, 'VK_I'], + KeyJ: ['j', 'J', '', '', 0, 'VK_J'], + KeyK: ['k', 'K', '', '', 0, 'VK_K'], + KeyL: ['l', 'L', '', '', 0, 'VK_L'], + KeyM: ['m', 'M', '', '', 0, 'VK_M'], + KeyN: ['n', 'N', '', '', 0, 'VK_N'], + KeyO: ['o', 'O', '', '', 0, 'VK_O'], + KeyP: ['p', 'P', '', '', 0, 'VK_P'], + KeyQ: ['q', 'Q', '@', '', 0, 'VK_Q'], + KeyR: ['r', 'R', '', '', 0, 'VK_R'], + KeyS: ['s', 'S', '', '', 0, 'VK_S'], + KeyT: ['t', 'T', '', '', 0, 'VK_T'], + KeyU: ['u', 'U', '', '', 0, 'VK_U'], + KeyV: ['v', 'V', '', '', 0, 'VK_V'], + KeyW: ['w', 'W', '', '', 0, 'VK_W'], + KeyX: ['x', 'X', '', '', 0, 'VK_X'], + KeyY: ['y', 'Y', '', '', 0, 'VK_Y'], + KeyZ: ['z', 'Z', '', '', 0, 'VK_Z'], + Digit1: ['1', '!', '', '', 0, 'VK_1'], + Digit2: ['2', '"', '', '', 0, 'VK_2'], + Digit3: ['3', '#', '', '', 0, 'VK_3'], + Digit4: ['4', '$', '', '', 0, 'VK_4'], + Digit5: ['5', '%', '', '', 0, 'VK_5'], + Digit6: ['6', '&', '', '', 0, 'VK_6'], + Digit7: ['7', '/', '', '', 0, 'VK_7'], + Digit8: ['8', '(', '', '', 0, 'VK_8'], + Digit9: ['9', ')', '', '', 0, 'VK_9'], + Digit0: ['0', '=', '', '', 0, 'VK_0'], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', '', '', 0, 'VK_SPACE'], + Minus: ['\'', '?', '\\', '', 0, 'VK_OEM_4'], + Equal: ['¿', '¡', '', '', 0, 'VK_OEM_6'], + BracketLeft: ['´', '¨', '', '', 0, 'VK_OEM_1'], + BracketRight: ['+', '*', '~', '', 0, 'VK_OEM_PLUS'], + Backslash: ['}', ']', '`', '', 0, 'VK_OEM_2'], + Semicolon: ['ñ', 'Ñ', '', '', 0, 'VK_OEM_3'], + Quote: ['{', '[', '^', '', 0, 'VK_OEM_7'], + Backquote: ['|', '°', '¬', '', 0, 'VK_OEM_5'], + Comma: [',', ';', '', '', 0, 'VK_OEM_COMMA'], + Period: ['.', ':', '', '', 0, 'VK_OEM_PERIOD'], + Slash: ['-', '_', '', '', 0, 'VK_OEM_MINUS'], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + PrintScreen: [], + ScrollLock: [], + Pause: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '', '', 0, 'VK_DIVIDE'], + NumpadMultiply: ['*', '*', '', '', 0, 'VK_MULTIPLY'], + NumpadSubtract: ['-', '-', '', '', 0, 'VK_SUBTRACT'], + NumpadAdd: ['+', '+', '', '', 0, 'VK_ADD'], + NumpadEnter: [], + Numpad1: [], + Numpad2: [], + Numpad3: [], + Numpad4: [], + Numpad5: [], + Numpad6: [], + Numpad7: [], + Numpad8: [], + Numpad9: [], + Numpad0: [], + NumpadDecimal: [], + IntlBackslash: ['<', '>', '', '', 0, 'VK_OEM_102'], + ContextMenu: [], + Power: [], + NumpadEqual: [], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + F21: [], + F22: [], + F23: [], + F24: [], + Help: [], + Undo: [], + Cut: [], + Copy: [], + Paste: [], + AudioVolumeMute: [], + AudioVolumeUp: [], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + Convert: [], + NonConvert: [], + Lang1: [], + Lang2: [], + Lang3: [], + Lang4: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [], + MediaTrackNext: [], + MediaTrackPrevious: [], + MediaStop: [], + Eject: [], + MediaPlayPause: [], + MediaSelect: [], + LaunchMail: [], + LaunchApp2: [], + LaunchApp1: [], + BrowserSearch: [], + BrowserHome: [], + BrowserBack: [], + BrowserForward: [], + BrowserStop: [], + BrowserRefresh: [], + BrowserFavorites: [] + } + +}); \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/es.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/es.darwin.ts new file mode 100644 index 000000000..679dfb36d --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/es.darwin.ts @@ -0,0 +1,132 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { id: 'com.apple.keylayout.Spanish-ISO', lang: 'es', localizedName: 'Spanish - ISO' }, + secondaryLayouts: [], + mapping: { + KeyA: ['a', 'A', 'å', 'Å', 0], + KeyB: ['b', 'B', 'ß', '', 0], + KeyC: ['c', 'C', '©', ' ', 0], + KeyD: ['d', 'D', '∂', '∆', 0], + KeyE: ['e', 'E', '€', '€', 0], + KeyF: ['f', 'F', 'ƒ', 'fi', 0], + KeyG: ['g', 'G', '', 'fl', 0], + KeyH: ['h', 'H', '™', ' ', 0], + KeyI: ['i', 'I', ' ', ' ', 0], + KeyJ: ['j', 'J', '¶', '¯', 0], + KeyK: ['k', 'K', '§', 'ˇ', 0], + KeyL: ['l', 'L', ' ', '˘', 0], + KeyM: ['m', 'M', 'µ', '˚', 0], + KeyN: ['n', 'N', ' ', '˙', 0], + KeyO: ['o', 'O', 'ø', 'Ø', 0], + KeyP: ['p', 'P', 'π', '∏', 0], + KeyQ: ['q', 'Q', 'œ', 'Œ', 0], + KeyR: ['r', 'R', '®', ' ', 0], + KeyS: ['s', 'S', '∫', ' ', 0], + KeyT: ['t', 'T', '†', '‡', 0], + KeyU: ['u', 'U', ' ', ' ', 0], + KeyV: ['v', 'V', '√', '◊', 0], + KeyW: ['w', 'W', 'æ', 'Æ', 0], + KeyX: ['x', 'X', '∑', '›', 0], + KeyY: ['y', 'Y', '¥', ' ', 0], + KeyZ: ['z', 'Z', 'Ω', '‹', 0], + Digit1: ['1', '!', '|', 'ı', 0], + Digit2: ['2', '"', '@', '˝', 0], + Digit3: ['3', '·', '#', '•', 0], + Digit4: ['4', '$', '¢', '£', 0], + Digit5: ['5', '%', '∞', '‰', 0], + Digit6: ['6', '&', '¬', ' ', 0], + Digit7: ['7', '/', '÷', '⁄', 0], + Digit8: ['8', '(', '“', '‘', 0], + Digit9: ['9', ')', '”', '’', 0], + Digit0: ['0', '=', '≠', '≈', 0], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', ' ', ' ', 0], + Minus: ['\'', '?', '´', '¸', 0], + Equal: ['¡', '¿', '‚', '˛', 0], + BracketLeft: ['`', '^', '[', 'ˆ', 3], + BracketRight: ['+', '*', ']', '±', 0], + Backslash: ['ç', 'Ç', '}', '»', 0], + Semicolon: ['ñ', 'Ñ', '~', '˜', 4], + Quote: ['´', '¨', '{', '«', 3], + Backquote: ['<', '>', '≤', '≥', 0], + Comma: [',', ';', '„', '', 0], + Period: ['.', ':', '…', '…', 0], + Slash: ['-', '_', '–', '—', 0], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '/', '/', 0], + NumpadMultiply: ['*', '*', '*', '*', 0], + NumpadSubtract: ['-', '-', '-', '-', 0], + NumpadAdd: ['+', '+', '+', '+', 0], + NumpadEnter: [], + Numpad1: ['1', '1', '1', '1', 0], + Numpad2: ['2', '2', '2', '2', 0], + Numpad3: ['3', '3', '3', '3', 0], + Numpad4: ['4', '4', '4', '4', 0], + Numpad5: ['5', '5', '5', '5', 0], + Numpad6: ['6', '6', '6', '6', 0], + Numpad7: ['7', '7', '7', '7', 0], + Numpad8: ['8', '8', '8', '8', 0], + Numpad9: ['9', '9', '9', '9', 0], + Numpad0: ['0', '0', '0', '0', 0], + NumpadDecimal: [',', ',', ',', ',', 0], + IntlBackslash: ['º', 'ª', '\\', '°', 0], + ContextMenu: [], + NumpadEqual: ['=', '=', '=', '=', 0], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + AudioVolumeMute: [], + AudioVolumeUp: ['', '=', '', '=', 0], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [] + } +}); \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/es.linux.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/es.linux.ts new file mode 100644 index 000000000..8fcff46f8 --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/es.linux.ts @@ -0,0 +1,187 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { model: 'pc105', layout: 'es', variant: '', options: '', rules: 'evdev' }, + secondaryLayouts: [], + mapping: { + Sleep: [], + WakeUp: [], + KeyA: ['a', 'A', 'æ', 'Æ', 0], + KeyB: ['b', 'B', '”', '’', 0], + KeyC: ['c', 'C', '¢', '©', 0], + KeyD: ['d', 'D', 'ð', 'Ð', 0], + KeyE: ['e', 'E', '€', '¢', 0], + KeyF: ['f', 'F', 'đ', 'ª', 0], + KeyG: ['g', 'G', 'ŋ', 'Ŋ', 0], + KeyH: ['h', 'H', 'ħ', 'Ħ', 0], + KeyI: ['i', 'I', '→', 'ı', 0], + KeyJ: ['j', 'J', '̉', '̛', 0], + KeyK: ['k', 'K', 'ĸ', '&', 0], + KeyL: ['l', 'L', 'ł', 'Ł', 0], + KeyM: ['m', 'M', 'µ', 'º', 0], + KeyN: ['n', 'N', 'n', 'N', 0], + KeyO: ['o', 'O', 'ø', 'Ø', 0], + KeyP: ['p', 'P', 'þ', 'Þ', 0], + KeyQ: ['q', 'Q', '@', 'Ω', 0], + KeyR: ['r', 'R', '¶', '®', 0], + KeyS: ['s', 'S', 'ß', '§', 0], + KeyT: ['t', 'T', 'ŧ', 'Ŧ', 0], + KeyU: ['u', 'U', '↓', '↑', 0], + KeyV: ['v', 'V', '“', '‘', 0], + KeyW: ['w', 'W', 'ł', 'Ł', 0], + KeyX: ['x', 'X', '»', '>', 0], + KeyY: ['y', 'Y', '←', '¥', 0], + KeyZ: ['z', 'Z', '«', '<', 0], + Digit1: ['1', '!', '|', '¡', 0], + Digit2: ['2', '"', '@', '⅛', 0], + Digit3: ['3', '·', '#', '£', 0], + Digit4: ['4', '$', '~', '$', 0], + Digit5: ['5', '%', '½', '⅜', 0], + Digit6: ['6', '&', '¬', '⅝', 0], + Digit7: ['7', '/', '{', '⅞', 0], + Digit8: ['8', '(', '[', '™', 0], + Digit9: ['9', ')', ']', '±', 0], + Digit0: ['0', '=', '}', '°', 0], + Enter: ['\r', '\r', '\r', '\r', 0], + Escape: ['\u001b', '\u001b', '\u001b', '\u001b', 0], + Backspace: ['\b', '\b', '\b', '\b', 0], + Tab: ['\t', '', '\t', '', 0], + Space: [' ', ' ', ' ', ' ', 0], + Minus: ['\'', '?', '\\', '¿', 0], + Equal: ['¡', '¿', '̃', '~', 0], + BracketLeft: ['̀', '̂', '[', '̊', 0], + BracketRight: ['+', '*', ']', '̄', 0], + Backslash: ['ç', 'Ç', '}', '̆', 0], + Semicolon: ['ñ', 'Ñ', '~', '̋', 0], + Quote: ['́', '̈', '{', '{', 0], + Backquote: ['º', 'ª', '\\', '\\', 0], + Comma: [',', ';', '─', '×', 0], + Period: ['.', ':', '·', '÷', 0], + Slash: ['-', '_', '̣', '̇', 0], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + PrintScreen: [], + ScrollLock: [], + Pause: [], + Insert: [], + Home: [], + PageUp: [], + Delete: ['', '', '', '', 0], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '/', '/', 0], + NumpadMultiply: ['*', '*', '*', '*', 0], + NumpadSubtract: ['-', '-', '-', '-', 0], + NumpadAdd: ['+', '+', '+', '+', 0], + NumpadEnter: ['\r', '\r', '\r', '\r', 0], + Numpad1: ['', '1', '', '1', 0], + Numpad2: ['', '2', '', '2', 0], + Numpad3: ['', '3', '', '3', 0], + Numpad4: ['', '4', '', '4', 0], + Numpad5: ['', '5', '', '5', 0], + Numpad6: ['', '6', '', '6', 0], + Numpad7: ['', '7', '', '7', 0], + Numpad8: ['', '8', '', '8', 0], + Numpad9: ['', '9', '', '9', 0], + Numpad0: ['', '0', '', '0', 0], + NumpadDecimal: ['', '.', '', '.', 0], + IntlBackslash: ['<', '>', '|', '¦', 0], + ContextMenu: [], + Power: [], + NumpadEqual: ['=', '=', '=', '=', 0], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + F21: [], + F22: [], + F23: [], + F24: [], + Open: [], + Help: [], + Select: [], + Again: [], + Undo: [], + Cut: [], + Copy: [], + Paste: [], + Find: [], + AudioVolumeMute: [], + AudioVolumeUp: [], + AudioVolumeDown: [], + NumpadComma: ['.', '.', '.', '.', 0], + IntlRo: [], + KanaMode: [], + IntlYen: [], + Convert: [], + NonConvert: [], + Lang1: [], + Lang2: [], + Lang3: [], + Lang4: [], + Lang5: [], + NumpadParenLeft: ['(', '(', '(', '(', 0], + NumpadParenRight: [')', ')', ')', ')', 0], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [], + BrightnessUp: [], + BrightnessDown: [], + MediaPlay: [], + MediaRecord: [], + MediaFastForward: [], + MediaRewind: [], + MediaTrackNext: [], + MediaTrackPrevious: [], + MediaStop: [], + Eject: [], + MediaPlayPause: [], + MediaSelect: [], + LaunchMail: [], + LaunchApp2: [], + LaunchApp1: [], + SelectTask: [], + LaunchScreenSaver: [], + BrowserSearch: [], + BrowserHome: [], + BrowserBack: [], + BrowserForward: [], + BrowserStop: [], + BrowserRefresh: [], + BrowserFavorites: [], + MailReply: [], + MailForward: [], + MailSend: [] + } +}); \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/es.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/es.win.ts new file mode 100644 index 000000000..3ac96a5dc --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/es.win.ts @@ -0,0 +1,169 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { name: '0000040A', id: '', text: 'Spanish' }, + secondaryLayouts: [], + mapping: { + Sleep: [], + WakeUp: [], + KeyA: ['a', 'A', '', '', 0, 'VK_A'], + KeyB: ['b', 'B', '', '', 0, 'VK_B'], + KeyC: ['c', 'C', '', '', 0, 'VK_C'], + KeyD: ['d', 'D', '', '', 0, 'VK_D'], + KeyE: ['e', 'E', '€', '', 0, 'VK_E'], + KeyF: ['f', 'F', '', '', 0, 'VK_F'], + KeyG: ['g', 'G', '', '', 0, 'VK_G'], + KeyH: ['h', 'H', '', '', 0, 'VK_H'], + KeyI: ['i', 'I', '', '', 0, 'VK_I'], + KeyJ: ['j', 'J', '', '', 0, 'VK_J'], + KeyK: ['k', 'K', '', '', 0, 'VK_K'], + KeyL: ['l', 'L', '', '', 0, 'VK_L'], + KeyM: ['m', 'M', '', '', 0, 'VK_M'], + KeyN: ['n', 'N', '', '', 0, 'VK_N'], + KeyO: ['o', 'O', '', '', 0, 'VK_O'], + KeyP: ['p', 'P', '', '', 0, 'VK_P'], + KeyQ: ['q', 'Q', '', '', 0, 'VK_Q'], + KeyR: ['r', 'R', '', '', 0, 'VK_R'], + KeyS: ['s', 'S', '', '', 0, 'VK_S'], + KeyT: ['t', 'T', '', '', 0, 'VK_T'], + KeyU: ['u', 'U', '', '', 0, 'VK_U'], + KeyV: ['v', 'V', '', '', 0, 'VK_V'], + KeyW: ['w', 'W', '', '', 0, 'VK_W'], + KeyX: ['x', 'X', '', '', 0, 'VK_X'], + KeyY: ['y', 'Y', '', '', 0, 'VK_Y'], + KeyZ: ['z', 'Z', '', '', 0, 'VK_Z'], + Digit1: ['1', '!', '|', '', 0, 'VK_1'], + Digit2: ['2', '"', '@', '', 0, 'VK_2'], + Digit3: ['3', '·', '#', '', 0, 'VK_3'], + Digit4: ['4', '$', '~', '', 0, 'VK_4'], + Digit5: ['5', '%', '€', '', 0, 'VK_5'], + Digit6: ['6', '&', '¬', '', 0, 'VK_6'], + Digit7: ['7', '/', '', '', 0, 'VK_7'], + Digit8: ['8', '(', '', '', 0, 'VK_8'], + Digit9: ['9', ')', '', '', 0, 'VK_9'], + Digit0: ['0', '=', '', '', 0, 'VK_0'], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', '', '', 0, 'VK_SPACE'], + Minus: ['\'', '?', '', '', 0, 'VK_OEM_4'], + Equal: ['¡', '¿', '', '', 0, 'VK_OEM_6'], + BracketLeft: ['`', '^', '[', '', 0, 'VK_OEM_1'], + BracketRight: ['+', '*', ']', '', 0, 'VK_OEM_PLUS'], + Backslash: ['ç', 'Ç', '}', '', 0, 'VK_OEM_2'], + Semicolon: ['ñ', 'Ñ', '', '', 0, 'VK_OEM_3'], + Quote: ['´', '¨', '{', '', 0, 'VK_OEM_7'], + Backquote: ['º', 'ª', '\\', '', 0, 'VK_OEM_5'], + Comma: [',', ';', '', '', 0, 'VK_OEM_COMMA'], + Period: ['.', ':', '', '', 0, 'VK_OEM_PERIOD'], + Slash: ['-', '_', '', '', 0, 'VK_OEM_MINUS'], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + PrintScreen: [], + ScrollLock: [], + Pause: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '', '', 0, 'VK_DIVIDE'], + NumpadMultiply: ['*', '*', '', '', 0, 'VK_MULTIPLY'], + NumpadSubtract: ['-', '-', '', '', 0, 'VK_SUBTRACT'], + NumpadAdd: ['+', '+', '', '', 0, 'VK_ADD'], + NumpadEnter: [], + Numpad1: [], + Numpad2: [], + Numpad3: [], + Numpad4: [], + Numpad5: [], + Numpad6: [], + Numpad7: [], + Numpad8: [], + Numpad9: [], + Numpad0: [], + NumpadDecimal: [], + IntlBackslash: ['<', '>', '', '', 0, 'VK_OEM_102'], + ContextMenu: [], + Power: [], + NumpadEqual: [], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + F21: [], + F22: [], + F23: [], + F24: [], + Help: [], + Undo: [], + Cut: [], + Copy: [], + Paste: [], + AudioVolumeMute: [], + AudioVolumeUp: [], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + Convert: [], + NonConvert: [], + Lang1: [], + Lang2: [], + Lang3: [], + Lang4: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [], + MediaTrackNext: [], + MediaTrackPrevious: [], + MediaStop: [], + Eject: [], + MediaPlayPause: [], + MediaSelect: [], + LaunchMail: [], + LaunchApp2: [], + LaunchApp1: [], + BrowserSearch: [], + BrowserHome: [], + BrowserBack: [], + BrowserForward: [], + BrowserStop: [], + BrowserRefresh: [], + BrowserFavorites: [] + } +}); \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/fr.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/fr.darwin.ts new file mode 100644 index 000000000..fa9198b64 --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/fr.darwin.ts @@ -0,0 +1,132 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { id: 'com.apple.keylayout.French', lang: 'fr', localizedName: 'French' }, + secondaryLayouts: [], + mapping: { + KeyA: ['q', 'Q', '‡', 'Ω', 0], + KeyB: ['b', 'B', 'ß', '∫', 0], + KeyC: ['c', 'C', '©', '¢', 0], + KeyD: ['d', 'D', '∂', '∆', 0], + KeyE: ['e', 'E', 'ê', 'Ê', 0], + KeyF: ['f', 'F', 'ƒ', '·', 0], + KeyG: ['g', 'G', 'fi', 'fl', 0], + KeyH: ['h', 'H', 'Ì', 'Î', 0], + KeyI: ['i', 'I', 'î', 'ï', 0], + KeyJ: ['j', 'J', 'Ï', 'Í', 0], + KeyK: ['k', 'K', 'È', 'Ë', 0], + KeyL: ['l', 'L', '¬', '|', 0], + KeyM: [',', '?', '∞', '¿', 0], + KeyN: ['n', 'N', '~', 'ı', 4], + KeyO: ['o', 'O', 'œ', 'Œ', 0], + KeyP: ['p', 'P', 'π', '∏', 0], + KeyQ: ['a', 'A', 'æ', 'Æ', 0], + KeyR: ['r', 'R', '®', '‚', 0], + KeyS: ['s', 'S', 'Ò', '∑', 0], + KeyT: ['t', 'T', '†', '™', 0], + KeyU: ['u', 'U', 'º', 'ª', 0], + KeyV: ['v', 'V', '◊', '√', 0], + KeyW: ['z', 'Z', 'Â', 'Å', 0], + KeyX: ['x', 'X', '≈', '⁄', 0], + KeyY: ['y', 'Y', 'Ú', 'Ÿ', 0], + KeyZ: ['w', 'W', '‹', '›', 0], + Digit1: ['&', '1', '', '´', 8], + Digit2: ['é', '2', 'ë', '„', 0], + Digit3: ['"', '3', '“', '”', 0], + Digit4: ['\'', '4', '‘', '’', 0], + Digit5: ['(', '5', '{', '[', 0], + Digit6: ['§', '6', '¶', 'å', 0], + Digit7: ['è', '7', '«', '»', 0], + Digit8: ['!', '8', '¡', 'Û', 0], + Digit9: ['ç', '9', 'Ç', 'Á', 0], + Digit0: ['à', '0', 'ø', 'Ø', 0], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', ' ', ' ', 0], + Minus: [')', '°', '}', ']', 0], + Equal: ['-', '_', '—', '–', 0], + BracketLeft: ['^', '¨', 'ô', 'Ô', 3], + BracketRight: ['$', '*', '€', '¥', 0], + Backslash: ['`', '£', '@', '#', 1], + Semicolon: ['m', 'M', 'µ', 'Ó', 0], + Quote: ['ù', '%', 'Ù', '‰', 0], + Backquote: ['<', '>', '≤', '≥', 0], + Comma: [';', '.', '…', '•', 0], + Period: [':', '/', '÷', '\\', 0], + Slash: ['=', '+', '≠', '±', 0], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '/', '/', 0], + NumpadMultiply: ['*', '*', '*', '*', 0], + NumpadSubtract: ['-', '-', '-', '-', 0], + NumpadAdd: ['+', '+', '+', '+', 0], + NumpadEnter: [], + Numpad1: ['1', '1', '1', '1', 0], + Numpad2: ['2', '2', '2', '2', 0], + Numpad3: ['3', '3', '3', '3', 0], + Numpad4: ['4', '4', '4', '4', 0], + Numpad5: ['5', '5', '5', '5', 0], + Numpad6: ['6', '6', '6', '6', 0], + Numpad7: ['7', '7', '7', '7', 0], + Numpad8: ['8', '8', '8', '8', 0], + Numpad9: ['9', '9', '9', '9', 0], + Numpad0: ['0', '0', '0', '0', 0], + NumpadDecimal: [',', '.', ',', '.', 0], + IntlBackslash: ['@', '#', '•', 'Ÿ', 0], + ContextMenu: [], + NumpadEqual: ['=', '=', '=', '=', 0], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + AudioVolumeMute: [], + AudioVolumeUp: ['', '=', '', '=', 0], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [] + } +}); diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/fr.linux.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/fr.linux.ts new file mode 100644 index 000000000..dc9488f28 --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/fr.linux.ts @@ -0,0 +1,187 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { model: 'pc104', layout: 'fr', variant: '', options: '', rules: 'base' }, + secondaryLayouts: [], + mapping: { + Sleep: [], + WakeUp: [], + KeyA: ['q', 'Q', '@', 'Ω', 0], + KeyB: ['b', 'B', '”', '’', 0], + KeyC: ['c', 'C', '¢', '©', 0], + KeyD: ['d', 'D', 'ð', 'Ð', 0], + KeyE: ['e', 'E', '€', '¢', 0], + KeyF: ['f', 'F', 'đ', 'ª', 0], + KeyG: ['g', 'G', 'ŋ', 'Ŋ', 0], + KeyH: ['h', 'H', 'ħ', 'Ħ', 0], + KeyI: ['i', 'I', '→', 'ı', 0], + KeyJ: ['j', 'J', '̉', '̛', 0], + KeyK: ['k', 'K', 'ĸ', '&', 0], + KeyL: ['l', 'L', 'ł', 'Ł', 0], + KeyM: [',', '?', '́', '̋', 0], + KeyN: ['n', 'N', 'n', 'N', 0], + KeyO: ['o', 'O', 'ø', 'Ø', 0], + KeyP: ['p', 'P', 'þ', 'Þ', 0], + KeyQ: ['a', 'A', 'æ', 'Æ', 0], + KeyR: ['r', 'R', '¶', '®', 0], + KeyS: ['s', 'S', 'ß', '§', 0], + KeyT: ['t', 'T', 'ŧ', 'Ŧ', 0], + KeyU: ['u', 'U', '↓', '↑', 0], + KeyV: ['v', 'V', '“', '‘', 0], + KeyW: ['z', 'Z', '«', '<', 0], + KeyX: ['x', 'X', '»', '>', 0], + KeyY: ['y', 'Y', '←', '¥', 0], + KeyZ: ['w', 'W', 'ł', 'Ł', 0], + Digit1: ['&', '1', '¹', '¡', 0], + Digit2: ['é', '2', '~', '⅛', 0], + Digit3: ['"', '3', '#', '£', 0], + Digit4: ['\'', '4', '{', '$', 0], + Digit5: ['(', '5', '[', '⅜', 0], + Digit6: ['-', '6', '|', '⅝', 0], + Digit7: ['è', '7', '`', '⅞', 0], + Digit8: ['_', '8', '\\', '™', 0], + Digit9: ['ç', '9', '^', '±', 0], + Digit0: ['à', '0', '@', '°', 0], + Enter: ['\r', '\r', '\r', '\r', 0], + Escape: ['\u001b', '\u001b', '\u001b', '\u001b', 0], + Backspace: ['\b', '\b', '\b', '\b', 0], + Tab: ['\t', '', '\t', '', 0], + Space: [' ', ' ', ' ', ' ', 0], + Minus: [')', '°', ']', '¿', 0], + Equal: ['=', '+', '}', '̨', 0], + BracketLeft: ['̂', '̈', '̈', '̊', 0], + BracketRight: ['$', '£', '¤', '̄', 0], + Backslash: ['*', 'µ', '̀', '̆', 0], + Semicolon: ['m', 'M', 'µ', 'º', 0], + Quote: ['ù', '%', '̂', '̌', 0], + Backquote: ['²', '~', '¬', '¬', 0], + Comma: [';', '.', '─', '×', 0], + Period: [':', '/', '·', '÷', 0], + Slash: ['!', '§', '̣', '̇', 0], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + PrintScreen: ['', '', '', '', 0], + ScrollLock: [], + Pause: [], + Insert: [], + Home: [], + PageUp: ['/', '/', '/', '/', 0], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: [], + NumpadMultiply: ['*', '*', '*', '*', 0], + NumpadSubtract: ['-', '-', '-', '-', 0], + NumpadAdd: ['+', '+', '+', '+', 0], + NumpadEnter: [], + Numpad1: ['', '1', '', '1', 0], + Numpad2: ['', '2', '', '2', 0], + Numpad3: ['', '3', '', '3', 0], + Numpad4: ['', '4', '', '4', 0], + Numpad5: ['', '5', '', '5', 0], + Numpad6: ['', '6', '', '6', 0], + Numpad7: ['', '7', '', '7', 0], + Numpad8: ['', '8', '', '8', 0], + Numpad9: ['', '9', '', '9', 0], + Numpad0: ['', '0', '', '0', 0], + NumpadDecimal: ['', '.', '', '.', 0], + IntlBackslash: ['<', '>', '|', '¦', 0], + ContextMenu: [], + Power: [], + NumpadEqual: [], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + F21: [], + F22: [], + F23: [], + F24: [], + Open: [], + Help: [], + Select: [], + Again: [], + Undo: [], + Cut: [], + Copy: [], + Paste: [], + Find: [], + AudioVolumeMute: [], + AudioVolumeUp: [], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + Convert: [], + NonConvert: [], + Lang1: [], + Lang2: [], + Lang3: [], + Lang4: [], + Lang5: [], + NumpadParenLeft: [], + NumpadParenRight: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: ['\r', '\r', '\r', '\r', 0], + MetaRight: ['.', '.', '.', '.', 0], + BrightnessUp: [], + BrightnessDown: [], + MediaPlay: [], + MediaRecord: [], + MediaFastForward: [], + MediaRewind: [], + MediaTrackNext: [], + MediaTrackPrevious: [], + MediaStop: [], + Eject: [], + MediaPlayPause: [], + MediaSelect: [], + LaunchMail: [], + LaunchApp2: [], + LaunchApp1: [], + SelectTask: [], + LaunchScreenSaver: [], + BrowserSearch: [], + BrowserHome: [], + BrowserBack: [], + BrowserForward: [], + BrowserStop: [], + BrowserRefresh: [], + BrowserFavorites: [], + MailReply: [], + MailForward: [], + MailSend: [] + } +}); diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/fr.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/fr.win.ts new file mode 100644 index 000000000..c9f032d7b --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/fr.win.ts @@ -0,0 +1,169 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { name: '0000040C', id: '', text: 'French' }, + secondaryLayouts: [], + mapping: { + Sleep: [], + WakeUp: [], + KeyA: ['q', 'Q', '', '', 0, 'VK_Q'], + KeyB: ['b', 'B', '', '', 0, 'VK_B'], + KeyC: ['c', 'C', '', '', 0, 'VK_C'], + KeyD: ['d', 'D', '', '', 0, 'VK_D'], + KeyE: ['e', 'E', '€', '', 0, 'VK_E'], + KeyF: ['f', 'F', '', '', 0, 'VK_F'], + KeyG: ['g', 'G', '', '', 0, 'VK_G'], + KeyH: ['h', 'H', '', '', 0, 'VK_H'], + KeyI: ['i', 'I', '', '', 0, 'VK_I'], + KeyJ: ['j', 'J', '', '', 0, 'VK_J'], + KeyK: ['k', 'K', '', '', 0, 'VK_K'], + KeyL: ['l', 'L', '', '', 0, 'VK_L'], + KeyM: [',', '?', '', '', 0, 'VK_OEM_COMMA'], + KeyN: ['n', 'N', '', '', 0, 'VK_N'], + KeyO: ['o', 'O', '', '', 0, 'VK_O'], + KeyP: ['p', 'P', '', '', 0, 'VK_P'], + KeyQ: ['a', 'A', '', '', 0, 'VK_A'], + KeyR: ['r', 'R', '', '', 0, 'VK_R'], + KeyS: ['s', 'S', '', '', 0, 'VK_S'], + KeyT: ['t', 'T', '', '', 0, 'VK_T'], + KeyU: ['u', 'U', '', '', 0, 'VK_U'], + KeyV: ['v', 'V', '', '', 0, 'VK_V'], + KeyW: ['z', 'Z', '', '', 0, 'VK_Z'], + KeyX: ['x', 'X', '', '', 0, 'VK_X'], + KeyY: ['y', 'Y', '', '', 0, 'VK_Y'], + KeyZ: ['w', 'W', '', '', 0, 'VK_W'], + Digit1: ['&', '1', '', '', 0, 'VK_1'], + Digit2: ['é', '2', '~', '', 0, 'VK_2'], + Digit3: ['"', '3', '#', '', 0, 'VK_3'], + Digit4: ['\'', '4', '{', '', 0, 'VK_4'], + Digit5: ['(', '5', '[', '', 0, 'VK_5'], + Digit6: ['-', '6', '|', '', 0, 'VK_6'], + Digit7: ['è', '7', '`', '', 0, 'VK_7'], + Digit8: ['_', '8', '\\', '', 0, 'VK_8'], + Digit9: ['ç', '9', '^', '', 0, 'VK_9'], + Digit0: ['à', '0', '@', '', 0, 'VK_0'], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', '', '', 0, 'VK_SPACE'], + Minus: [')', '°', ']', '', 0, 'VK_OEM_4'], + Equal: ['=', '+', '}', '', 0, 'VK_OEM_PLUS'], + BracketLeft: ['^', '¨', '', '', 0, 'VK_OEM_6'], + BracketRight: ['$', '£', '¤', '', 0, 'VK_OEM_1'], + Backslash: ['*', 'µ', '', '', 0, 'VK_OEM_5'], + Semicolon: ['m', 'M', '', '', 0, 'VK_M'], + Quote: ['ù', '%', '', '', 0, 'VK_OEM_3'], + Backquote: ['²', '', '', '', 0, 'VK_OEM_7'], + Comma: [';', '.', '', '', 0, 'VK_OEM_PERIOD'], + Period: [':', '/', '', '', 0, 'VK_OEM_2'], + Slash: ['!', '§', '', '', 0, 'VK_OEM_8'], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + PrintScreen: [], + ScrollLock: [], + Pause: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '', '', 0, 'VK_DIVIDE'], + NumpadMultiply: ['*', '*', '', '', 0, 'VK_MULTIPLY'], + NumpadSubtract: ['-', '-', '', '', 0, 'VK_SUBTRACT'], + NumpadAdd: ['+', '+', '', '', 0, 'VK_ADD'], + NumpadEnter: [], + Numpad1: [], + Numpad2: [], + Numpad3: [], + Numpad4: [], + Numpad5: [], + Numpad6: [], + Numpad7: [], + Numpad8: [], + Numpad9: [], + Numpad0: [], + NumpadDecimal: [], + IntlBackslash: ['<', '>', '', '', 0, 'VK_OEM_102'], + ContextMenu: [], + Power: [], + NumpadEqual: [], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + F21: [], + F22: [], + F23: [], + F24: [], + Help: [], + Undo: [], + Cut: [], + Copy: [], + Paste: [], + AudioVolumeMute: [], + AudioVolumeUp: [], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + Convert: [], + NonConvert: [], + Lang1: [], + Lang2: [], + Lang3: [], + Lang4: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [], + MediaTrackNext: [], + MediaTrackPrevious: [], + MediaStop: [], + Eject: [], + MediaPlayPause: [], + MediaSelect: [], + LaunchMail: [], + LaunchApp2: [], + LaunchApp1: [], + BrowserSearch: [], + BrowserHome: [], + BrowserBack: [], + BrowserForward: [], + BrowserStop: [], + BrowserRefresh: [], + BrowserFavorites: [] + } +}); \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/hu.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/hu.win.ts new file mode 100644 index 000000000..d6b5a4dac --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/hu.win.ts @@ -0,0 +1,169 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { name: '0000040E', id: '', text: 'Hungarian' }, + secondaryLayouts: [], + mapping: { + Sleep: [], + WakeUp: [], + KeyA: ['a', 'A', 'ä', '', 0, 'VK_A'], + KeyB: ['b', 'B', '{', '', 0, 'VK_B'], + KeyC: ['c', 'C', '&', '', 0, 'VK_C'], + KeyD: ['d', 'D', 'Đ', '', 0, 'VK_D'], + KeyE: ['e', 'E', 'Ä', '', 0, 'VK_E'], + KeyF: ['f', 'F', '[', '', 0, 'VK_F'], + KeyG: ['g', 'G', ']', '', 0, 'VK_G'], + KeyH: ['h', 'H', '', '', 0, 'VK_H'], + KeyI: ['i', 'I', 'Í', '', 0, 'VK_I'], + KeyJ: ['j', 'J', 'í', '', 0, 'VK_J'], + KeyK: ['k', 'K', 'ł', '', 0, 'VK_K'], + KeyL: ['l', 'L', 'Ł', '', 0, 'VK_L'], + KeyM: ['m', 'M', '<', '', 0, 'VK_M'], + KeyN: ['n', 'N', '}', '', 0, 'VK_N'], + KeyO: ['o', 'O', '', '', 0, 'VK_O'], + KeyP: ['p', 'P', '', '', 0, 'VK_P'], + KeyQ: ['q', 'Q', '\\', '', 0, 'VK_Q'], + KeyR: ['r', 'R', '', '', 0, 'VK_R'], + KeyS: ['s', 'S', 'đ', '', 0, 'VK_S'], + KeyT: ['t', 'T', '', '', 0, 'VK_T'], + KeyU: ['u', 'U', '€', '', 0, 'VK_U'], + KeyV: ['v', 'V', '@', '', 0, 'VK_V'], + KeyW: ['w', 'W', '|', '', 0, 'VK_W'], + KeyX: ['x', 'X', '#', '', 0, 'VK_X'], + KeyY: ['z', 'Z', '', '', 0, 'VK_Z'], + KeyZ: ['y', 'Y', '>', '', 0, 'VK_Y'], + Digit1: ['1', '\'', '~', '', 0, 'VK_1'], + Digit2: ['2', '"', 'ˇ', '', 0, 'VK_2'], + Digit3: ['3', '+', '^', '', 0, 'VK_3'], + Digit4: ['4', '!', '˘', '', 0, 'VK_4'], + Digit5: ['5', '%', '°', '', 0, 'VK_5'], + Digit6: ['6', '/', '˛', '', 0, 'VK_6'], + Digit7: ['7', '=', '`', '', 0, 'VK_7'], + Digit8: ['8', '(', '˙', '', 0, 'VK_8'], + Digit9: ['9', ')', '´', '', 0, 'VK_9'], + Digit0: ['ö', 'Ö', '˝', '', 0, 'VK_OEM_3'], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', '', '', 0, 'VK_SPACE'], + Minus: ['ü', 'Ü', '¨', '', 0, 'VK_OEM_2'], + Equal: ['ó', 'Ó', '¸', '', 0, 'VK_OEM_PLUS'], + BracketLeft: ['ő', 'Ő', '÷', '', 0, 'VK_OEM_4'], + BracketRight: ['ú', 'Ú', '×', '', 0, 'VK_OEM_6'], + Backslash: ['ű', 'Ű', '¤', '', 0, 'VK_OEM_5'], + Semicolon: ['é', 'É', '$', '', 0, 'VK_OEM_1'], + Quote: ['á', 'Á', 'ß', '', 0, 'VK_OEM_7'], + Backquote: ['0', '§', '', '', 0, 'VK_0'], + Comma: [',', '?', ';', '', 0, 'VK_OEM_COMMA'], + Period: ['.', ':', '>', '', 0, 'VK_OEM_PERIOD'], + Slash: ['-', '_', '*', '', 0, 'VK_OEM_MINUS'], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + PrintScreen: [], + ScrollLock: [], + Pause: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '', '', 0, 'VK_DIVIDE'], + NumpadMultiply: ['*', '*', '', '', 0, 'VK_MULTIPLY'], + NumpadSubtract: ['-', '-', '', '', 0, 'VK_SUBTRACT'], + NumpadAdd: ['+', '+', '', '', 0, 'VK_ADD'], + NumpadEnter: [], + Numpad1: [], + Numpad2: [], + Numpad3: [], + Numpad4: [], + Numpad5: [], + Numpad6: [], + Numpad7: [], + Numpad8: [], + Numpad9: [], + Numpad0: [], + NumpadDecimal: [], + IntlBackslash: ['í', 'Í', '<', '', 0, 'VK_OEM_102'], + ContextMenu: [], + Power: [], + NumpadEqual: [], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + F21: [], + F22: [], + F23: [], + F24: [], + Help: [], + Undo: [], + Cut: [], + Copy: [], + Paste: [], + AudioVolumeMute: [], + AudioVolumeUp: [], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + Convert: [], + NonConvert: [], + Lang1: [], + Lang2: [], + Lang3: [], + Lang4: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [], + MediaTrackNext: [], + MediaTrackPrevious: [], + MediaStop: [], + Eject: [], + MediaPlayPause: [], + MediaSelect: [], + LaunchMail: [], + LaunchApp2: [], + LaunchApp1: [], + BrowserSearch: [], + BrowserHome: [], + BrowserBack: [], + BrowserForward: [], + BrowserStop: [], + BrowserRefresh: [], + BrowserFavorites: [] + } +}); diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/it.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/it.darwin.ts new file mode 100644 index 000000000..1dc97d990 --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/it.darwin.ts @@ -0,0 +1,132 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { id: 'com.apple.keylayout.Italian-Pro', lang: 'it', localizedName: 'Italian' }, + secondaryLayouts: [], + mapping: { + KeyA: ['a', 'A', 'å', 'Å', 0], + KeyB: ['b', 'B', '∫', 'Í', 0], + KeyC: ['c', 'C', '©', 'Á', 0], + KeyD: ['d', 'D', '∂', '˘', 0], + KeyE: ['e', 'E', '€', 'È', 0], + KeyF: ['f', 'F', 'ƒ', '˙', 0], + KeyG: ['g', 'G', '∞', '˚', 0], + KeyH: ['h', 'H', '∆', '¸', 0], + KeyI: ['i', 'I', 'œ', 'Œ', 0], + KeyJ: ['j', 'J', 'ª', '˝', 0], + KeyK: ['k', 'K', 'º', '˛', 0], + KeyL: ['l', 'L', '¬', 'ˇ', 0], + KeyM: ['m', 'M', 'µ', 'Ú', 0], + KeyN: ['n', 'N', '˜', 'Ó', 4], + KeyO: ['o', 'O', 'ø', 'Ø', 0], + KeyP: ['p', 'P', 'π', '∏', 0], + KeyQ: ['q', 'Q', '„', '‚', 0], + KeyR: ['r', 'R', '®', 'Ì', 0], + KeyS: ['s', 'S', 'ß', '¯', 0], + KeyT: ['t', 'T', '™', 'Ò', 0], + KeyU: ['u', 'U', '¨', 'Ù', 4], + KeyV: ['v', 'V', '√', 'É', 0], + KeyW: ['w', 'W', 'Ω', 'À', 0], + KeyX: ['x', 'X', '†', '‡', 0], + KeyY: ['y', 'Y', 'æ', 'Æ', 0], + KeyZ: ['z', 'Z', '∑', ' ', 0], + Digit1: ['1', '!', '«', '»', 0], + Digit2: ['2', '"', '“', '”', 0], + Digit3: ['3', '£', '‘', '’', 0], + Digit4: ['4', '$', '¥', '¢', 0], + Digit5: ['5', '%', '~', '‰', 0], + Digit6: ['6', '&', '‹', '›', 0], + Digit7: ['7', '/', '÷', '⁄', 0], + Digit8: ['8', '(', '´', '', 4], + Digit9: ['9', ')', '`', ' ', 4], + Digit0: ['0', '=', '≠', '≈', 0], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', ' ', ' ', 0], + Minus: ['\'', '?', '¡', '¿', 0], + Equal: ['ì', '^', 'ˆ', '±', 4], + BracketLeft: ['è', 'é', '[', '{', 0], + BracketRight: ['+', '*', ']', '}', 0], + Backslash: ['ù', '§', '¶', '◊', 0], + Semicolon: ['ò', 'ç', '@', 'Ç', 0], + Quote: ['à', '°', '#', '∞', 0], + Backquote: ['<', '>', '≤', '≥', 0], + Comma: [',', ';', '…', ' ', 0], + Period: ['.', ':', '•', '·', 0], + Slash: ['-', '_', '–', '—', 0], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '/', '/', 0], + NumpadMultiply: ['*', '*', '*', '*', 0], + NumpadSubtract: ['-', '-', '-', '-', 0], + NumpadAdd: ['+', '+', '+', '+', 0], + NumpadEnter: [], + Numpad1: ['1', '1', '1', '1', 0], + Numpad2: ['2', '2', '2', '2', 0], + Numpad3: ['3', '3', '3', '3', 0], + Numpad4: ['4', '4', '4', '4', 0], + Numpad5: ['5', '5', '5', '5', 0], + Numpad6: ['6', '6', '6', '6', 0], + Numpad7: ['7', '7', '7', '7', 0], + Numpad8: ['8', '8', '8', '8', 0], + Numpad9: ['9', '9', '9', '9', 0], + Numpad0: ['0', '0', '0', '0', 0], + NumpadDecimal: [',', '.', ',', '.', 0], + IntlBackslash: ['\\', '|', '`', 'ı', 0], + ContextMenu: [], + NumpadEqual: ['=', '=', '=', '=', 0], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + AudioVolumeMute: [], + AudioVolumeUp: ['', '=', '', '=', 0], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [] + } +}); \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/it.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/it.win.ts new file mode 100644 index 000000000..573b7b0c6 --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/it.win.ts @@ -0,0 +1,169 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { name: '00000410', id: '', text: 'Italian' }, + secondaryLayouts: [], + mapping: { + Sleep: [], + WakeUp: [], + KeyA: ['a', 'A', '', '', 0, 'VK_A'], + KeyB: ['b', 'B', '', '', 0, 'VK_B'], + KeyC: ['c', 'C', '', '', 0, 'VK_C'], + KeyD: ['d', 'D', '', '', 0, 'VK_D'], + KeyE: ['e', 'E', '€', '', 0, 'VK_E'], + KeyF: ['f', 'F', '', '', 0, 'VK_F'], + KeyG: ['g', 'G', '', '', 0, 'VK_G'], + KeyH: ['h', 'H', '', '', 0, 'VK_H'], + KeyI: ['i', 'I', '', '', 0, 'VK_I'], + KeyJ: ['j', 'J', '', '', 0, 'VK_J'], + KeyK: ['k', 'K', '', '', 0, 'VK_K'], + KeyL: ['l', 'L', '', '', 0, 'VK_L'], + KeyM: ['m', 'M', '', '', 0, 'VK_M'], + KeyN: ['n', 'N', '', '', 0, 'VK_N'], + KeyO: ['o', 'O', '', '', 0, 'VK_O'], + KeyP: ['p', 'P', '', '', 0, 'VK_P'], + KeyQ: ['q', 'Q', '', '', 0, 'VK_Q'], + KeyR: ['r', 'R', '', '', 0, 'VK_R'], + KeyS: ['s', 'S', '', '', 0, 'VK_S'], + KeyT: ['t', 'T', '', '', 0, 'VK_T'], + KeyU: ['u', 'U', '', '', 0, 'VK_U'], + KeyV: ['v', 'V', '', '', 0, 'VK_V'], + KeyW: ['w', 'W', '', '', 0, 'VK_W'], + KeyX: ['x', 'X', '', '', 0, 'VK_X'], + KeyY: ['y', 'Y', '', '', 0, 'VK_Y'], + KeyZ: ['z', 'Z', '', '', 0, 'VK_Z'], + Digit1: ['1', '!', '', '', 0, 'VK_1'], + Digit2: ['2', '"', '', '', 0, 'VK_2'], + Digit3: ['3', '£', '', '', 0, 'VK_3'], + Digit4: ['4', '$', '', '', 0, 'VK_4'], + Digit5: ['5', '%', '€', '', 0, 'VK_5'], + Digit6: ['6', '&', '', '', 0, 'VK_6'], + Digit7: ['7', '/', '', '', 0, 'VK_7'], + Digit8: ['8', '(', '', '', 0, 'VK_8'], + Digit9: ['9', ')', '', '', 0, 'VK_9'], + Digit0: ['0', '=', '', '', 0, 'VK_0'], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', '', '', 0, 'VK_SPACE'], + Minus: ['\'', '?', '', '', 0, 'VK_OEM_4'], + Equal: ['ì', '^', '', '', 0, 'VK_OEM_6'], + BracketLeft: ['è', 'é', '[', '{', 0, 'VK_OEM_1'], + BracketRight: ['+', '*', ']', '}', 0, 'VK_OEM_PLUS'], + Backslash: ['ù', '§', '', '', 0, 'VK_OEM_2'], + Semicolon: ['ò', 'ç', '@', '', 0, 'VK_OEM_3'], + Quote: ['à', '°', '#', '', 0, 'VK_OEM_7'], + Backquote: ['\\', '|', '', '', 0, 'VK_OEM_5'], + Comma: [',', ';', '', '', 0, 'VK_OEM_COMMA'], + Period: ['.', ':', '', '', 0, 'VK_OEM_PERIOD'], + Slash: ['-', '_', '', '', 0, 'VK_OEM_MINUS'], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + PrintScreen: [], + ScrollLock: [], + Pause: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '', '', 0, 'VK_DIVIDE'], + NumpadMultiply: ['*', '*', '', '', 0, 'VK_MULTIPLY'], + NumpadSubtract: ['-', '-', '', '', 0, 'VK_SUBTRACT'], + NumpadAdd: ['+', '+', '', '', 0, 'VK_ADD'], + NumpadEnter: [], + Numpad1: [], + Numpad2: [], + Numpad3: [], + Numpad4: [], + Numpad5: [], + Numpad6: [], + Numpad7: [], + Numpad8: [], + Numpad9: [], + Numpad0: [], + NumpadDecimal: [], + IntlBackslash: ['<', '>', '', '', 0, 'VK_OEM_102'], + ContextMenu: [], + Power: [], + NumpadEqual: [], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + F21: [], + F22: [], + F23: [], + F24: [], + Help: [], + Undo: [], + Cut: [], + Copy: [], + Paste: [], + AudioVolumeMute: [], + AudioVolumeUp: [], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + Convert: [], + NonConvert: [], + Lang1: [], + Lang2: [], + Lang3: [], + Lang4: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [], + MediaTrackNext: [], + MediaTrackPrevious: [], + MediaStop: [], + Eject: [], + MediaPlayPause: [], + MediaSelect: [], + LaunchMail: [], + LaunchApp2: [], + LaunchApp1: [], + BrowserSearch: [], + BrowserHome: [], + BrowserBack: [], + BrowserForward: [], + BrowserStop: [], + BrowserRefresh: [], + BrowserFavorites: [] + } +}); \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/jp-roman.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/jp-roman.darwin.ts new file mode 100644 index 000000000..27328f3d8 --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/jp-roman.darwin.ts @@ -0,0 +1,132 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { id: 'com.google.inputmethod.Japanese.Roman', lang: 'en', localizedName: 'Alphanumeric (Google)' }, + secondaryLayouts: [], + mapping: { + KeyA: ['a', 'A', '¯', '̄', 4], + KeyB: ['b', 'B', '˘', '̆', 4], + KeyC: ['c', 'C', '¸', '̧', 4], + KeyD: ['d', 'D', 'ð', 'Ð', 0], + KeyE: ['e', 'E', '´', '́', 4], + KeyF: ['f', 'F', 'ƒ', '', 0], + KeyG: ['g', 'G', '©', '‸', 8], + KeyH: ['h', 'H', 'ˍ', '̱', 4], + KeyI: ['i', 'I', 'ʼ', '̛', 4], + KeyJ: ['j', 'J', '˝', '̋', 4], + KeyK: ['k', 'K', '˚', '̊', 4], + KeyL: ['l', 'L', '-', '̵', 4], + KeyM: ['m', 'M', '˛', '̨', 4], + KeyN: ['n', 'N', '˜', '̃', 4], + KeyO: ['o', 'O', 'ø', 'Ø', 0], + KeyP: ['p', 'P', ',', '̦', 4], + KeyQ: ['q', 'Q', 'œ', 'Œ', 0], + KeyR: ['r', 'R', '®', '‰', 0], + KeyS: ['s', 'S', 'ß', '', 0], + KeyT: ['t', 'T', 'þ', 'Þ', 0], + KeyU: ['u', 'U', '¨', '̈', 4], + KeyV: ['v', 'V', 'ˇ', '̌', 4], + KeyW: ['w', 'W', '˙', '̇', 4], + KeyX: ['x', 'X', '.', '̣', 4], + KeyY: ['y', 'Y', '¥', '', 0], + KeyZ: ['z', 'Z', 'ˀ', '̉', 4], + Digit1: ['1', '!', '¡', '⁄', 0], + Digit2: ['2', '@', '™', '€', 0], + Digit3: ['3', '#', '£', '‹', 0], + Digit4: ['4', '$', '¢', '›', 0], + Digit5: ['5', '%', '§', '†', 0], + Digit6: ['6', '^', 'ˆ', '̂', 4], + Digit7: ['7', '&', '¶', '‡', 0], + Digit8: ['8', '*', '•', '°', 0], + Digit9: ['9', '(', 'ª', '·', 0], + Digit0: ['0', ')', 'º', '‚', 0], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', ' ', ' ', 0], + Minus: ['-', '_', '–', '—', 0], + Equal: ['=', '+', '≠', '±', 0], + BracketLeft: ['[', '{', '“', '”', 0], + BracketRight: [']', '}', '‘', '’', 0], + Backslash: ['\\', '|', '«', '»', 0], + Semicolon: [';', ':', '…', '№', 8], + Quote: ['\'', '"', 'æ', 'Æ', 0], + Backquote: ['`', '~', '`', '̀', 4], + Comma: [',', '<', '≤', '„', 0], + Period: ['.', '>', '≥', 'ʔ', 8], + Slash: ['/', '?', '÷', '¿', 0], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '/', '/', 0], + NumpadMultiply: ['*', '*', '*', '*', 0], + NumpadSubtract: ['-', '-', '-', '-', 0], + NumpadAdd: ['+', '+', '+', '+', 0], + NumpadEnter: [], + Numpad1: ['1', '1', '1', '1', 0], + Numpad2: ['2', '2', '2', '2', 0], + Numpad3: ['3', '3', '3', '3', 0], + Numpad4: ['4', '4', '4', '4', 0], + Numpad5: ['5', '5', '5', '5', 0], + Numpad6: ['6', '6', '6', '6', 0], + Numpad7: ['7', '7', '7', '7', 0], + Numpad8: ['8', '8', '8', '8', 0], + Numpad9: ['9', '9', '9', '9', 0], + Numpad0: ['0', '0', '0', '0', 0], + NumpadDecimal: ['.', '.', '.', '.', 0], + IntlBackslash: ['§', '±', '§', '±', 0], + ContextMenu: [], + NumpadEqual: ['=', '=', '=', '=', 0], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + AudioVolumeMute: [], + AudioVolumeUp: ['', '=', '', '=', 0], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [] + } +}); \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/jp.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/jp.darwin.ts new file mode 100644 index 000000000..819f96ba5 --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/jp.darwin.ts @@ -0,0 +1,132 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { id: 'com.apple.inputmethod.Kotoeri.Japanese', lang: 'ja', localizedName: 'Hiragana' }, + secondaryLayouts: [], + mapping: { + KeyA: ['a', 'A', 'å', 'Å', 0], + KeyB: ['b', 'B', '∫', 'ı', 0], + KeyC: ['c', 'C', 'ç', 'Ç', 0], + KeyD: ['d', 'D', '∂', 'Î', 0], + KeyE: ['e', 'E', '´', '´', 4], + KeyF: ['f', 'F', 'ƒ', 'Ï', 0], + KeyG: ['g', 'G', '©', '˝', 0], + KeyH: ['h', 'H', '˙', 'Ó', 0], + KeyI: ['i', 'I', 'ˆ', 'ˆ', 4], + KeyJ: ['j', 'J', '∆', 'Ô', 0], + KeyK: ['k', 'K', '˚', '', 0], + KeyL: ['l', 'L', '¬', 'Ò', 0], + KeyM: ['m', 'M', 'µ', 'Â', 0], + KeyN: ['n', 'N', '˜', '˜', 4], + KeyO: ['o', 'O', 'ø', 'Ø', 0], + KeyP: ['p', 'P', 'π', '∏', 0], + KeyQ: ['q', 'Q', 'œ', 'Œ', 0], + KeyR: ['r', 'R', '®', '‰', 0], + KeyS: ['s', 'S', 'ß', 'Í', 0], + KeyT: ['t', 'T', '†', 'ˇ', 0], + KeyU: ['u', 'U', '¨', '¨', 4], + KeyV: ['v', 'V', '√', '◊', 0], + KeyW: ['w', 'W', '∑', '„', 0], + KeyX: ['x', 'X', '≈', '˛', 0], + KeyY: ['y', 'Y', '¥', 'Á', 0], + KeyZ: ['z', 'Z', 'Ω', '¸', 0], + Digit1: ['1', '!', '¡', '⁄', 0], + Digit2: ['2', '@', '™', '€', 0], + Digit3: ['3', '#', '£', '‹', 0], + Digit4: ['4', '$', '¢', '›', 0], + Digit5: ['5', '%', '∞', 'fi', 0], + Digit6: ['6', '^', '§', 'fl', 0], + Digit7: ['7', '&', '¶', '‡', 0], + Digit8: ['8', '*', '•', '°', 0], + Digit9: ['9', '(', 'ª', '·', 0], + Digit0: ['0', ')', 'º', '‚', 0], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', ' ', ' ', 0], + Minus: ['-', '_', '–', '—', 0], + Equal: ['=', '+', '≠', '±', 0], + BracketLeft: ['[', '{', '“', '”', 0], + BracketRight: [']', '}', '‘', '’', 0], + Backslash: ['\\', '|', '«', '»', 0], + Semicolon: [';', ':', '…', 'Ú', 0], + Quote: ['\'', '"', 'æ', 'Æ', 0], + Backquote: ['`', '~', '`', '`', 4], + Comma: [',', '<', '≤', '¯', 0], + Period: ['.', '>', '≥', '˘', 0], + Slash: ['/', '?', '÷', '¿', 0], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '/', '/', 0], + NumpadMultiply: ['*', '*', '*', '*', 0], + NumpadSubtract: ['-', '-', '-', '-', 0], + NumpadAdd: ['+', '+', '+', '+', 0], + NumpadEnter: [], + Numpad1: ['1', '1', '1', '1', 0], + Numpad2: ['2', '2', '2', '2', 0], + Numpad3: ['3', '3', '3', '3', 0], + Numpad4: ['4', '4', '4', '4', 0], + Numpad5: ['5', '5', '5', '5', 0], + Numpad6: ['6', '6', '6', '6', 0], + Numpad7: ['7', '7', '7', '7', 0], + Numpad8: ['8', '8', '8', '8', 0], + Numpad9: ['9', '9', '9', '9', 0], + Numpad0: ['0', '0', '0', '0', 0], + NumpadDecimal: ['.', '.', '.', '.', 0], + IntlBackslash: ['§', '±', '§', '±', 0], + ContextMenu: [], + NumpadEqual: ['=', '=', '=', '=', 0], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + AudioVolumeMute: [], + AudioVolumeUp: ['', '=', '', '=', 0], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [] + } +}); \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/ko.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/ko.darwin.ts new file mode 100644 index 000000000..4219a7bd6 --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/ko.darwin.ts @@ -0,0 +1,132 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { id: 'com.apple.inputmethod.Korean.2SetKorean', lang: 'ko', localizedName: '2-Set Korean' }, + secondaryLayouts: [], + mapping: { + KeyA: ['ㅁ', 'ㅁ', 'a', 'A', 0], + KeyB: ['ㅠ', 'ㅠ', 'b', 'B', 0], + KeyC: ['ㅊ', 'ㅊ', 'c', 'C', 0], + KeyD: ['ㅇ', 'ㅇ', 'd', 'D', 0], + KeyE: ['ㄷ', 'ㄸ', 'e', 'E', 0], + KeyF: ['ㄹ', 'ㄹ', 'f', 'F', 0], + KeyG: ['ㅎ', 'ㅎ', 'g', 'G', 0], + KeyH: ['ㅗ', 'ㅗ', 'h', 'H', 0], + KeyI: ['ㅑ', 'ㅑ', 'i', 'I', 0], + KeyJ: ['ㅓ', 'ㅓ', 'j', 'J', 0], + KeyK: ['ㅏ', 'ㅏ', 'k', 'K', 0], + KeyL: ['ㅣ', 'ㅣ', 'l', 'L', 0], + KeyM: ['ㅡ', 'ㅡ', 'm', 'M', 0], + KeyN: ['ㅜ', 'ㅜ', 'n', 'N', 0], + KeyO: ['ㅐ', 'ㅒ', 'o', 'O', 0], + KeyP: ['ㅔ', 'ㅖ', 'p', 'P', 0], + KeyQ: ['ㅂ', 'ㅃ', 'q', 'Q', 0], + KeyR: ['ㄱ', 'ㄲ', 'r', 'R', 0], + KeyS: ['ㄴ', 'ㄴ', 's', 'S', 0], + KeyT: ['ㅅ', 'ㅆ', 't', 'T', 0], + KeyU: ['ㅕ', 'ㅕ', 'u', 'U', 0], + KeyV: ['ㅍ', 'ㅍ', 'v', 'V', 0], + KeyW: ['ㅈ', 'ㅉ', 'w', 'W', 0], + KeyX: ['ㅌ', 'ㅌ', 'x', 'X', 0], + KeyY: ['ㅛ', 'ㅛ', 'y', 'Y', 0], + KeyZ: ['ㅋ', 'ㅋ', 'z', 'Z', 0], + Digit1: ['1', '!', '1', '!', 0], + Digit2: ['2', '@', '2', '@', 0], + Digit3: ['3', '#', '3', '#', 0], + Digit4: ['4', '$', '4', '$', 0], + Digit5: ['5', '%', '5', '%', 0], + Digit6: ['6', '^', '6', '^', 0], + Digit7: ['7', '&', '7', '&', 0], + Digit8: ['8', '*', '8', '*', 0], + Digit9: ['9', '(', '9', '(', 0], + Digit0: ['0', ')', '0', ')', 0], + Enter: [], + Escape: ['', '', '', '‌', 0], + Backspace: [], + Tab: [], + Space: [' ', ' ', ' ', ' ', 0], + Minus: ['-', '_', '-', '_', 0], + Equal: ['=', '+', '=', '+', 0], + BracketLeft: ['[', '{', '[', '{', 0], + BracketRight: [']', '}', ']', '}', 0], + Backslash: ['\\', '|', '\\', '|', 0], + Semicolon: [';', ':', ';', ':', 0], + Quote: ['\'', '"', '\'', '"', 0], + Backquote: ['₩', '~', '`', '~', 0], + Comma: [',', '<', ',', '<', 0], + Period: ['.', '>', '.', '>', 0], + Slash: ['/', '?', '/', '?', 0], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '/', '/', 0], + NumpadMultiply: ['*', '*', '*', '*', 0], + NumpadSubtract: ['-', '-', '-', '-', 0], + NumpadAdd: ['+', '+', '+', '+', 0], + NumpadEnter: [], + Numpad1: ['1', '1', '1', '1', 0], + Numpad2: ['2', '2', '2', '2', 0], + Numpad3: ['3', '3', '3', '3', 0], + Numpad4: ['4', '4', '4', '4', 0], + Numpad5: ['5', '5', '5', '5', 0], + Numpad6: ['6', '6', '6', '6', 0], + Numpad7: ['7', '7', '7', '7', 0], + Numpad8: ['8', '8', '8', '8', 0], + Numpad9: ['9', '9', '9', '9', 0], + Numpad0: ['0', '0', '0', '0', 0], + NumpadDecimal: ['.', '.', '.', '.', 0], + IntlBackslash: ['§', '±', '§', '±', 0], + ContextMenu: [], + NumpadEqual: ['=', '=', '=', '=', 0], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + AudioVolumeMute: [], + AudioVolumeUp: ['', '=', '', '=', 0], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [] + } +}); \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.darwin.ts new file mode 100644 index 000000000..a9fbd20de --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.darwin.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. + *--------------------------------------------------------------------------------------------*/ + +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/en.darwin'; // 15% +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/zh-hans.darwin'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/en-uk.darwin'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/es.darwin'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/jp-roman.darwin'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/de.darwin'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/en-intl.darwin'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/en-ext.darwin'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/fr.darwin'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/jp.darwin'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/pl.darwin'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/it.darwin'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/ru.darwin'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/pt.darwin'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/ko.darwin'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/dvorak.darwin'; + +export { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.linux.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.linux.ts new file mode 100644 index 000000000..6561501fc --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.linux.ts @@ -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. + *--------------------------------------------------------------------------------------------*/ + +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/en.linux'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/es.linux'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/de.linux'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/fr.linux'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/ru.linux'; + +export { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.win.ts new file mode 100644 index 000000000..bb85b252f --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.win.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 'vs/workbench/services/keybinding/browser/keyboardLayouts/en.win'; // 40% +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/es-latin.win'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/en-in.win'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/de.win'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/en-uk.win'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/fr.win'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/pt-br.win'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/es.win'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/en-intl.win'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/ru.win'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/pl.win'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/it.win'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/sv.win'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/tr.win'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/pt.win'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/dk.win'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/no.win'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/thai.win'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/hu.win'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/de-swiss.win'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/en-belgian.win'; +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/cz.win'; + +export { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/no.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/no.win.ts new file mode 100644 index 000000000..2c415e8eb --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/no.win.ts @@ -0,0 +1,169 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { name: '00000414', id: '', text: 'Norwegian' }, + secondaryLayouts: [], + mapping: { + Sleep: [], + WakeUp: [], + KeyA: ['a', 'A', '', '', 0, 'VK_A'], + KeyB: ['b', 'B', '', '', 0, 'VK_B'], + KeyC: ['c', 'C', '', '', 0, 'VK_C'], + KeyD: ['d', 'D', '', '', 0, 'VK_D'], + KeyE: ['e', 'E', '€', '', 0, 'VK_E'], + KeyF: ['f', 'F', '', '', 0, 'VK_F'], + KeyG: ['g', 'G', '', '', 0, 'VK_G'], + KeyH: ['h', 'H', '', '', 0, 'VK_H'], + KeyI: ['i', 'I', '', '', 0, 'VK_I'], + KeyJ: ['j', 'J', '', '', 0, 'VK_J'], + KeyK: ['k', 'K', '', '', 0, 'VK_K'], + KeyL: ['l', 'L', '', '', 0, 'VK_L'], + KeyM: ['m', 'M', 'µ', '', 0, 'VK_M'], + KeyN: ['n', 'N', '', '', 0, 'VK_N'], + KeyO: ['o', 'O', '', '', 0, 'VK_O'], + KeyP: ['p', 'P', '', '', 0, 'VK_P'], + KeyQ: ['q', 'Q', '', '', 0, 'VK_Q'], + KeyR: ['r', 'R', '', '', 0, 'VK_R'], + KeyS: ['s', 'S', '', '', 0, 'VK_S'], + KeyT: ['t', 'T', '', '', 0, 'VK_T'], + KeyU: ['u', 'U', '', '', 0, 'VK_U'], + KeyV: ['v', 'V', '', '', 0, 'VK_V'], + KeyW: ['w', 'W', '', '', 0, 'VK_W'], + KeyX: ['x', 'X', '', '', 0, 'VK_X'], + KeyY: ['y', 'Y', '', '', 0, 'VK_Y'], + KeyZ: ['z', 'Z', '', '', 0, 'VK_Z'], + Digit1: ['1', '!', '', '', 0, 'VK_1'], + Digit2: ['2', '"', '@', '', 0, 'VK_2'], + Digit3: ['3', '#', '£', '', 0, 'VK_3'], + Digit4: ['4', '¤', '$', '', 0, 'VK_4'], + Digit5: ['5', '%', '€', '', 0, 'VK_5'], + Digit6: ['6', '&', '', '', 0, 'VK_6'], + Digit7: ['7', '/', '{', '', 0, 'VK_7'], + Digit8: ['8', '(', '[', '', 0, 'VK_8'], + Digit9: ['9', ')', ']', '', 0, 'VK_9'], + Digit0: ['0', '=', '}', '', 0, 'VK_0'], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', '', '', 0, 'VK_SPACE'], + Minus: ['+', '?', '', '', 0, 'VK_OEM_PLUS'], + Equal: ['\\', '`', '´', '', 0, 'VK_OEM_4'], + BracketLeft: ['å', 'Å', '', '', 0, 'VK_OEM_6'], + BracketRight: ['¨', '^', '~', '', 0, 'VK_OEM_1'], + Backslash: ['\'', '*', '', '', 0, 'VK_OEM_2'], + Semicolon: ['ø', 'Ø', '', '', 0, 'VK_OEM_3'], + Quote: ['æ', 'Æ', '', '', 0, 'VK_OEM_7'], + Backquote: ['|', '§', '', '', 0, 'VK_OEM_5'], + Comma: [',', ';', '', '', 0, 'VK_OEM_COMMA'], + Period: ['.', ':', '', '', 0, 'VK_OEM_PERIOD'], + Slash: ['-', '_', '', '', 0, 'VK_OEM_MINUS'], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + PrintScreen: [], + ScrollLock: [], + Pause: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '', '', 0, 'VK_DIVIDE'], + NumpadMultiply: ['*', '*', '', '', 0, 'VK_MULTIPLY'], + NumpadSubtract: ['-', '-', '', '', 0, 'VK_SUBTRACT'], + NumpadAdd: ['+', '+', '', '', 0, 'VK_ADD'], + NumpadEnter: [], + Numpad1: [], + Numpad2: [], + Numpad3: [], + Numpad4: [], + Numpad5: [], + Numpad6: [], + Numpad7: [], + Numpad8: [], + Numpad9: [], + Numpad0: [], + NumpadDecimal: [], + IntlBackslash: ['<', '>', '', '', 0, 'VK_OEM_102'], + ContextMenu: [], + Power: [], + NumpadEqual: [], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + F21: [], + F22: [], + F23: [], + F24: [], + Help: [], + Undo: [], + Cut: [], + Copy: [], + Paste: [], + AudioVolumeMute: [], + AudioVolumeUp: [], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + Convert: [], + NonConvert: [], + Lang1: [], + Lang2: [], + Lang3: [], + Lang4: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [], + MediaTrackNext: [], + MediaTrackPrevious: [], + MediaStop: [], + Eject: [], + MediaPlayPause: [], + MediaSelect: [], + LaunchMail: [], + LaunchApp2: [], + LaunchApp1: [], + BrowserSearch: [], + BrowserHome: [], + BrowserBack: [], + BrowserForward: [], + BrowserStop: [], + BrowserRefresh: [], + BrowserFavorites: [] + } +}); diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/pl.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/pl.darwin.ts new file mode 100644 index 000000000..57577ba51 --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/pl.darwin.ts @@ -0,0 +1,132 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { id: 'com.apple.keylayout.PolishPro', lang: 'pl', localizedName: 'Polish - Pro' }, + secondaryLayouts: [], + mapping: { + KeyA: ['a', 'A', 'ą', 'Ą', 0], + KeyB: ['b', 'B', 'ļ', 'ű', 0], + KeyC: ['c', 'C', 'ć', 'Ć', 0], + KeyD: ['d', 'D', '∂', 'Ž', 0], + KeyE: ['e', 'E', 'ę', 'Ę', 0], + KeyF: ['f', 'F', 'ń', 'ž', 0], + KeyG: ['g', 'G', '©', 'Ū', 0], + KeyH: ['h', 'H', 'ķ', 'Ó', 0], + KeyI: ['i', 'I', '^', 'ť', 4], + KeyJ: ['j', 'J', '∆', 'Ô', 0], + KeyK: ['k', 'K', 'Ż', 'ū', 0], + KeyL: ['l', 'L', 'ł', 'Ł', 0], + KeyM: ['m', 'M', 'Ķ', 'ų', 0], + KeyN: ['n', 'N', 'ń', 'Ń', 0], + KeyO: ['o', 'O', 'ó', 'Ó', 0], + KeyP: ['p', 'P', 'Ļ', 'ł', 0], + KeyQ: ['q', 'Q', 'Ō', 'ő', 0], + KeyR: ['r', 'R', '®', '£', 0], + KeyS: ['s', 'S', 'ś', 'Ś', 0], + KeyT: ['t', 'T', '†', 'ś', 0], + KeyU: ['u', 'U', '¨', 'Ť', 4], + KeyV: ['v', 'V', '√', '◊', 0], + KeyW: ['w', 'W', '∑', '„', 0], + KeyX: ['x', 'X', 'ź', 'Ź', 0], + KeyY: ['y', 'Y', 'ī', 'Á', 0], + KeyZ: ['z', 'Z', 'ż', 'Ż', 0], + Digit1: ['1', '!', 'Ń', 'ŕ', 0], + Digit2: ['2', '@', '™', 'Ř', 0], + Digit3: ['3', '#', '€', '‹', 0], + Digit4: ['4', '$', 'ß', '›', 0], + Digit5: ['5', '%', 'į', 'ř', 0], + Digit6: ['6', '^', '§', 'Ŗ', 0], + Digit7: ['7', '&', '¶', 'ŗ', 0], + Digit8: ['8', '*', '•', '°', 0], + Digit9: ['9', '(', 'Ľ', 'Š', 0], + Digit0: ['0', ')', 'ľ', '‚', 0], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', ' ', ' ', 0], + Minus: ['-', '_', '–', '—', 0], + Equal: ['=', '+', '≠', 'Ī', 0], + BracketLeft: ['[', '{', '„', '”', 0], + BracketRight: [']', '}', '‚', '’', 0], + Backslash: ['\\', '|', '«', '»', 0], + Semicolon: [';', ':', '…', 'Ú', 0], + Quote: ['\'', '"', 'ĺ', 'ģ', 0], + Backquote: ['`', '~', '`', 'Ŕ', 4], + Comma: [',', '<', '≤', 'Ý', 0], + Period: ['.', '>', '≥', 'ý', 0], + Slash: ['/', '?', '÷', 'ņ', 0], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '/', '/', 0], + NumpadMultiply: ['*', '*', '*', '*', 0], + NumpadSubtract: ['-', '-', '-', '-', 0], + NumpadAdd: ['+', '+', '+', '+', 0], + NumpadEnter: [], + Numpad1: ['1', '1', '1', '1', 0], + Numpad2: ['2', '2', '2', '2', 0], + Numpad3: ['3', '3', '3', '3', 0], + Numpad4: ['4', '4', '4', '4', 0], + Numpad5: ['5', '5', '5', '5', 0], + Numpad6: ['6', '6', '6', '6', 0], + Numpad7: ['7', '7', '7', '7', 0], + Numpad8: ['8', '8', '8', '8', 0], + Numpad9: ['9', '9', '9', '9', 0], + Numpad0: ['0', '0', '0', '0', 0], + NumpadDecimal: ['.', '.', '.', '.', 0], + IntlBackslash: ['§', '£', '¬', '¬', 0], + ContextMenu: [], + NumpadEqual: ['=', '=', '=', '=', 0], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + AudioVolumeMute: [], + AudioVolumeUp: ['', '=', '', '=', 0], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [] + } +}); \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/pl.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/pl.win.ts new file mode 100644 index 000000000..a110111a8 --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/pl.win.ts @@ -0,0 +1,169 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { name: '00000415', id: '', text: 'Polish (Programmers)' }, + secondaryLayouts: [], + mapping: { + Sleep: [], + WakeUp: [], + KeyA: ['a', 'A', 'ą', 'Ą', 0, 'VK_A'], + KeyB: ['b', 'B', '', '', 0, 'VK_B'], + KeyC: ['c', 'C', 'ć', 'Ć', 0, 'VK_C'], + KeyD: ['d', 'D', '', '', 0, 'VK_D'], + KeyE: ['e', 'E', 'ę', 'Ę', 0, 'VK_E'], + KeyF: ['f', 'F', '', '', 0, 'VK_F'], + KeyG: ['g', 'G', '', '', 0, 'VK_G'], + KeyH: ['h', 'H', '', '', 0, 'VK_H'], + KeyI: ['i', 'I', '', '', 0, 'VK_I'], + KeyJ: ['j', 'J', '', '', 0, 'VK_J'], + KeyK: ['k', 'K', '', '', 0, 'VK_K'], + KeyL: ['l', 'L', 'ł', 'Ł', 0, 'VK_L'], + KeyM: ['m', 'M', '', '', 0, 'VK_M'], + KeyN: ['n', 'N', 'ń', 'Ń', 0, 'VK_N'], + KeyO: ['o', 'O', 'ó', 'Ó', 0, 'VK_O'], + KeyP: ['p', 'P', '', '', 0, 'VK_P'], + KeyQ: ['q', 'Q', '', '', 0, 'VK_Q'], + KeyR: ['r', 'R', '', '', 0, 'VK_R'], + KeyS: ['s', 'S', 'ś', 'Ś', 0, 'VK_S'], + KeyT: ['t', 'T', '', '', 0, 'VK_T'], + KeyU: ['u', 'U', '€', '', 0, 'VK_U'], + KeyV: ['v', 'V', '', '', 0, 'VK_V'], + KeyW: ['w', 'W', '', '', 0, 'VK_W'], + KeyX: ['x', 'X', 'ź', 'Ź', 0, 'VK_X'], + KeyY: ['y', 'Y', '', '', 0, 'VK_Y'], + KeyZ: ['z', 'Z', 'ż', 'Ż', 0, 'VK_Z'], + Digit1: ['1', '!', '', '', 0, 'VK_1'], + Digit2: ['2', '@', '', '', 0, 'VK_2'], + Digit3: ['3', '#', '', '', 0, 'VK_3'], + Digit4: ['4', '$', '', '', 0, 'VK_4'], + Digit5: ['5', '%', '', '', 0, 'VK_5'], + Digit6: ['6', '^', '', '', 0, 'VK_6'], + Digit7: ['7', '&', '', '', 0, 'VK_7'], + Digit8: ['8', '*', '', '', 0, 'VK_8'], + Digit9: ['9', '(', '', '', 0, 'VK_9'], + Digit0: ['0', ')', '', '', 0, 'VK_0'], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', '', '', 0, 'VK_SPACE'], + Minus: ['-', '_', '', '', 0, 'VK_OEM_MINUS'], + Equal: ['=', '+', '', '', 0, 'VK_OEM_PLUS'], + BracketLeft: ['[', '{', '', '', 0, 'VK_OEM_4'], + BracketRight: [']', '}', '', '', 0, 'VK_OEM_6'], + Backslash: ['\\', '|', '', '', 0, 'VK_OEM_5'], + Semicolon: [';', ':', '', '', 0, 'VK_OEM_1'], + Quote: ['\'', '"', '', '', 0, 'VK_OEM_7'], + Backquote: ['`', '~', '', '', 0, 'VK_OEM_3'], + Comma: [',', '<', '', '', 0, 'VK_OEM_COMMA'], + Period: ['.', '>', '', '', 0, 'VK_OEM_PERIOD'], + Slash: ['/', '?', '', '', 0, 'VK_OEM_2'], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + PrintScreen: [], + ScrollLock: [], + Pause: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '', '', 0, 'VK_DIVIDE'], + NumpadMultiply: ['*', '*', '', '', 0, 'VK_MULTIPLY'], + NumpadSubtract: ['-', '-', '', '', 0, 'VK_SUBTRACT'], + NumpadAdd: ['+', '+', '', '', 0, 'VK_ADD'], + NumpadEnter: [], + Numpad1: [], + Numpad2: [], + Numpad3: [], + Numpad4: [], + Numpad5: [], + Numpad6: [], + Numpad7: [], + Numpad8: [], + Numpad9: [], + Numpad0: [], + NumpadDecimal: [], + IntlBackslash: ['\\', '|', '', '', 0, 'VK_OEM_102'], + ContextMenu: [], + Power: [], + NumpadEqual: [], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + F21: [], + F22: [], + F23: [], + F24: [], + Help: [], + Undo: [], + Cut: [], + Copy: [], + Paste: [], + AudioVolumeMute: [], + AudioVolumeUp: [], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + Convert: [], + NonConvert: [], + Lang1: [], + Lang2: [], + Lang3: [], + Lang4: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [], + MediaTrackNext: [], + MediaTrackPrevious: [], + MediaStop: [], + Eject: [], + MediaPlayPause: [], + MediaSelect: [], + LaunchMail: [], + LaunchApp2: [], + LaunchApp1: [], + BrowserSearch: [], + BrowserHome: [], + BrowserBack: [], + BrowserForward: [], + BrowserStop: [], + BrowserRefresh: [], + BrowserFavorites: [] + } +}); \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/pt-br.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/pt-br.win.ts new file mode 100644 index 000000000..9bb82448a --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/pt-br.win.ts @@ -0,0 +1,170 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { name: '00000416', id: '', text: 'Portuguese (Brazilian ABNT)' }, + secondaryLayouts: [], + mapping: { + Sleep: [], + WakeUp: [], + KeyA: ['a', 'A', '', '', 0, 'VK_A'], + KeyB: ['b', 'B', '', '', 0, 'VK_B'], + KeyC: ['c', 'C', '₢', '', 0, 'VK_C'], + KeyD: ['d', 'D', '', '', 0, 'VK_D'], + KeyE: ['e', 'E', '°', '', 0, 'VK_E'], + KeyF: ['f', 'F', '', '', 0, 'VK_F'], + KeyG: ['g', 'G', '', '', 0, 'VK_G'], + KeyH: ['h', 'H', '', '', 0, 'VK_H'], + KeyI: ['i', 'I', '', '', 0, 'VK_I'], + KeyJ: ['j', 'J', '', '', 0, 'VK_J'], + KeyK: ['k', 'K', '', '', 0, 'VK_K'], + KeyL: ['l', 'L', '', '', 0, 'VK_L'], + KeyM: ['m', 'M', '', '', 0, 'VK_M'], + KeyN: ['n', 'N', '', '', 0, 'VK_N'], + KeyO: ['o', 'O', '', '', 0, 'VK_O'], + KeyP: ['p', 'P', '', '', 0, 'VK_P'], + KeyQ: ['q', 'Q', '/', '', 0, 'VK_Q'], + KeyR: ['r', 'R', '', '', 0, 'VK_R'], + KeyS: ['s', 'S', '', '', 0, 'VK_S'], + KeyT: ['t', 'T', '', '', 0, 'VK_T'], + KeyU: ['u', 'U', '', '', 0, 'VK_U'], + KeyV: ['v', 'V', '', '', 0, 'VK_V'], + KeyW: ['w', 'W', '?', '', 0, 'VK_W'], + KeyX: ['x', 'X', '', '', 0, 'VK_X'], + KeyY: ['y', 'Y', '', '', 0, 'VK_Y'], + KeyZ: ['z', 'Z', '', '', 0, 'VK_Z'], + Digit1: ['1', '!', '¹', '', 0, 'VK_1'], + Digit2: ['2', '@', '²', '', 0, 'VK_2'], + Digit3: ['3', '#', '³', '', 0, 'VK_3'], + Digit4: ['4', '$', '£', '', 0, 'VK_4'], + Digit5: ['5', '%', '¢', '', 0, 'VK_5'], + Digit6: ['6', '¨', '¬', '', 0, 'VK_6'], + Digit7: ['7', '&', '', '', 0, 'VK_7'], + Digit8: ['8', '*', '', '', 0, 'VK_8'], + Digit9: ['9', '(', '', '', 0, 'VK_9'], + Digit0: ['0', ')', '', '', 0, 'VK_0'], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', '', '', 0, 'VK_SPACE'], + Minus: ['-', '_', '', '', 0, 'VK_OEM_MINUS'], + Equal: ['=', '+', '§', '', 0, 'VK_OEM_PLUS'], + BracketLeft: ['´', '`', '', '', 0, 'VK_OEM_4'], + BracketRight: ['[', '{', 'ª', '', 0, 'VK_OEM_6'], + Backslash: [']', '}', 'º', '', 0, 'VK_OEM_5'], + Semicolon: ['ç', 'Ç', '', '', 0, 'VK_OEM_1'], + Quote: ['~', '^', '', '', 0, 'VK_OEM_7'], + Backquote: ['\'', '"', '', '', 0, 'VK_OEM_3'], + Comma: [',', '<', '', '', 0, 'VK_OEM_COMMA'], + Period: ['.', '>', '', '', 0, 'VK_OEM_PERIOD'], + Slash: [';', ':', '', '', 0, 'VK_OEM_2'], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + PrintScreen: [], + ScrollLock: [], + Pause: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '', '', 0, 'VK_DIVIDE'], + NumpadMultiply: ['*', '*', '', '', 0, 'VK_MULTIPLY'], + NumpadSubtract: ['-', '-', '', '', 0, 'VK_SUBTRACT'], + NumpadAdd: ['+', '+', '', '', 0, 'VK_ADD'], + NumpadEnter: [], + Numpad1: [], + Numpad2: [], + Numpad3: [], + Numpad4: [], + Numpad5: [], + Numpad6: [], + Numpad7: [], + Numpad8: [], + Numpad9: [], + Numpad0: [], + NumpadDecimal: [], + IntlBackslash: ['\\', '|', '', '', 0, 'VK_OEM_102'], + ContextMenu: [], + Power: [], + NumpadEqual: [], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + F21: [], + F22: [], + F23: [], + F24: [], + Help: [], + Undo: [], + Cut: [], + Copy: [], + Paste: [], + AudioVolumeMute: [], + AudioVolumeUp: [], + AudioVolumeDown: [], + NumpadComma: ['.', '.', '', '', 0, 'VK_ABNT_C2'], + IntlRo: ['/', '?', '°', '', 0, 'VK_ABNT_C1'], + KanaMode: [], + IntlYen: [], + Convert: [], + NonConvert: [], + Lang1: [], + Lang2: [], + Lang3: [], + Lang4: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [], + MediaTrackNext: [], + MediaTrackPrevious: [], + MediaStop: [], + Eject: [], + MediaPlayPause: [], + MediaSelect: [], + LaunchMail: [], + LaunchApp2: [], + LaunchApp1: [], + BrowserSearch: [], + BrowserHome: [], + BrowserBack: [], + BrowserForward: [], + + BrowserStop: [], + BrowserRefresh: [], + BrowserFavorites: [] + } +}); \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/pt.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/pt.darwin.ts new file mode 100644 index 000000000..87435fdc0 --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/pt.darwin.ts @@ -0,0 +1,132 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { id: 'com.apple.keylayout.Brazilian-Pro', lang: 'pt' }, + secondaryLayouts: [], + mapping: { + KeyA: ['a', 'A', 'å', 'Å', 0], + KeyB: ['b', 'B', '∫', 'ı', 0], + KeyC: ['c', 'C', 'ç', 'Ç', 0], + KeyD: ['d', 'D', '∂', 'Î', 0], + KeyE: ['e', 'E', '´', '´', 4], + KeyF: ['f', 'F', 'ƒ', 'Ï', 0], + KeyG: ['g', 'G', '©', '˝', 0], + KeyH: ['h', 'H', '˙', 'Ó', 0], + KeyI: ['i', 'I', 'ˆ', 'ˆ', 4], + KeyJ: ['j', 'J', '∆', 'Ô', 0], + KeyK: ['k', 'K', '˚', '', 0], + KeyL: ['l', 'L', '¬', 'Ò', 0], + KeyM: ['m', 'M', 'µ', 'Â', 0], + KeyN: ['n', 'N', '˜', '˜', 4], + KeyO: ['o', 'O', 'ø', 'Ø', 0], + KeyP: ['p', 'P', 'π', '∏', 0], + KeyQ: ['q', 'Q', 'œ', 'Œ', 0], + KeyR: ['r', 'R', '®', '‰', 0], + KeyS: ['s', 'S', 'ß', 'Í', 0], + KeyT: ['t', 'T', '†', 'ˇ', 0], + KeyU: ['u', 'U', '¨', '¨', 4], + KeyV: ['v', 'V', '√', '◊', 0], + KeyW: ['w', 'W', '∑', '„', 0], + KeyX: ['x', 'X', '≈', '˛', 0], + KeyY: ['y', 'Y', '¥', 'Á', 0], + KeyZ: ['z', 'Z', 'Ω', '¸', 0], + Digit1: ['1', '!', '¡', '⁄', 0], + Digit2: ['2', '@', '™', '€', 0], + Digit3: ['3', '#', '£', '‹', 0], + Digit4: ['4', '$', '¢', '›', 0], + Digit5: ['5', '%', '∞', 'fi', 0], + Digit6: ['6', 'ˆ', '§', 'fl', 2], + Digit7: ['7', '&', '¶', '‡', 0], + Digit8: ['8', '*', '•', '°', 0], + Digit9: ['9', '(', 'ª', '·', 0], + Digit0: ['0', ')', 'º', '‚', 0], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', ' ', ' ', 0], + Minus: ['-', '_', '–', '—', 0], + Equal: ['=', '+', '≠', '±', 0], + BracketLeft: ['[', '{', '“', '”', 0], + BracketRight: [']', '}', '‘', '’', 0], + Backslash: ['\\', '|', '«', '»', 0], + Semicolon: [';', ':', '…', 'Ú', 0], + Quote: ['\'', '"', 'æ', 'Æ', 3], + Backquote: ['`', '˜', '`', '`', 7], + Comma: [',', '<', '≤', '¯', 0], + Period: ['.', '>', '≥', '˘', 0], + Slash: ['/', '?', '÷', '¿', 0], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '/', '/', 0], + NumpadMultiply: ['*', '*', '*', '*', 0], + NumpadSubtract: ['-', '-', '-', '-', 0], + NumpadAdd: ['+', '+', '+', '+', 0], + NumpadEnter: [], + Numpad1: ['1', '1', '1', '1', 0], + Numpad2: ['2', '2', '2', '2', 0], + Numpad3: ['3', '3', '3', '3', 0], + Numpad4: ['4', '4', '4', '4', 0], + Numpad5: ['5', '5', '5', '5', 0], + Numpad6: ['6', '6', '6', '6', 0], + Numpad7: ['7', '7', '7', '7', 0], + Numpad8: ['8', '8', '8', '8', 0], + Numpad9: ['9', '9', '9', '9', 0], + Numpad0: ['0', '0', '0', '0', 0], + NumpadDecimal: ['.', '.', '.', '.', 0], + IntlBackslash: ['§', '±', '§', '±', 0], + ContextMenu: [], + NumpadEqual: ['=', '=', '=', '=', 0], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + AudioVolumeMute: [], + AudioVolumeUp: ['', '=', '', '=', 0], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [] + } +}); diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/pt.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/pt.win.ts new file mode 100644 index 000000000..456a53765 --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/pt.win.ts @@ -0,0 +1,170 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { name: '00000816', id: '', text: 'Portuguese' }, + secondaryLayouts: [], + mapping: { + Sleep: [], + WakeUp: [], + KeyA: ['a', 'A', '', '', 0, 'VK_A'], + KeyB: ['b', 'B', '', '', 0, 'VK_B'], + KeyC: ['c', 'C', '', '', 0, 'VK_C'], + KeyD: ['d', 'D', '', '', 0, 'VK_D'], + KeyE: ['e', 'E', '€', '', 0, 'VK_E'], + KeyF: ['f', 'F', '', '', 0, 'VK_F'], + KeyG: ['g', 'G', '', '', 0, 'VK_G'], + KeyH: ['h', 'H', '', '', 0, 'VK_H'], + KeyI: ['i', 'I', '', '', 0, 'VK_I'], + KeyJ: ['j', 'J', '', '', 0, 'VK_J'], + KeyK: ['k', 'K', '', '', 0, 'VK_K'], + KeyL: ['l', 'L', '', '', 0, 'VK_L'], + KeyM: ['m', 'M', '', '', 0, 'VK_M'], + KeyN: ['n', 'N', '', '', 0, 'VK_N'], + KeyO: ['o', 'O', '', '', 0, 'VK_O'], + KeyP: ['p', 'P', '', '', 0, 'VK_P'], + KeyQ: ['q', 'Q', '', '', 0, 'VK_Q'], + KeyR: ['r', 'R', '', '', 0, 'VK_R'], + KeyS: ['s', 'S', '', '', 0, 'VK_S'], + KeyT: ['t', 'T', '', '', 0, 'VK_T'], + KeyU: ['u', 'U', '', '', 0, 'VK_U'], + KeyV: ['v', 'V', '', '', 0, 'VK_V'], + KeyW: ['w', 'W', '', '', 0, 'VK_W'], + KeyX: ['x', 'X', '', '', 0, 'VK_X'], + KeyY: ['y', 'Y', '', '', 0, 'VK_Y'], + KeyZ: ['z', 'Z', '', '', 0, 'VK_Z'], + Digit1: ['1', '!', '', '', 0, 'VK_1'], + Digit2: ['2', '"', '@', '', 0, 'VK_2'], + Digit3: ['3', '#', '£', '', 0, 'VK_3'], + Digit4: ['4', '$', '§', '', 0, 'VK_4'], + Digit5: ['5', '%', '€', '', 0, 'VK_5'], + Digit6: ['6', '&', '', '', 0, 'VK_6'], + Digit7: ['7', '/', '{', '', 0, 'VK_7'], + Digit8: ['8', '(', '[', '', 0, 'VK_8'], + Digit9: ['9', ')', ']', '', 0, 'VK_9'], + Digit0: ['0', '=', '}', '', 0, 'VK_0'], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', '', '', 0, 'VK_SPACE'], + Minus: ['\'', '?', '', '', 0, 'VK_OEM_4'], + Equal: ['«', '»', '', '', 0, 'VK_OEM_6'], + BracketLeft: ['+', '*', '¨', '', 0, 'VK_OEM_PLUS'], + BracketRight: ['´', '`', ']', '', 0, 'VK_OEM_1'], + Backslash: ['~', '^', '', '', 0, 'VK_OEM_2'], + Semicolon: ['ç', 'Ç', '', '', 0, 'VK_OEM_3'], + Quote: ['º', 'ª', '', '', 0, 'VK_OEM_7'], + Backquote: ['\\', '|', '', '', 0, 'VK_OEM_5'], + Comma: [',', ';', '', '', 0, 'VK_OEM_COMMA'], + Period: ['.', ':', '', '', 0, 'VK_OEM_PERIOD'], + Slash: ['-', '_', '', '', 0, 'VK_OEM_MINUS'], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + PrintScreen: [], + ScrollLock: [], + Pause: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '', '', 0, 'VK_DIVIDE'], + NumpadMultiply: ['*', '*', '', '', 0, 'VK_MULTIPLY'], + NumpadSubtract: ['-', '-', '', '', 0, 'VK_SUBTRACT'], + NumpadAdd: ['+', '+', '', '', 0, 'VK_ADD'], + NumpadEnter: [], + Numpad1: [], + Numpad2: [], + Numpad3: [], + Numpad4: [], + Numpad5: [], + Numpad6: [], + Numpad7: [], + Numpad8: [], + Numpad9: [], + Numpad0: [], + NumpadDecimal: [], + IntlBackslash: ['<', '>', '', '', 0, 'VK_OEM_102'], + ContextMenu: [], + Power: [], + NumpadEqual: [], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + F21: [], + F22: [], + F23: [], + F24: [], + Help: [], + Undo: [], + Cut: [], + Copy: [], + Paste: [], + AudioVolumeMute: [], + AudioVolumeUp: [], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + Convert: [], + NonConvert: [], + Lang1: [], + Lang2: [], + Lang3: [], + Lang4: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [], + MediaTrackNext: [], + MediaTrackPrevious: [], + MediaStop: [], + Eject: [], + MediaPlayPause: [], + MediaSelect: [], + LaunchMail: [], + LaunchApp2: [], + LaunchApp1: [], + BrowserSearch: [], + BrowserHome: [], + BrowserBack: [], + BrowserForward: [], + BrowserStop: [], + BrowserRefresh: [], + BrowserFavorites: [] + } + +}); \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/ru.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/ru.darwin.ts new file mode 100644 index 000000000..5eea5ac38 --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/ru.darwin.ts @@ -0,0 +1,132 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { id: 'com.apple.keylayout.Russian', lang: 'ru', localizedName: 'Russian' }, + secondaryLayouts: [], + mapping: { + KeyA: ['ф', 'Ф', 'ƒ', 'ƒ', 0], + KeyB: ['и', 'И', 'и', 'И', 0], + KeyC: ['с', 'С', '≠', '≠', 0], + KeyD: ['в', 'В', 'ћ', 'Ћ', 0], + KeyE: ['у', 'У', 'ќ', 'Ќ', 0], + KeyF: ['а', 'А', '÷', '÷', 0], + KeyG: ['п', 'П', '©', '©', 0], + KeyH: ['р', 'Р', '₽', '₽', 0], + KeyI: ['ш', 'Ш', 'ѕ', 'Ѕ', 0], + KeyJ: ['о', 'О', '°', '•', 0], + KeyK: ['л', 'Л', 'љ', 'Љ', 0], + KeyL: ['д', 'Д', '∆', '∆', 0], + KeyM: ['ь', 'Ь', '~', '~', 0], + KeyN: ['т', 'Т', '™', '™', 0], + KeyO: ['щ', 'Щ', 'ў', 'Ў', 0], + KeyP: ['з', 'З', '‘', '’', 0], + KeyQ: ['й', 'Й', 'ј', 'Ј', 0], + KeyR: ['к', 'К', '®', '®', 0], + KeyS: ['ы', 'Ы', 'ы', 'Ы', 0], + KeyT: ['е', 'Е', '†', '†', 0], + KeyU: ['г', 'Г', 'ѓ', 'Ѓ', 0], + KeyV: ['м', 'М', 'µ', 'µ', 0], + KeyW: ['ц', 'Ц', 'џ', 'Џ', 0], + KeyX: ['ч', 'Ч', '≈', '≈', 0], + KeyY: ['н', 'Н', 'њ', 'Њ', 0], + KeyZ: ['я', 'Я', 'ђ', 'Ђ', 0], + Digit1: ['1', '!', '!', '|', 0], + Digit2: ['2', '"', '@', '"', 0], + Digit3: ['3', '№', '#', '£', 0], + Digit4: ['4', '%', '$', '€', 0], + Digit5: ['5', ':', '%', '∞', 0], + Digit6: ['6', ',', '^', '¬', 0], + Digit7: ['7', '.', '&', '¶', 0], + Digit8: ['8', ';', '*', '√', 0], + Digit9: ['9', '(', '{', '\'', 0], + Digit0: ['0', ')', '}', '`', 0], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', ' ', ' ', 0], + Minus: ['-', '_', '–', '—', 0], + Equal: ['=', '+', '»', '«', 0], + BracketLeft: ['х', 'Х', '“', '”', 0], + BracketRight: ['ъ', 'Ъ', 'ъ', 'Ъ', 0], + Backslash: ['ё', 'Ё', 'ё', 'Ё', 0], + Semicolon: ['ж', 'Ж', '…', '…', 0], + Quote: ['э', 'Э', 'э', 'Э', 0], + Backquote: [']', '[', ']', '[', 0], + Comma: ['б', 'Б', '≤', '<', 0], + Period: ['ю', 'Ю', '≥', '>', 0], + Slash: ['/', '?', '“', '„', 0], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '/', '/', 0], + NumpadMultiply: ['*', '*', '*', '*', 0], + NumpadSubtract: ['-', '-', '-', '-', 0], + NumpadAdd: ['+', '+', '+', '+', 0], + NumpadEnter: [], + Numpad1: ['1', '1', '1', '1', 0], + Numpad2: ['2', '2', '2', '2', 0], + Numpad3: ['3', '3', '3', '3', 0], + Numpad4: ['4', '4', '4', '4', 0], + Numpad5: ['5', '5', '5', '5', 0], + Numpad6: ['6', '6', '6', '6', 0], + Numpad7: ['7', '7', '7', '7', 0], + Numpad8: ['8', '8', '8', '8', 0], + Numpad9: ['9', '9', '9', '9', 0], + Numpad0: ['0', '0', '0', '0', 0], + NumpadDecimal: [',', '.', ',', ',', 0], + IntlBackslash: ['>', '<', '§', '±', 0], + ContextMenu: [], + NumpadEqual: ['=', '=', '=', '=', 0], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + AudioVolumeMute: [], + AudioVolumeUp: ['', '=', '', '', 0], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [] + } +}); \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/ru.linux.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/ru.linux.ts new file mode 100644 index 000000000..b13adb0d9 --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/ru.linux.ts @@ -0,0 +1,187 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { model: 'pc104', layout: 'ru', variant: ',', options: '', rules: 'base' }, + secondaryLayouts: [], + mapping: { + Sleep: [], + WakeUp: [], + KeyA: ['ф', 'Ф', 'ф', 'Ф', 0], + KeyB: ['и', 'И', 'и', 'И', 0], + KeyC: ['с', 'С', 'с', 'С', 0], + KeyD: ['в', 'В', 'в', 'В', 0], + KeyE: ['у', 'У', 'у', 'У', 0], + KeyF: ['а', 'А', 'а', 'А', 0], + KeyG: ['п', 'П', 'п', 'П', 0], + KeyH: ['р', 'Р', 'р', 'Р', 0], + KeyI: ['ш', 'Ш', 'ш', 'Ш', 0], + KeyJ: ['о', 'О', 'о', 'О', 0], + KeyK: ['л', 'Л', 'л', 'Л', 0], + KeyL: ['д', 'Д', 'д', 'Д', 0], + KeyM: ['ь', 'Ь', 'ь', 'Ь', 0], + KeyN: ['т', 'Т', 'т', 'Т', 0], + KeyO: ['щ', 'Щ', 'щ', 'Щ', 0], + KeyP: ['з', 'З', 'з', 'З', 0], + KeyQ: ['й', 'Й', 'й', 'Й', 0], + KeyR: ['к', 'К', 'к', 'К', 0], + KeyS: ['ы', 'Ы', 'ы', 'Ы', 0], + KeyT: ['е', 'Е', 'е', 'Е', 0], + KeyU: ['г', 'Г', 'г', 'Г', 0], + KeyV: ['м', 'М', 'м', 'М', 0], + KeyW: ['ц', 'Ц', 'ц', 'Ц', 0], + KeyX: ['ч', 'Ч', 'ч', 'Ч', 0], + KeyY: ['н', 'Н', 'н', 'Н', 0], + KeyZ: ['я', 'Я', 'я', 'Я', 0], + Digit1: ['1', '!', '1', '!', 0], + Digit2: ['2', '"', '2', '"', 0], + Digit3: ['3', '№', '3', '№', 0], + Digit4: ['4', ';', '4', ';', 0], + Digit5: ['5', '%', '5', '%', 0], + Digit6: ['6', ':', '6', ':', 0], + Digit7: ['7', '?', '7', '?', 0], + Digit8: ['8', '*', '₽', '', 0], + Digit9: ['9', '(', '9', '(', 0], + Digit0: ['0', ')', '0', ')', 0], + Enter: ['\r', '\r', '\r', '\r', 0], + Escape: ['\u001b', '\u001b', '\u001b', '\u001b', 0], + Backspace: ['\b', '\b', '\b', '\b', 0], + Tab: ['\t', '', '\t', '', 0], + Space: [' ', ' ', ' ', ' ', 0], + Minus: ['-', '_', '-', '_', 0], + Equal: ['=', '+', '=', '+', 0], + BracketLeft: ['х', 'Х', 'х', 'Х', 0], + BracketRight: ['ъ', 'Ъ', 'ъ', 'Ъ', 0], + Backslash: ['\\', '/', '\\', '/', 0], + Semicolon: ['ж', 'Ж', 'ж', 'Ж', 0], + Quote: ['э', 'Э', 'э', 'Э', 0], + Backquote: ['ё', 'Ё', 'ё', 'Ё', 0], + Comma: ['б', 'Б', 'б', 'Б', 0], + Period: ['ю', 'Ю', 'ю', 'Ю', 0], + Slash: ['.', ',', '.', ',', 0], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + PrintScreen: ['', '', '', '', 0], + ScrollLock: [], + Pause: [], + Insert: [], + Home: [], + PageUp: ['/', '/', '/', '/', 0], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: [], + NumpadMultiply: ['*', '*', '*', '*', 0], + NumpadSubtract: ['-', '-', '-', '-', 0], + NumpadAdd: ['+', '+', '+', '+', 0], + NumpadEnter: [], + Numpad1: ['', '1', '', '1', 0], + Numpad2: ['', '2', '', '2', 0], + Numpad3: ['', '3', '', '3', 0], + Numpad4: ['', '4', '', '4', 0], + Numpad5: ['', '5', '', '5', 0], + Numpad6: ['', '6', '', '6', 0], + Numpad7: ['', '7', '', '7', 0], + Numpad8: ['', '8', '', '8', 0], + Numpad9: ['', '9', '', '9', 0], + Numpad0: ['', '0', '', '0', 0], + NumpadDecimal: ['', ',', '', ',', 0], + IntlBackslash: ['/', '|', '|', '¦', 0], + ContextMenu: [], + Power: [], + NumpadEqual: [], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + F21: [], + F22: [], + F23: [], + F24: [], + Open: [], + Help: [], + Select: [], + Again: [], + Undo: [], + Cut: [], + Copy: [], + Paste: [], + Find: [], + AudioVolumeMute: [], + AudioVolumeUp: [], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + Convert: [], + NonConvert: [], + Lang1: [], + Lang2: [], + Lang3: [], + Lang4: [], + Lang5: [], + NumpadParenLeft: [], + NumpadParenRight: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: ['\r', '\r', '\r', '\r', 0], + MetaRight: ['.', '.', '.', '.', 0], + BrightnessUp: [], + BrightnessDown: [], + MediaPlay: [], + MediaRecord: [], + MediaFastForward: [], + MediaRewind: [], + MediaTrackNext: [], + MediaTrackPrevious: [], + MediaStop: [], + Eject: [], + MediaPlayPause: [], + MediaSelect: [], + LaunchMail: [], + LaunchApp2: [], + LaunchApp1: [], + SelectTask: [], + LaunchScreenSaver: [], + BrowserSearch: [], + BrowserHome: [], + BrowserBack: [], + BrowserForward: [], + BrowserStop: [], + BrowserRefresh: [], + BrowserFavorites: [], + MailReply: [], + MailForward: [], + MailSend: [] + } +}); diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/ru.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/ru.win.ts new file mode 100644 index 000000000..0da492a10 --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/ru.win.ts @@ -0,0 +1,169 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { name: '00000419', id: '', text: 'Russian' }, + secondaryLayouts: [], + mapping: { + Sleep: [], + WakeUp: [], + KeyA: ['ф', 'Ф', '', '', 0, 'VK_A'], + KeyB: ['и', 'И', '', '', 0, 'VK_B'], + KeyC: ['с', 'С', '', '', 0, 'VK_C'], + KeyD: ['в', 'В', '', '', 0, 'VK_D'], + KeyE: ['у', 'У', '', '', 0, 'VK_E'], + KeyF: ['а', 'А', '', '', 0, 'VK_F'], + KeyG: ['п', 'П', '', '', 0, 'VK_G'], + KeyH: ['р', 'Р', '', '', 0, 'VK_H'], + KeyI: ['ш', 'Ш', '', '', 0, 'VK_I'], + KeyJ: ['о', 'О', '', '', 0, 'VK_J'], + KeyK: ['л', 'Л', '', '', 0, 'VK_K'], + KeyL: ['д', 'Д', '', '', 0, 'VK_L'], + KeyM: ['ь', 'Ь', '', '', 0, 'VK_M'], + KeyN: ['т', 'Т', '', '', 0, 'VK_N'], + KeyO: ['щ', 'Щ', '', '', 0, 'VK_O'], + KeyP: ['з', 'З', '', '', 0, 'VK_P'], + KeyQ: ['й', 'Й', '', '', 0, 'VK_Q'], + KeyR: ['к', 'К', '', '', 0, 'VK_R'], + KeyS: ['ы', 'Ы', '', '', 0, 'VK_S'], + KeyT: ['е', 'Е', '', '', 0, 'VK_T'], + KeyU: ['г', 'Г', '', '', 0, 'VK_U'], + KeyV: ['м', 'М', '', '', 0, 'VK_V'], + KeyW: ['ц', 'Ц', '', '', 0, 'VK_W'], + KeyX: ['ч', 'Ч', '', '', 0, 'VK_X'], + KeyY: ['н', 'Н', '', '', 0, 'VK_Y'], + KeyZ: ['я', 'Я', '', '', 0, 'VK_Z'], + Digit1: ['1', '!', '', '', 0, 'VK_1'], + Digit2: ['2', '"', '', '', 0, 'VK_2'], + Digit3: ['3', '№', '', '', 0, 'VK_3'], + Digit4: ['4', ';', '', '', 0, 'VK_4'], + Digit5: ['5', '%', '', '', 0, 'VK_5'], + Digit6: ['6', ':', '', '', 0, 'VK_6'], + Digit7: ['7', '?', '', '', 0, 'VK_7'], + Digit8: ['8', '*', '₽', '', 0, 'VK_8'], + Digit9: ['9', '(', '', '', 0, 'VK_9'], + Digit0: ['0', ')', '', '', 0, 'VK_0'], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', '', '', 0, 'VK_SPACE'], + Minus: ['-', '_', '', '', 0, 'VK_OEM_MINUS'], + Equal: ['=', '+', '', '', 0, 'VK_OEM_PLUS'], + BracketLeft: ['х', 'Х', '', '', 0, 'VK_OEM_4'], + BracketRight: ['ъ', 'Ъ', '', '', 0, 'VK_OEM_6'], + Backslash: ['\\', '/', '', '', 0, 'VK_OEM_5'], + Semicolon: ['ж', 'Ж', '', '', 0, 'VK_OEM_1'], + Quote: ['э', 'Э', '', '', 0, 'VK_OEM_7'], + Backquote: ['ё', 'Ё', '', '', 0, 'VK_OEM_3'], + Comma: ['б', 'Б', '', '', 0, 'VK_OEM_COMMA'], + Period: ['ю', 'Ю', '', '', 0, 'VK_OEM_PERIOD'], + Slash: ['.', ',', '', '', 0, 'VK_OEM_2'], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + PrintScreen: [], + ScrollLock: [], + Pause: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '', '', 0, 'VK_DIVIDE'], + NumpadMultiply: ['*', '*', '', '', 0, 'VK_MULTIPLY'], + NumpadSubtract: ['-', '-', '', '', 0, 'VK_SUBTRACT'], + NumpadAdd: ['+', '+', '', '', 0, 'VK_ADD'], + NumpadEnter: [], + Numpad1: [], + Numpad2: [], + Numpad3: [], + Numpad4: [], + Numpad5: [], + Numpad6: [], + Numpad7: [], + Numpad8: [], + Numpad9: [], + Numpad0: [], + NumpadDecimal: [], + IntlBackslash: ['\\', '/', '', '', 0, 'VK_OEM_102'], + ContextMenu: [], + Power: [], + NumpadEqual: [], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + F21: [], + F22: [], + F23: [], + F24: [], + Help: [], + Undo: [], + Cut: [], + Copy: [], + Paste: [], + AudioVolumeMute: [], + AudioVolumeUp: [], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + Convert: [], + NonConvert: [], + Lang1: [], + Lang2: [], + Lang3: [], + Lang4: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [], + MediaTrackNext: [], + MediaTrackPrevious: [], + MediaStop: [], + Eject: [], + MediaPlayPause: [], + MediaSelect: [], + LaunchMail: [], + LaunchApp2: [], + LaunchApp1: [], + BrowserSearch: [], + BrowserHome: [], + BrowserBack: [], + BrowserForward: [], + BrowserStop: [], + BrowserRefresh: [], + BrowserFavorites: [] + } +}); \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/sv.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/sv.darwin.ts new file mode 100644 index 000000000..6d80477a6 --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/sv.darwin.ts @@ -0,0 +1,132 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { id: 'com.apple.keylayout.Swedish-Pro', lang: 'sv', localizedName: 'Swedish - Pro' }, + secondaryLayouts: [], + mapping: { + KeyA: ['a', 'A', '', '◊', 0], + KeyB: ['b', 'B', '›', '»', 0], + KeyC: ['c', 'C', 'ç', 'Ç', 0], + KeyD: ['d', 'D', '∂', '∆', 0], + KeyE: ['e', 'E', 'é', 'É', 0], + KeyF: ['f', 'F', 'ƒ', '∫', 0], + KeyG: ['g', 'G', '¸', '¯', 0], + KeyH: ['h', 'H', '˛', '˘', 0], + KeyI: ['i', 'I', 'ı', 'ˆ', 0], + KeyJ: ['j', 'J', '√', '¬', 0], + KeyK: ['k', 'K', 'ª', 'º', 0], + KeyL: ['l', 'L', 'fi', 'fl', 0], + KeyM: ['m', 'M', '’', '”', 0], + KeyN: ['n', 'N', '‘', '“', 0], + KeyO: ['o', 'O', 'œ', 'Œ', 0], + KeyP: ['p', 'P', 'π', '∏', 0], + KeyQ: ['q', 'Q', '•', '°', 0], + KeyR: ['r', 'R', '®', '√', 0], + KeyS: ['s', 'S', 'ß', '∑', 0], + KeyT: ['t', 'T', '†', '‡', 0], + KeyU: ['u', 'U', 'ü', 'Ü', 0], + KeyV: ['v', 'V', '‹', '«', 0], + KeyW: ['w', 'W', 'Ω', '˝', 0], + KeyX: ['x', 'X', '≈', 'ˇ', 0], + KeyY: ['y', 'Y', 'µ', '˜', 0], + KeyZ: ['z', 'Z', '÷', '⁄', 0], + Digit1: ['1', '!', '©', '¡', 0], + Digit2: ['2', '"', '@', '”', 0], + Digit3: ['3', '#', '£', '¥', 0], + Digit4: ['4', '€', '$', '¢', 0], + Digit5: ['5', '%', '∞', '‰', 0], + Digit6: ['6', '&', '§', '¶', 0], + Digit7: ['7', '/', '|', '\\', 0], + Digit8: ['8', '(', '[', '{', 0], + Digit9: ['9', ')', ']', '}', 0], + Digit0: ['0', '=', '≈', '≠', 0], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', ' ', ' ', 0], + Minus: ['+', '?', '±', '¿', 0], + Equal: ['´', '`', '´', '`', 3], + BracketLeft: ['å', 'Å', '˙', '˚', 0], + BracketRight: ['¨', '^', '~', '^', 7], + Backslash: ['\'', '*', '™', '’', 0], + Semicolon: ['ö', 'Ö', 'ø', 'Ø', 0], + Quote: ['ä', 'Ä', 'æ', 'Æ', 0], + Backquote: ['<', '>', '≤', '≥', 0], + Comma: [',', ';', '‚', '„', 0], + Period: ['.', ':', '…', '·', 0], + Slash: ['-', '_', '–', '—', 0], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '/', '/', 0], + NumpadMultiply: ['*', '*', '*', '*', 0], + NumpadSubtract: ['-', '-', '-', '-', 0], + NumpadAdd: ['+', '+', '+', '+', 0], + NumpadEnter: [], + Numpad1: ['1', '1', '1', '1', 0], + Numpad2: ['2', '2', '2', '2', 0], + Numpad3: ['3', '3', '3', '3', 0], + Numpad4: ['4', '4', '4', '4', 0], + Numpad5: ['5', '5', '5', '5', 0], + Numpad6: ['6', '6', '6', '6', 0], + Numpad7: ['7', '7', '7', '7', 0], + Numpad8: ['8', '8', '8', '8', 0], + Numpad9: ['9', '9', '9', '9', 0], + Numpad0: ['0', '0', '0', '0', 0], + NumpadDecimal: [',', '.', ',', '.', 0], + IntlBackslash: ['§', '°', '¶', '•', 0], + ContextMenu: [], + NumpadEqual: ['=', '=', '=', '=', 0], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + AudioVolumeMute: [], + AudioVolumeUp: ['', '=', '', '=', 0], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [] + } +}); \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/sv.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/sv.win.ts new file mode 100644 index 000000000..c7128b5c9 --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/sv.win.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 { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { name: '0000041D', id: '', text: 'Swedish' }, + secondaryLayouts: [ + { name: '0000040B', id: '', text: 'Finnish' } + ], + mapping: { + Sleep: [], + WakeUp: [], + KeyA: ['a', 'A', '', '', 0, 'VK_A'], + KeyB: ['b', 'B', '', '', 0, 'VK_B'], + KeyC: ['c', 'C', '', '', 0, 'VK_C'], + KeyD: ['d', 'D', '', '', 0, 'VK_D'], + KeyE: ['e', 'E', '€', '', 0, 'VK_E'], + KeyF: ['f', 'F', '', '', 0, 'VK_F'], + KeyG: ['g', 'G', '', '', 0, 'VK_G'], + KeyH: ['h', 'H', '', '', 0, 'VK_H'], + KeyI: ['i', 'I', '', '', 0, 'VK_I'], + KeyJ: ['j', 'J', '', '', 0, 'VK_J'], + KeyK: ['k', 'K', '', '', 0, 'VK_K'], + KeyL: ['l', 'L', '', '', 0, 'VK_L'], + KeyM: ['m', 'M', 'µ', '', 0, 'VK_M'], + KeyN: ['n', 'N', '', '', 0, 'VK_N'], + KeyO: ['o', 'O', '', '', 0, 'VK_O'], + KeyP: ['p', 'P', '', '', 0, 'VK_P'], + KeyQ: ['q', 'Q', '', '', 0, 'VK_Q'], + KeyR: ['r', 'R', '', '', 0, 'VK_R'], + KeyS: ['s', 'S', '', '', 0, 'VK_S'], + KeyT: ['t', 'T', '', '', 0, 'VK_T'], + KeyU: ['u', 'U', '', '', 0, 'VK_U'], + KeyV: ['v', 'V', '', '', 0, 'VK_V'], + KeyW: ['w', 'W', '', '', 0, 'VK_W'], + KeyX: ['x', 'X', '', '', 0, 'VK_X'], + KeyY: ['y', 'Y', '', '', 0, 'VK_Y'], + KeyZ: ['z', 'Z', '', '', 0, 'VK_Z'], + Digit1: ['1', '!', '', '', 0, 'VK_1'], + Digit2: ['2', '"', '@', '', 0, 'VK_2'], + Digit3: ['3', '#', '£', '', 0, 'VK_3'], + Digit4: ['4', '¤', '$', '', 0, 'VK_4'], + Digit5: ['5', '%', '€', '', 0, 'VK_5'], + Digit6: ['6', '&', '', '', 0, 'VK_6'], + Digit7: ['7', '/', '{', '', 0, 'VK_7'], + Digit8: ['8', '(', '[', '', 0, 'VK_8'], + Digit9: ['9', ')', ']', '', 0, 'VK_9'], + Digit0: ['0', '=', '}', '', 0, 'VK_0'], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', '', '', 0, 'VK_SPACE'], + Minus: ['+', '?', '\\', '', 0, 'VK_OEM_PLUS'], + Equal: ['´', '`', '', '', 0, 'VK_OEM_4'], + BracketLeft: ['å', 'Å', '', '', 0, 'VK_OEM_6'], + BracketRight: ['¨', '^', '~', '', 0, 'VK_OEM_1'], + Backslash: ['\'', '*', '', '', 0, 'VK_OEM_2'], + Semicolon: ['ö', 'Ö', '', '', 0, 'VK_OEM_3'], + Quote: ['ä', 'Ä', '', '', 0, 'VK_OEM_7'], + Backquote: ['§', '½', '', '', 0, 'VK_OEM_5'], + Comma: [',', ';', '', '', 0, 'VK_OEM_COMMA'], + Period: ['.', ':', '', '', 0, 'VK_OEM_PERIOD'], + Slash: ['-', '_', '', '', 0, 'VK_OEM_MINUS'], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + PrintScreen: [], + ScrollLock: [], + Pause: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '', '', 0, 'VK_DIVIDE'], + NumpadMultiply: ['*', '*', '', '', 0, 'VK_MULTIPLY'], + NumpadSubtract: ['-', '-', '', '', 0, 'VK_SUBTRACT'], + NumpadAdd: ['+', '+', '', '', 0, 'VK_ADD'], + NumpadEnter: [], + Numpad1: [], + Numpad2: [], + Numpad3: [], + Numpad4: [], + Numpad5: [], + Numpad6: [], + Numpad7: [], + Numpad8: [], + Numpad9: [], + Numpad0: [], + NumpadDecimal: [], + IntlBackslash: ['<', '>', '|', '', 0, 'VK_OEM_102'], + ContextMenu: [], + Power: [], + NumpadEqual: [], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + F21: [], + F22: [], + F23: [], + F24: [], + Help: [], + Undo: [], + Cut: [], + Copy: [], + Paste: [], + AudioVolumeMute: [], + AudioVolumeUp: [], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + Convert: [], + NonConvert: [], + Lang1: [], + Lang2: [], + Lang3: [], + Lang4: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [], + MediaTrackNext: [], + MediaTrackPrevious: [], + MediaStop: [], + Eject: [], + MediaPlayPause: [], + MediaSelect: [], + LaunchMail: [], + LaunchApp2: [], + LaunchApp1: [], + BrowserSearch: [], + BrowserHome: [], + BrowserBack: [], + BrowserForward: [], + BrowserStop: [], + BrowserRefresh: [], + BrowserFavorites: [] + } +}); diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/thai.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/thai.win.ts new file mode 100644 index 000000000..be85bfedd --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/thai.win.ts @@ -0,0 +1,168 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { name: '0000041E', id: '', text: 'Thai Kedmanee' }, + secondaryLayouts: [], + mapping: { + Sleep: [], + WakeUp: [], + KeyA: ['ฟ', 'ฤ', '', '', 0, 'VK_A'], + KeyB: ['ิ', 'ฺ', '', '', 0, 'VK_B'], + KeyC: ['แ', 'ฉ', '', '', 0, 'VK_C'], + KeyD: ['ก', 'ฏ', '', '', 0, 'VK_D'], + KeyE: ['ำ', 'ฎ', '', '', 0, 'VK_E'], + KeyF: ['ด', 'โ', '', '', 0, 'VK_F'], + KeyG: ['เ', 'ฌ', '', '', 0, 'VK_G'], + KeyH: ['้', '็', '', '', 0, 'VK_H'], + KeyI: ['ร', 'ณ', '', '', 0, 'VK_I'], + KeyJ: ['่', '๋', '', '', 0, 'VK_J'], + KeyK: ['า', 'ษ', '', '', 0, 'VK_K'], + KeyL: ['ส', 'ศ', '', '', 0, 'VK_L'], + KeyM: ['ท', '?', '', '', 0, 'VK_M'], + KeyN: ['ื', '์', '', '', 0, 'VK_N'], + KeyO: ['น', 'ฯ', '', '', 0, 'VK_O'], + KeyP: ['ย', 'ญ', '', '', 0, 'VK_P'], + KeyQ: ['ๆ', '๐', '', '', 0, 'VK_Q'], + KeyR: ['พ', 'ฑ', '', '', 0, 'VK_R'], + KeyS: ['ห', 'ฆ', '', '', 0, 'VK_S'], + KeyT: ['ะ', 'ธ', '', '', 0, 'VK_T'], + KeyU: ['ี', '๊', '', '', 0, 'VK_U'], + KeyV: ['อ', 'ฮ', '', '', 0, 'VK_V'], + KeyW: ['ไ', '"', '', '', 0, 'VK_W'], + KeyX: ['ป', ')', '', '', 0, 'VK_X'], + KeyY: ['ั', 'ํ', '', '', 0, 'VK_Y'], + KeyZ: ['ผ', '(', '', '', 0, 'VK_Z'], + Digit1: ['ๅ', '+', '', '', 0, 'VK_1'], + Digit2: ['/', '๑', '', '', 0, 'VK_2'], + Digit3: ['-', '๒', '', '', 0, 'VK_3'], + Digit4: ['ภ', '๓', '', '', 0, 'VK_4'], + Digit5: ['ถ', '๔', '', '', 0, 'VK_5'], + Digit6: ['ุ', 'ู', '', '', 0, 'VK_6'], + Digit7: ['ึ', '฿', '', '', 0, 'VK_7'], + Digit8: ['ค', '๕', '', '', 0, 'VK_8'], + Digit9: ['ต', '๖', '', '', 0, 'VK_9'], + Digit0: ['จ', '๗', '', '', 0, 'VK_0'], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', '', '', 0, 'VK_SPACE'], + Minus: ['ข', '๘', '', '', 0, 'VK_OEM_MINUS'], + Equal: ['ช', '๙', '', '', 0, 'VK_OEM_PLUS'], + BracketLeft: ['บ', 'ฐ', '', '', 0, 'VK_OEM_4'], + BracketRight: ['ล', ',', '', '', 0, 'VK_OEM_6'], + Backslash: ['ฃ', 'ฅ', '', '', 0, 'VK_OEM_5'], + Semicolon: ['ว', 'ซ', '', '', 0, 'VK_OEM_1'], + Quote: ['ง', '.', '', '', 0, 'VK_OEM_7'], + Backquote: ['_', '%', '', '', 0, 'VK_OEM_3'], + Comma: ['ม', 'ฒ', '', '', 0, 'VK_OEM_COMMA'], + Period: ['ใ', 'ฬ', '', '', 0, 'VK_OEM_PERIOD'], + Slash: ['ฝ', 'ฦ', '', '', 0, 'VK_OEM_2'], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + PrintScreen: [], + ScrollLock: [], + Pause: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '', '', 0, 'VK_DIVIDE'], + NumpadMultiply: ['*', '*', '', '', 0, 'VK_MULTIPLY'], + NumpadSubtract: ['-', '-', '', '', 0, 'VK_SUBTRACT'], + NumpadAdd: ['+', '+', '', '', 0, 'VK_ADD'], + NumpadEnter: [], + Numpad1: [], + Numpad2: [], + Numpad3: [], + Numpad4: [], + Numpad5: [], + Numpad6: [], + Numpad7: [], + Numpad8: [], + Numpad9: [], + Numpad0: [], + NumpadDecimal: [], + IntlBackslash: ['ฃ', 'ฅ', '', '', 0, 'VK_OEM_102'], + ContextMenu: [], + Power: [], + NumpadEqual: [], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + F21: [], + F22: [], + F23: [], + F24: [], + Help: [], + Undo: [], + Cut: [], + Copy: [], + Paste: [], + AudioVolumeMute: [], + AudioVolumeUp: [], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + Convert: [], + NonConvert: [], + Lang1: [], + Lang2: [], + Lang3: [], + Lang4: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [], + MediaTrackNext: [], + MediaTrackPrevious: [], + MediaStop: [], + Eject: [], + MediaPlayPause: [], + MediaSelect: [], + LaunchMail: [], + LaunchApp2: [], + LaunchApp1: [], + BrowserSearch: [], + BrowserHome: [], + BrowserBack: [], + BrowserForward: [], + BrowserStop: [], + BrowserRefresh: [], + BrowserFavorites: [] + } +}); diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/tr.win.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/tr.win.ts new file mode 100644 index 000000000..955b03f5f --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/tr.win.ts @@ -0,0 +1,168 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { name: '0000041F', id: '', text: 'Turkish Q' }, + secondaryLayouts: [], + mapping: { + Sleep: [], + WakeUp: [], + KeyA: ['a', 'A', 'æ', 'Æ', 0, 'VK_A'], + KeyB: ['b', 'B', '', '', 0, 'VK_B'], + KeyC: ['c', 'C', '', '', 0, 'VK_C'], + KeyD: ['d', 'D', '', '', 0, 'VK_D'], + KeyE: ['e', 'E', '€', '', 0, 'VK_E'], + KeyF: ['f', 'F', '', '', 0, 'VK_F'], + KeyG: ['g', 'G', '', '', 0, 'VK_G'], + KeyH: ['h', 'H', '', '', 0, 'VK_H'], + KeyI: ['ı', 'I', 'i', 'İ', 0, 'VK_I'], + KeyJ: ['j', 'J', '', '', 0, 'VK_J'], + KeyK: ['k', 'K', '', '', 0, 'VK_K'], + KeyL: ['l', 'L', '', '', 0, 'VK_L'], + KeyM: ['m', 'M', '', '', 0, 'VK_M'], + KeyN: ['n', 'N', '', '', 0, 'VK_N'], + KeyO: ['o', 'O', '', '', 0, 'VK_O'], + KeyP: ['p', 'P', '', '', 0, 'VK_P'], + KeyQ: ['q', 'Q', '@', '', 0, 'VK_Q'], + KeyR: ['r', 'R', '', '', 0, 'VK_R'], + KeyS: ['s', 'S', 'ß', '', 0, 'VK_S'], + KeyT: ['t', 'T', '₺', '', 0, 'VK_T'], + KeyU: ['u', 'U', '', '', 0, 'VK_U'], + KeyV: ['v', 'V', '', '', 0, 'VK_V'], + KeyW: ['w', 'W', '', '', 0, 'VK_W'], + KeyX: ['x', 'X', '', '', 0, 'VK_X'], + KeyY: ['y', 'Y', '', '', 0, 'VK_Y'], + KeyZ: ['z', 'Z', '', '', 0, 'VK_Z'], + Digit1: ['1', '!', '>', '', 0, 'VK_1'], + Digit2: ['2', '\'', '£', '', 0, 'VK_2'], + Digit3: ['3', '^', '#', '', 0, 'VK_3'], + Digit4: ['4', '+', '$', '', 0, 'VK_4'], + Digit5: ['5', '%', '½', '', 0, 'VK_5'], + Digit6: ['6', '&', '', '', 0, 'VK_6'], + Digit7: ['7', '/', '{', '', 0, 'VK_7'], + Digit8: ['8', '(', '[', '', 0, 'VK_8'], + Digit9: ['9', ')', ']', '', 0, 'VK_9'], + Digit0: ['0', '=', '}', '', 0, 'VK_0'], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', '', '', 0, 'VK_SPACE'], + Minus: ['*', '?', '\\', '', 0, 'VK_OEM_8'], + Equal: ['-', '_', '|', '', 0, 'VK_OEM_MINUS'], + BracketLeft: ['ğ', 'Ğ', '¨', '', 0, 'VK_OEM_4'], + BracketRight: ['ü', 'Ü', '~', '', 0, 'VK_OEM_6'], + Backslash: [',', ';', '`', '', 0, 'VK_OEM_COMMA'], + Semicolon: ['ş', 'Ş', '´', '', 0, 'VK_OEM_1'], + Quote: ['i', 'İ', '', '', 0, 'VK_OEM_7'], + Backquote: ['"', 'é', '<', '', 0, 'VK_OEM_3'], + Comma: ['ö', 'Ö', '', '', 0, 'VK_OEM_2'], + Period: ['ç', 'Ç', '', '', 0, 'VK_OEM_5'], + Slash: ['.', ':', '', '', 0, 'VK_OEM_PERIOD'], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + PrintScreen: [], + ScrollLock: [], + Pause: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '', '', 0, 'VK_DIVIDE'], + NumpadMultiply: ['*', '*', '', '', 0, 'VK_MULTIPLY'], + NumpadSubtract: ['-', '-', '', '', 0, 'VK_SUBTRACT'], + NumpadAdd: ['+', '+', '', '', 0, 'VK_ADD'], + NumpadEnter: [], + Numpad1: [], + Numpad2: [], + Numpad3: [], + Numpad4: [], + Numpad5: [], + Numpad6: [], + Numpad7: [], + Numpad8: [], + Numpad9: [], + Numpad0: [], + NumpadDecimal: [], + IntlBackslash: ['<', '>', '|', '', 0, 'VK_OEM_102'], + ContextMenu: [], + Power: [], + NumpadEqual: [], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + F21: [], + F22: [], + F23: [], + F24: [], + Help: [], + Undo: [], + Cut: [], + Copy: [], + Paste: [], + AudioVolumeMute: [], + AudioVolumeUp: [], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + Convert: [], + NonConvert: [], + Lang1: [], + Lang2: [], + Lang3: [], + Lang4: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [], + MediaTrackNext: [], + MediaTrackPrevious: [], + MediaStop: [], + Eject: [], + MediaPlayPause: [], + MediaSelect: [], + LaunchMail: [], + LaunchApp2: [], + LaunchApp1: [], + BrowserSearch: [], + BrowserHome: [], + BrowserBack: [], + BrowserForward: [], + BrowserStop: [], + BrowserRefresh: [], + BrowserFavorites: [] + } +}); \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/browser/keyboardLayouts/zh-hans.darwin.ts b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/zh-hans.darwin.ts new file mode 100644 index 000000000..49d1f60ae --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keyboardLayouts/zh-hans.darwin.ts @@ -0,0 +1,131 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; + +KeyboardLayoutContribution.INSTANCE.registerKeyboardLayout({ + layout: { id: 'com.apple.inputmethod.SCIM.ITABC', lang: 'zh-Hans', localizedName: '搜狗拼音' }, + secondaryLayouts: [], + mapping: { + KeyA: ['a', 'A', 'å', 'Å', 0], + KeyB: ['b', 'B', '∫', 'ı', 0], + KeyC: ['c', 'C', 'ç', 'Ç', 0], + KeyD: ['d', 'D', '∂', 'Î', 0], + KeyE: ['e', 'E', '´', '´', 4], + KeyF: ['f', 'F', 'ƒ', 'Ï', 0], + KeyG: ['g', 'G', '©', '˝', 0], + KeyH: ['h', 'H', '˙', 'Ó', 0], + KeyI: ['i', 'I', 'ˆ', 'ˆ', 4], + KeyJ: ['j', 'J', '∆', 'Ô', 0], + KeyK: ['k', 'K', '˚', '', 0], + KeyL: ['l', 'L', '¬', 'Ò', 0], + KeyM: ['m', 'M', 'µ', 'Â', 0], + KeyN: ['n', 'N', '˜', '˜', 4], + KeyO: ['o', 'O', 'ø', 'Ø', 0], + KeyP: ['p', 'P', 'π', '∏', 0], + KeyQ: ['q', 'Q', 'œ', 'Œ', 0], + KeyR: ['r', 'R', '®', '‰', 0], + KeyS: ['s', 'S', 'ß', 'Í', 0], + KeyT: ['t', 'T', '†', 'ˇ', 0], + KeyU: ['u', 'U', '¨', '¨', 4], + KeyV: ['v', 'V', '√', '◊', 0], + KeyW: ['w', 'W', '∑', '„', 0], + KeyX: ['x', 'X', '≈', '˛', 0], + KeyY: ['y', 'Y', '¥', 'Á', 0], + KeyZ: ['z', 'Z', 'Ω', '¸', 0], + Digit1: ['1', '!', '¡', '⁄', 0], + Digit2: ['2', '@', '™', '€', 0], + Digit3: ['3', '#', '£', '‹', 0], + Digit4: ['4', '¥', '¢', '›', 0], + Digit5: ['5', '%', '∞', 'fi', 0], + Digit6: ['6', '', '§', 'fl', 0], + Digit7: ['7', '&', '¶', '‡', 0], + Digit8: ['8', '*', '•', '°', 0], + Digit9: ['9', '(', 'ª', '·', 0], + Digit0: ['0', ')', 'º', '‚', 0], + Enter: [], + Escape: [], + Backspace: [], + Tab: [], + Space: [' ', ' ', ' ', ' ', 0], + Minus: ['-', '', '–', '—', 0], + Equal: ['=', '+', '≠', '±', 0], + BracketLeft: ['【', '「', '“', '”', 0], + BracketRight: ['】', '」', '‘', '’', 0], + Backslash: ['、', '|', '«', '»', 0], + Semicolon: [';', ':', '…', 'Ú', 0], + Quote: ['\'', '"', 'æ', 'Æ', 0], + Backquote: ['·', '~', '`', '`', 4], + Comma: [',', '《', '≤', '¯', 0], + Period: ['。', '》', '≥', '˘', 0], + Slash: ['/', '?', '÷', '¿', 0], + CapsLock: [], + F1: [], + F2: [], + F3: [], + F4: [], + F5: [], + F6: [], + F7: [], + F8: [], + F9: [], + F10: [], + F11: [], + F12: [], + Insert: [], + Home: [], + PageUp: [], + Delete: [], + End: [], + PageDown: [], + ArrowRight: [], + ArrowLeft: [], + ArrowDown: [], + ArrowUp: [], + NumLock: [], + NumpadDivide: ['/', '/', '/', '/', 0], + NumpadMultiply: ['*', '*', '*', '*', 0], + NumpadSubtract: ['-', '-', '-', '-', 0], + NumpadAdd: ['+', '+', '+', '+', 0], + NumpadEnter: [], + Numpad1: ['1', '1', '1', '1', 0], + Numpad2: ['2', '2', '2', '2', 0], + Numpad3: ['3', '3', '3', '3', 0], + Numpad4: ['4', '4', '4', '4', 0], + Numpad5: ['5', '5', '5', '5', 0], + Numpad6: ['6', '6', '6', '6', 0], + Numpad7: ['7', '7', '7', '7', 0], + Numpad8: ['8', '8', '8', '8', 0], + Numpad9: ['9', '9', '9', '9', 0], + Numpad0: ['0', '0', '0', '0', 0], + NumpadDecimal: ['.', '.', '.', '.', 0], + IntlBackslash: ['§', '±', '§', '±', 0], + ContextMenu: [], + NumpadEqual: ['=', '=', '=', '=', 0], + F13: [], + F14: [], + F15: [], + F16: [], + F17: [], + F18: [], + F19: [], + F20: [], + AudioVolumeMute: [], + AudioVolumeUp: ['', '=', '', '=', 0], + AudioVolumeDown: [], + NumpadComma: [], + IntlRo: [], + KanaMode: [], + IntlYen: [], + ControlLeft: [], + ShiftLeft: [], + AltLeft: [], + MetaLeft: [], + ControlRight: [], + ShiftRight: [], + AltRight: [], + MetaRight: [] + } +}); \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/browser/keymapService.ts b/src/vs/workbench/services/keybinding/browser/keymapService.ts new file mode 100644 index 000000000..faacc11fb --- /dev/null +++ b/src/vs/workbench/services/keybinding/browser/keymapService.ts @@ -0,0 +1,627 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { Emitter, Event } from 'vs/base/common/event'; +import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle'; +import { IKeymapService, IKeyboardLayoutInfo, IKeyboardMapping, IWindowsKeyboardMapping, KeymapInfo, IRawMixedKeyboardMapping, getKeyboardLayoutId, IKeymapInfo } from 'vs/workbench/services/keybinding/common/keymapInfo'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { DispatchConfig } from 'vs/workbench/services/keybinding/common/dispatchConfig'; +import { IKeyboardMapper, CachedKeyboardMapper } from 'vs/workbench/services/keybinding/common/keyboardMapper'; +import { OS, OperatingSystem, isMacintosh, isWindows } from 'vs/base/common/platform'; +import { WindowsKeyboardMapper } from 'vs/workbench/services/keybinding/common/windowsKeyboardMapper'; +import { MacLinuxFallbackKeyboardMapper } from 'vs/workbench/services/keybinding/common/macLinuxFallbackKeyboardMapper'; +import { IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding'; +import { IMacLinuxKeyboardMapping, MacLinuxKeyboardMapper } from 'vs/workbench/services/keybinding/common/macLinuxKeyboardMapper'; +import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; +import { URI } from 'vs/base/common/uri'; +import { IFileService } from 'vs/platform/files/common/files'; +import { RunOnceScheduler } from 'vs/base/common/async'; +import { parse } from 'vs/base/common/json'; +import * as objects from 'vs/base/common/objects'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { Extensions as ConfigExtensions, IConfigurationRegistry, IConfigurationNode } from 'vs/platform/configuration/common/configurationRegistry'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { INavigatorWithKeyboard } from 'vs/workbench/services/keybinding/common/navigatorKeyboard'; +import { INotificationService } from 'vs/platform/notification/common/notification'; +import { ICommandService } from 'vs/platform/commands/common/commands'; +import { IStorageService } from 'vs/platform/storage/common/storage'; + +export class BrowserKeyboardMapperFactoryBase { + // keyboard mapper + protected _initialized: boolean; + protected _keyboardMapper: IKeyboardMapper | null; + private readonly _onDidChangeKeyboardMapper = new Emitter(); + public readonly onDidChangeKeyboardMapper: Event = this._onDidChangeKeyboardMapper.event; + + // keymap infos + protected _keymapInfos: KeymapInfo[]; + protected _mru: KeymapInfo[]; + private _activeKeymapInfo: KeymapInfo | null; + + get activeKeymap(): KeymapInfo | null { + return this._activeKeymapInfo; + } + + get keymapInfos(): KeymapInfo[] { + return this._keymapInfos; + } + + get activeKeyboardLayout(): IKeyboardLayoutInfo | null { + if (!this._initialized) { + return null; + } + + return this._activeKeymapInfo && this._activeKeymapInfo.layout; + } + + get activeKeyMapping(): IKeyboardMapping | null { + if (!this._initialized) { + return null; + } + + return this._activeKeymapInfo && this._activeKeymapInfo.mapping; + } + + get keyboardLayouts(): IKeyboardLayoutInfo[] { + return this._keymapInfos.map(keymapInfo => keymapInfo.layout); + } + + protected constructor( + // private _notificationService: INotificationService, + // private _storageService: IStorageService, + // private _commandService: ICommandService + ) { + this._keyboardMapper = null; + this._initialized = false; + this._keymapInfos = []; + this._mru = []; + this._activeKeymapInfo = null; + + if ((navigator).keyboard && (navigator).keyboard.addEventListener) { + (navigator).keyboard.addEventListener!('layoutchange', () => { + // Update user keyboard map settings + this._getBrowserKeyMapping().then((mapping: IKeyboardMapping | null) => { + if (this.isKeyMappingActive(mapping)) { + return; + } + + this.onKeyboardLayoutChanged(); + }); + }); + } + } + + registerKeyboardLayout(layout: KeymapInfo) { + this._keymapInfos.push(layout); + this._mru = this._keymapInfos; + } + + removeKeyboardLayout(layout: KeymapInfo): void { + let index = this._mru.indexOf(layout); + this._mru.splice(index, 1); + index = this._keymapInfos.indexOf(layout); + this._keymapInfos.splice(index, 1); + } + + getMatchedKeymapInfo(keyMapping: IKeyboardMapping | null): { result: KeymapInfo, score: number } | null { + if (!keyMapping) { + return null; + } + + let usStandard = this.getUSStandardLayout(); + + if (usStandard) { + let maxScore = usStandard.getScore(keyMapping); + if (maxScore === 0) { + return { + result: usStandard, + score: 0 + }; + } + + let result = usStandard; + for (let i = 0; i < this._mru.length; i++) { + let score = this._mru[i].getScore(keyMapping); + if (score > maxScore) { + if (score === 0) { + return { + result: this._mru[i], + score: 0 + }; + } + + maxScore = score; + result = this._mru[i]; + } + } + + return { + result, + score: maxScore + }; + } + + for (let i = 0; i < this._mru.length; i++) { + if (this._mru[i].fuzzyEqual(keyMapping)) { + return { + result: this._mru[i], + score: 0 + }; + } + } + + return null; + } + + getUSStandardLayout() { + const usStandardLayouts = this._mru.filter(layout => layout.layout.isUSStandard); + + if (usStandardLayouts.length) { + return usStandardLayouts[0]; + } + + return null; + } + + isKeyMappingActive(keymap: IKeyboardMapping | null) { + return this._activeKeymapInfo && keymap && this._activeKeymapInfo.fuzzyEqual(keymap); + } + + setUSKeyboardLayout() { + this._activeKeymapInfo = this.getUSStandardLayout(); + } + + setActiveKeyMapping(keymap: IKeyboardMapping | null) { + let matchedKeyboardLayout = this.getMatchedKeymapInfo(keymap); + if (matchedKeyboardLayout) { + // let score = matchedKeyboardLayout.score; + + // Due to https://bugs.chromium.org/p/chromium/issues/detail?id=977609, any key after a dead key will generate a wrong mapping, + // we shoud avoid yielding the false error. + // if (keymap && score < 0) { + // const donotAskUpdateKey = 'missing.keyboardlayout.donotask'; + // if (this._storageService.getBoolean(donotAskUpdateKey, StorageScope.GLOBAL)) { + // return; + // } + + // // the keyboard layout doesn't actually match the key event or the keymap from chromium + // this._notificationService.prompt( + // Severity.Info, + // nls.localize('missing.keyboardlayout', 'Fail to find matching keyboard layout'), + // [{ + // label: nls.localize('keyboardLayoutMissing.configure', "Configure"), + // run: () => this._commandService.executeCommand('workbench.action.openKeyboardLayoutPicker') + // }, { + // label: nls.localize('neverAgain', "Don't Show Again"), + // isSecondary: true, + // run: () => this._storageService.store(donotAskUpdateKey, true, StorageScope.GLOBAL) + // }] + // ); + + // console.warn('Active keymap/keyevent does not match current keyboard layout', JSON.stringify(keymap), this._activeKeymapInfo ? JSON.stringify(this._activeKeymapInfo.layout) : ''); + + // return; + // } + + if (!this._activeKeymapInfo) { + this._activeKeymapInfo = matchedKeyboardLayout.result; + } else if (keymap) { + if (matchedKeyboardLayout.result.getScore(keymap) > this._activeKeymapInfo.getScore(keymap)) { + this._activeKeymapInfo = matchedKeyboardLayout.result; + } + } + } + + if (!this._activeKeymapInfo) { + this._activeKeymapInfo = this.getUSStandardLayout(); + } + + if (!this._activeKeymapInfo) { + return; + } + + const index = this._mru.indexOf(this._activeKeymapInfo); + + this._mru.splice(index, 1); + this._mru.unshift(this._activeKeymapInfo); + + this._setKeyboardData(this._activeKeymapInfo); + } + + setActiveKeymapInfo(keymapInfo: KeymapInfo) { + this._activeKeymapInfo = keymapInfo; + + const index = this._mru.indexOf(this._activeKeymapInfo); + + if (index === 0) { + return; + } + + this._mru.splice(index, 1); + this._mru.unshift(this._activeKeymapInfo); + + this._setKeyboardData(this._activeKeymapInfo); + } + + public onKeyboardLayoutChanged(): void { + this._updateKeyboardLayoutAsync(this._initialized); + } + + private _updateKeyboardLayoutAsync(initialized: boolean, keyboardEvent?: IKeyboardEvent) { + if (!initialized) { + return; + } + + this._getBrowserKeyMapping(keyboardEvent).then(keyMap => { + // might be false positive + if (this.isKeyMappingActive(keyMap)) { + return; + } + this.setActiveKeyMapping(keyMap); + }); + } + + public getKeyboardMapper(dispatchConfig: DispatchConfig): IKeyboardMapper { + if (!this._initialized) { + return new MacLinuxFallbackKeyboardMapper(OS); + } + if (dispatchConfig === DispatchConfig.KeyCode) { + // Forcefully set to use keyCode + return new MacLinuxFallbackKeyboardMapper(OS); + } + return this._keyboardMapper!; + } + + public validateCurrentKeyboardMapping(keyboardEvent: IKeyboardEvent): void { + if (!this._initialized) { + return; + } + + let isCurrentKeyboard = this._validateCurrentKeyboardMapping(keyboardEvent); + + if (isCurrentKeyboard) { + return; + } + + this._updateKeyboardLayoutAsync(true, keyboardEvent); + } + + public setKeyboardLayout(layoutName: string) { + let matchedLayouts: KeymapInfo[] = this.keymapInfos.filter(keymapInfo => getKeyboardLayoutId(keymapInfo.layout) === layoutName); + + if (matchedLayouts.length > 0) { + this.setActiveKeymapInfo(matchedLayouts[0]); + } + } + + private _setKeyboardData(keymapInfo: KeymapInfo): void { + this._initialized = true; + + this._keyboardMapper = new CachedKeyboardMapper(BrowserKeyboardMapperFactory._createKeyboardMapper(keymapInfo)); + this._onDidChangeKeyboardMapper.fire(); + } + + private static _createKeyboardMapper(keymapInfo: KeymapInfo): IKeyboardMapper { + let rawMapping = keymapInfo.mapping; + const isUSStandard = !!keymapInfo.layout.isUSStandard; + if (OS === OperatingSystem.Windows) { + return new WindowsKeyboardMapper(isUSStandard, rawMapping); + } + if (Object.keys(rawMapping).length === 0) { + // Looks like reading the mappings failed (most likely Mac + Japanese/Chinese keyboard layouts) + return new MacLinuxFallbackKeyboardMapper(OS); + } + + return new MacLinuxKeyboardMapper(isUSStandard, rawMapping, OS); + } + + //#region Browser API + private _validateCurrentKeyboardMapping(keyboardEvent: IKeyboardEvent): boolean { + if (!this._initialized) { + return true; + } + + const standardKeyboardEvent = keyboardEvent as StandardKeyboardEvent; + const currentKeymap = this._activeKeymapInfo; + if (!currentKeymap) { + return true; + } + + const mapping = currentKeymap.mapping[standardKeyboardEvent.code]; + + if (!mapping) { + return false; + } + + if (mapping.value === '') { + // The value is empty when the key is not a printable character, we skip validation. + if (keyboardEvent.ctrlKey || keyboardEvent.metaKey) { + setTimeout(() => { + this._getBrowserKeyMapping().then((keymap: IKeyboardMapping) => { + if (this.isKeyMappingActive(keymap)) { + return; + } + + this.onKeyboardLayoutChanged(); + }); + }, 350); + } + return true; + } + + const expectedValue = standardKeyboardEvent.altKey && standardKeyboardEvent.shiftKey ? mapping.withShiftAltGr : + standardKeyboardEvent.altKey ? mapping.withAltGr : + standardKeyboardEvent.shiftKey ? mapping.withShift : mapping.value; + + const isDead = (standardKeyboardEvent.altKey && standardKeyboardEvent.shiftKey && mapping.withShiftAltGrIsDeadKey) || + (standardKeyboardEvent.altKey && mapping.withAltGrIsDeadKey) || + (standardKeyboardEvent.shiftKey && mapping.withShiftIsDeadKey) || + mapping.valueIsDeadKey; + + if (isDead && standardKeyboardEvent.browserEvent.key !== 'Dead') { + return false; + } + + // TODO, this assumption is wrong as `browserEvent.key` doesn't necessarily equal expectedValue from real keymap + if (!isDead && standardKeyboardEvent.browserEvent.key !== expectedValue) { + return false; + } + + return true; + } + + private async _getBrowserKeyMapping(keyboardEvent?: IKeyboardEvent): Promise { + if ((navigator as any).keyboard) { + try { + return (navigator as any).keyboard.getLayoutMap().then((e: any) => { + let ret: IKeyboardMapping = {}; + for (let key of e) { + ret[key[0]] = { + 'value': key[1], + 'withShift': '', + 'withAltGr': '', + 'withShiftAltGr': '' + }; + } + + return ret; + + // const matchedKeyboardLayout = this.getMatchedKeymapInfo(ret); + + // if (matchedKeyboardLayout) { + // return matchedKeyboardLayout.result.mapping; + // } + + // return null; + }); + } catch { + // getLayoutMap can throw if invoked from a nested browsing context + } + } else if (keyboardEvent && !keyboardEvent.shiftKey && !keyboardEvent.altKey && !keyboardEvent.metaKey && !keyboardEvent.metaKey) { + let ret: IKeyboardMapping = {}; + const standardKeyboardEvent = keyboardEvent as StandardKeyboardEvent; + ret[standardKeyboardEvent.browserEvent.code] = { + 'value': standardKeyboardEvent.browserEvent.key, + 'withShift': '', + 'withAltGr': '', + 'withShiftAltGr': '' + }; + + const matchedKeyboardLayout = this.getMatchedKeymapInfo(ret); + + if (matchedKeyboardLayout) { + return ret; + } + + return null; + } + + return null; + } + + //#endregion +} + +export class BrowserKeyboardMapperFactory extends BrowserKeyboardMapperFactoryBase { + constructor(notificationService: INotificationService, storageService: IStorageService, commandService: ICommandService) { + // super(notificationService, storageService, commandService); + super(); + + const platform = isWindows ? 'win' : isMacintosh ? 'darwin' : 'linux'; + + import('vs/workbench/services/keybinding/browser/keyboardLayouts/layout.contribution.' + platform).then((m) => { + let keymapInfos: IKeymapInfo[] = m.KeyboardLayoutContribution.INSTANCE.layoutInfos; + this._keymapInfos.push(...keymapInfos.map(info => (new KeymapInfo(info.layout, info.secondaryLayouts, info.mapping, info.isUserKeyboardLayout)))); + this._mru = this._keymapInfos; + this._initialized = true; + this.onKeyboardLayoutChanged(); + }); + } +} + +class UserKeyboardLayout extends Disposable { + + private readonly reloadConfigurationScheduler: RunOnceScheduler; + protected readonly _onDidChange: Emitter = this._register(new Emitter()); + readonly onDidChange: Event = this._onDidChange.event; + + private _keyboardLayout: KeymapInfo | null; + get keyboardLayout(): KeymapInfo | null { return this._keyboardLayout; } + + constructor( + private readonly keyboardLayoutResource: URI, + private readonly fileService: IFileService + ) { + super(); + + this._keyboardLayout = null; + + this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this.reload().then(changed => { + if (changed) { + this._onDidChange.fire(); + } + }), 50)); + + this._register(Event.filter(this.fileService.onFileChanges, e => e.contains(this.keyboardLayoutResource))(() => this.reloadConfigurationScheduler.schedule())); + } + + async initialize(): Promise { + await this.reload(); + } + + private async reload(): Promise { + const existing = this._keyboardLayout; + try { + const content = await this.fileService.readFile(this.keyboardLayoutResource); + const value = parse(content.value.toString()); + const layoutInfo = value.layout; + const mappings = value.rawMapping; + this._keyboardLayout = KeymapInfo.createKeyboardLayoutFromDebugInfo(layoutInfo, mappings, true); + } catch (e) { + this._keyboardLayout = null; + } + + return existing ? !objects.equals(existing, this._keyboardLayout) : true; + } + +} + +class BrowserKeymapService extends Disposable implements IKeymapService { + public _serviceBrand: any; + + private readonly _onDidChangeKeyboardMapper = new Emitter(); + public readonly onDidChangeKeyboardMapper: Event = this._onDidChangeKeyboardMapper.event; + + private _userKeyboardLayout: UserKeyboardLayout; + + private readonly layoutChangeListener = this._register(new MutableDisposable()); + private readonly _factory: BrowserKeyboardMapperFactory; + + constructor( + @IEnvironmentService environmentService: IEnvironmentService, + @IFileService fileService: IFileService, + @INotificationService notificationService: INotificationService, + @IStorageService storageService: IStorageService, + @ICommandService commandService: ICommandService, + @IConfigurationService private configurationService: IConfigurationService, + ) { + super(); + const keyboardConfig = configurationService.getValue<{ layout: string }>('keyboard'); + const layout = keyboardConfig.layout; + this._factory = new BrowserKeyboardMapperFactory(notificationService, storageService, commandService); + + this.registerKeyboardListener(); + + if (layout && layout !== 'autodetect') { + // set keyboard layout + this._factory.setKeyboardLayout(layout); + } + + this._register(configurationService.onDidChangeConfiguration(e => { + if (e.affectedKeys.indexOf('keyboard.layout') >= 0) { + const keyboardConfig = configurationService.getValue<{ layout: string }>('keyboard'); + const layout = keyboardConfig.layout; + + if (layout === 'autodetect') { + this.registerKeyboardListener(); + this._factory.onKeyboardLayoutChanged(); + } else { + this._factory.setKeyboardLayout(layout); + this.layoutChangeListener.clear(); + } + } + })); + + this._userKeyboardLayout = new UserKeyboardLayout(environmentService.keyboardLayoutResource, fileService); + this._userKeyboardLayout.initialize().then(() => { + if (this._userKeyboardLayout.keyboardLayout) { + this._factory.registerKeyboardLayout(this._userKeyboardLayout.keyboardLayout); + + this.setUserKeyboardLayoutIfMatched(); + } + }); + + this._register(this._userKeyboardLayout.onDidChange(() => { + let userKeyboardLayouts = this._factory.keymapInfos.filter(layout => layout.isUserKeyboardLayout); + + if (userKeyboardLayouts.length) { + if (this._userKeyboardLayout.keyboardLayout) { + userKeyboardLayouts[0].update(this._userKeyboardLayout.keyboardLayout); + } else { + this._factory.removeKeyboardLayout(userKeyboardLayouts[0]); + } + } else { + if (this._userKeyboardLayout.keyboardLayout) { + this._factory.registerKeyboardLayout(this._userKeyboardLayout.keyboardLayout); + } + } + + this.setUserKeyboardLayoutIfMatched(); + })); + } + + setUserKeyboardLayoutIfMatched() { + const keyboardConfig = this.configurationService.getValue<{ layout: string }>('keyboard'); + const layout = keyboardConfig.layout; + + if (layout && this._userKeyboardLayout.keyboardLayout) { + if (getKeyboardLayoutId(this._userKeyboardLayout.keyboardLayout.layout) === layout && this._factory.activeKeymap) { + + if (!this._userKeyboardLayout.keyboardLayout.equal(this._factory.activeKeymap)) { + this._factory.setActiveKeymapInfo(this._userKeyboardLayout.keyboardLayout); + } + } + } + } + + registerKeyboardListener() { + this.layoutChangeListener.value = this._factory.onDidChangeKeyboardMapper(() => { + this._onDidChangeKeyboardMapper.fire(); + }); + } + + getKeyboardMapper(dispatchConfig: DispatchConfig): IKeyboardMapper { + return this._factory.getKeyboardMapper(dispatchConfig); + } + + public getCurrentKeyboardLayout(): IKeyboardLayoutInfo | null { + return this._factory.activeKeyboardLayout; + } + + public getAllKeyboardLayouts(): IKeyboardLayoutInfo[] { + return this._factory.keyboardLayouts; + } + + public getRawKeyboardMapping(): IKeyboardMapping | null { + return this._factory.activeKeyMapping; + } + + public validateCurrentKeyboardMapping(keyboardEvent: IKeyboardEvent): void { + this._factory.validateCurrentKeyboardMapping(keyboardEvent); + } +} + +registerSingleton(IKeymapService, BrowserKeymapService, true); + +// Configuration +const configurationRegistry = Registry.as(ConfigExtensions.Configuration); +const keyboardConfiguration: IConfigurationNode = { + 'id': 'keyboard', + 'order': 15, + 'type': 'object', + 'title': nls.localize('keyboardConfigurationTitle', "Keyboard"), + 'overridable': true, + 'properties': { + 'keyboard.layout': { + 'type': 'string', + 'default': 'autodetect', + 'description': nls.localize('keyboard.layout.config', "Control the keyboard layout used in web.") + } + } +}; + +configurationRegistry.registerConfiguration(keyboardConfiguration); diff --git a/src/vs/workbench/services/keybinding/common/dispatchConfig.ts b/src/vs/workbench/services/keybinding/common/dispatchConfig.ts new file mode 100644 index 000000000..a92871c7e --- /dev/null +++ b/src/vs/workbench/services/keybinding/common/dispatchConfig.ts @@ -0,0 +1,17 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; + +export const enum DispatchConfig { + Code, + KeyCode +} + +export function getDispatchConfig(configurationService: IConfigurationService): DispatchConfig { + const keyboard = configurationService.getValue('keyboard'); + const r = (keyboard ? (keyboard).dispatch : null); + return (r === 'keyCode' ? DispatchConfig.KeyCode : DispatchConfig.Code); +} \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/common/keybindingEditing.ts b/src/vs/workbench/services/keybinding/common/keybindingEditing.ts index ffc636014..b3d4e7786 100644 --- a/src/vs/workbench/services/keybinding/common/keybindingEditing.ts +++ b/src/vs/workbench/services/keybinding/common/keybindingEditing.ts @@ -44,7 +44,7 @@ export class KeybindingsEditingService extends Disposable implements IKeybinding public _serviceBrand: any; private queue: Queue; - private resource: URI = URI.file(this.environmentService.appKeybindingsPath); + private resource: URI = this.environmentService.keybindingsResource; constructor( @ITextModelService private readonly textModelResolverService: ITextModelService, @@ -186,7 +186,7 @@ export class KeybindingsEditingService extends Disposable implements IKeybinding } private asObject(key: string, command: string | null, when: string | undefined, negate: boolean): any { - const object = { key }; + const object: any = { key }; if (command) { object['command'] = negate ? `-${command}` : command; } @@ -210,7 +210,7 @@ export class KeybindingsEditingService extends Disposable implements IKeybinding private resolveModelReference(): Promise> { return this.fileService.exists(this.resource) .then(exists => { - const EOL = this.configurationService.getValue('files', { overrideIdentifier: 'json' })['eol']; + const EOL = this.configurationService.getValue<{ eol: string }>('files', { overrideIdentifier: 'json' })['eol']; const result: Promise = exists ? Promise.resolve(null) : this.textFileService.write(this.resource, this.getEmptyContent(EOL), { encoding: 'utf8' }); return result.then(() => this.textModelResolverService.createModelReference(this.resource)); }); diff --git a/src/vs/workbench/services/keybinding/common/keymapInfo.ts b/src/vs/workbench/services/keybinding/common/keymapInfo.ts new file mode 100644 index 000000000..5282815cd --- /dev/null +++ b/src/vs/workbench/services/keybinding/common/keymapInfo.ts @@ -0,0 +1,342 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Event } from 'vs/base/common/event'; +import { isWindows, isLinux } from 'vs/base/common/platform'; +import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { DispatchConfig } from 'vs/workbench/services/keybinding/common/dispatchConfig'; +import { IKeyboardMapper } from 'vs/workbench/services/keybinding/common/keyboardMapper'; +import { IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding'; + + +export interface IWindowsKeyMapping { + vkey: string; + value: string; + withShift: string; + withAltGr: string; + withShiftAltGr: string; +} +export interface IWindowsKeyboardMapping { + [code: string]: IWindowsKeyMapping; +} +export interface ILinuxKeyMapping { + value: string; + withShift: string; + withAltGr: string; + withShiftAltGr: string; +} +export interface ILinuxKeyboardMapping { + [code: string]: ILinuxKeyMapping; +} +export interface IMacKeyMapping { + value: string; + withShift: string; + withAltGr: string; + withShiftAltGr: string; + valueIsDeadKey: boolean; + withShiftIsDeadKey: boolean; + withAltGrIsDeadKey: boolean; + withShiftAltGrIsDeadKey: boolean; +} +export interface IMacKeyboardMapping { + [code: string]: IMacKeyMapping; +} + +export type IKeyboardMapping = IWindowsKeyboardMapping | ILinuxKeyboardMapping | IMacKeyboardMapping; + +/* __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; + variant: string; + options: string; + rules: string; +} + +/* __GDPR__FRAGMENT__ + "IKeyboardLayoutInfo" : { + "id" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "lang": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "localizedName": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } + } +*/ +export interface IMacKeyboardLayoutInfo { + id: string; + lang: string; + localizedName?: string; +} + +export type IKeyboardLayoutInfo = (IWindowsKeyboardLayoutInfo | ILinuxKeyboardLayoutInfo | IMacKeyboardLayoutInfo) & { isUserKeyboardLayout?: boolean; isUSStandard?: true }; + +export const IKeymapService = createDecorator('keymapService'); + +export interface IKeymapService { + _serviceBrand: ServiceIdentifier; + onDidChangeKeyboardMapper: Event; + getKeyboardMapper(dispatchConfig: DispatchConfig): IKeyboardMapper; + getCurrentKeyboardLayout(): IKeyboardLayoutInfo | null; + getAllKeyboardLayouts(): IKeyboardLayoutInfo[]; + getRawKeyboardMapping(): IKeyboardMapping | null; + validateCurrentKeyboardMapping(keyboardEvent: IKeyboardEvent): void; +} + +export function areKeyboardLayoutsEqual(a: IKeyboardLayoutInfo | null, b: IKeyboardLayoutInfo | null): boolean { + if (!a || !b) { + return false; + } + + if ((a).name && (b).name && (a).name === (b).name) { + return true; + } + + if ((a).id && (b).id && (a).id === (b).id) { + return true; + } + + if ((a).model && + (b).model && + (a).model === (b).model && + (a).layout === (b).layout + ) { + return true; + } + + return false; +} + +export function parseKeyboardLayoutDescription(layout: IKeyboardLayoutInfo | null): { label: string, description: string } { + if (!layout) { + return { label: '', description: '' }; + } + + if ((layout).name) { + // windows + let windowsLayout = layout; + return { + label: windowsLayout.text, + description: '' + }; + } + + if ((layout).id) { + let macLayout = layout; + if (macLayout.localizedName) { + return { + label: macLayout.localizedName, + description: '' + }; + } + + if (/^com\.apple\.keylayout\./.test(macLayout.id)) { + return { + label: macLayout.id.replace(/^com\.apple\.keylayout\./, '').replace(/-/, ' '), + description: '' + }; + } + if (/^.*inputmethod\./.test(macLayout.id)) { + return { + label: macLayout.id.replace(/^.*inputmethod\./, '').replace(/[-\.]/, ' '), + description: `Input Method (${macLayout.lang})` + }; + } + + return { + label: macLayout.lang, + description: '' + }; + } + + let linuxLayout = layout; + + return { + label: linuxLayout.layout, + description: '' + }; +} + +export function getKeyboardLayoutId(layout: IKeyboardLayoutInfo): string { + if ((layout).name) { + return (layout).name; + } + + if ((layout).id) { + return (layout).id; + } + + return (layout).layout; +} + +function deserializeMapping(serializedMapping: ISerializedMapping) { + let mapping = serializedMapping; + + let ret: { [key: string]: any } = {}; + for (let key in mapping) { + let result: (string | number)[] = mapping[key]; + if (result.length) { + let value = result[0]; + let withShift = result[1]; + let withAltGr = result[2]; + let withShiftAltGr = result[3]; + let mask = Number(result[4]); + let vkey = result.length === 6 ? result[5] : undefined; + ret[key] = { + 'value': value, + 'vkey': vkey, + 'withShift': withShift, + 'withAltGr': withAltGr, + 'withShiftAltGr': withShiftAltGr, + 'valueIsDeadKey': (mask & 1) > 0, + 'withShiftIsDeadKey': (mask & 2) > 0, + 'withAltGrIsDeadKey': (mask & 4) > 0, + 'withShiftAltGrIsDeadKey': (mask & 8) > 0 + }; + } else { + ret[key] = { + 'value': '', + 'valueIsDeadKey': false, + 'withShift': '', + 'withShiftIsDeadKey': false, + 'withAltGr': '', + 'withAltGrIsDeadKey': false, + 'withShiftAltGr': '', + 'withShiftAltGrIsDeadKey': false + }; + } + } + + return ret; +} + +export interface IRawMixedKeyboardMapping { + [key: string]: { + value: string, + withShift: string; + withAltGr: string; + withShiftAltGr: string; + valueIsDeadKey?: boolean; + withShiftIsDeadKey?: boolean; + withAltGrIsDeadKey?: boolean; + withShiftAltGrIsDeadKey?: boolean; + + }; +} + +interface ISerializedMapping { + [key: string]: (string | number)[]; +} + +export interface IKeymapInfo { + layout: IKeyboardLayoutInfo; + secondaryLayouts: IKeyboardLayoutInfo[]; + mapping: ISerializedMapping; + isUserKeyboardLayout?: boolean; +} + +export class KeymapInfo { + mapping: IRawMixedKeyboardMapping; + isUserKeyboardLayout: boolean; + + constructor(public layout: IKeyboardLayoutInfo, public secondaryLayouts: IKeyboardLayoutInfo[], keyboardMapping: ISerializedMapping, isUserKeyboardLayout?: boolean) { + this.mapping = deserializeMapping(keyboardMapping); + this.isUserKeyboardLayout = !!isUserKeyboardLayout; + this.layout.isUserKeyboardLayout = !!isUserKeyboardLayout; + } + + static createKeyboardLayoutFromDebugInfo(layout: IKeyboardLayoutInfo, value: IRawMixedKeyboardMapping, isUserKeyboardLayout?: boolean): KeymapInfo { + let keyboardLayoutInfo = new KeymapInfo(layout, [], {}, true); + keyboardLayoutInfo.mapping = value; + return keyboardLayoutInfo; + } + + update(other: KeymapInfo) { + this.layout = other.layout; + this.secondaryLayouts = other.secondaryLayouts; + this.mapping = other.mapping; + this.isUserKeyboardLayout = other.isUserKeyboardLayout; + this.layout.isUserKeyboardLayout = other.isUserKeyboardLayout; + } + + getScore(other: IRawMixedKeyboardMapping): number { + let score = 0; + for (let key in other) { + if (isWindows && (key === 'Backslash' || key === 'KeyQ')) { + // keymap from Chromium is probably wrong. + continue; + } + + if (isLinux && (key === 'Backspace' || key === 'Escape')) { + // native keymap doesn't align with keyboard event + continue; + } + + if (this.mapping[key] === undefined) { + score -= 1; + } + + let currentMapping = this.mapping[key]; + let otherMapping = other[key]; + + if (currentMapping.value !== otherMapping.value) { + score -= 1; + } + } + + return score; + } + + equal(other: KeymapInfo): boolean { + if (this.isUserKeyboardLayout !== other.isUserKeyboardLayout) { + return false; + } + + if (getKeyboardLayoutId(this.layout) !== getKeyboardLayoutId(other.layout)) { + return false; + } + + return this.fuzzyEqual(other.mapping); + } + + fuzzyEqual(other: IRawMixedKeyboardMapping): boolean { + for (let key in other) { + if (isWindows && (key === 'Backslash' || key === 'KeyQ')) { + // keymap from Chromium is probably wrong. + continue; + } + if (this.mapping[key] === undefined) { + return false; + } + + let currentMapping = this.mapping[key]; + let otherMapping = other[key]; + + if (currentMapping.value !== otherMapping.value) { + return false; + } + } + + return true; + } +} diff --git a/src/vs/workbench/services/keybinding/common/navigatorKeyboard.ts b/src/vs/workbench/services/keybinding/common/navigatorKeyboard.ts new file mode 100644 index 000000000..51e8de9f7 --- /dev/null +++ b/src/vs/workbench/services/keybinding/common/navigatorKeyboard.ts @@ -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. + *--------------------------------------------------------------------------------------------*/ + +export interface IKeyboard { + getLayoutMap(): Promise; + lock(keyCodes?: string[]): Promise; + unlock(): void; + addEventListener?(type: string, listener: () => void): void; + +} +export type INavigatorWithKeyboard = Navigator & { + keyboard: IKeyboard +}; \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/electron-browser/keybinding.contribution.ts b/src/vs/workbench/services/keybinding/electron-browser/keybinding.contribution.ts new file mode 100644 index 000000000..eec3ac017 --- /dev/null +++ b/src/vs/workbench/services/keybinding/electron-browser/keybinding.contribution.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 * as nls from 'vs/nls'; +import { release } from 'os'; +import { OS, OperatingSystem } from 'vs/base/common/platform'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { Extensions as ConfigExtensions, IConfigurationNode, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; + +const configurationRegistry = Registry.as(ConfigExtensions.Configuration); +const keyboardConfiguration: IConfigurationNode = { + 'id': 'keyboard', + 'order': 15, + 'type': 'object', + 'title': nls.localize('keyboardConfigurationTitle', "Keyboard"), + 'overridable': true, + 'properties': { + 'keyboard.touchbar.enabled': { + 'type': 'boolean', + 'default': true, + 'description': nls.localize('touchbar.enabled', "Enables the macOS touchbar buttons on the keyboard if available."), + 'included': OS === OperatingSystem.Macintosh && parseFloat(release()) >= 16 // Minimum: macOS Sierra (10.12.x = darwin 16.x) + } + } +}; + +configurationRegistry.registerConfiguration(keyboardConfiguration); \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/electron-browser/keybindingService.ts b/src/vs/workbench/services/keybinding/electron-browser/keybindingService.ts deleted file mode 100644 index 0c3d16f07..000000000 --- a/src/vs/workbench/services/keybinding/electron-browser/keybindingService.ts +++ /dev/null @@ -1,715 +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 * as nativeKeymap from 'native-keymap'; -import { release } from 'os'; -import * as dom from 'vs/base/browser/dom'; -import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import { onUnexpectedError } from 'vs/base/common/errors'; -import { Emitter, Event } from 'vs/base/common/event'; -import { IJSONSchema } from 'vs/base/common/jsonSchema'; -import { Keybinding, ResolvedKeybinding } from 'vs/base/common/keyCodes'; -import { KeybindingParser } from 'vs/base/common/keybindingParser'; -import { OS, OperatingSystem } from 'vs/base/common/platform'; -import { ConfigWatcher } from 'vs/base/node/config'; -import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/commands'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { Extensions as ConfigExtensions, IConfigurationNode, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; -import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { Extensions, IJSONContributionRegistry } from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; -import { AbstractKeybindingService } from 'vs/platform/keybinding/common/abstractKeybindingService'; -import { IKeybindingEvent, IKeyboardEvent, IUserFriendlyKeybinding, KeybindingSource, IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { KeybindingResolver } from 'vs/platform/keybinding/common/keybindingResolver'; -import { IKeybindingItem, IKeybindingRule2, KeybindingWeight, KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; -import { INotificationService } from 'vs/platform/notification/common/notification'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { keybindingsTelemetry } from 'vs/platform/telemetry/common/telemetryUtils'; -import { ExtensionMessageCollector, ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; -import { IUserKeybindingItem, KeybindingIO, OutputBuilder } from 'vs/workbench/services/keybinding/common/keybindingIO'; -import { CachedKeyboardMapper, IKeyboardMapper } from 'vs/workbench/services/keybinding/common/keyboardMapper'; -import { MacLinuxFallbackKeyboardMapper } from 'vs/workbench/services/keybinding/common/macLinuxFallbackKeyboardMapper'; -import { IMacLinuxKeyboardMapping, MacLinuxKeyboardMapper, macLinuxKeyboardMappingEquals } from 'vs/workbench/services/keybinding/common/macLinuxKeyboardMapper'; -import { IWindowsKeyboardMapping, WindowsKeyboardMapper, windowsKeyboardMappingEquals } from 'vs/workbench/services/keybinding/common/windowsKeyboardMapper'; -import { IWindowService } from 'vs/platform/windows/common/windows'; -import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { MenuRegistry } from 'vs/platform/actions/common/actions'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; - -export class KeyboardMapperFactory { - public static readonly INSTANCE = new KeyboardMapperFactory(); - - private _layoutInfo: nativeKeymap.IKeyboardLayoutInfo | null; - private _rawMapping: nativeKeymap.IKeyboardMapping | null; - private _keyboardMapper: IKeyboardMapper | null; - private _initialized: boolean; - - private readonly _onDidChangeKeyboardMapper = new Emitter(); - public readonly onDidChangeKeyboardMapper: Event = this._onDidChangeKeyboardMapper.event; - - private constructor() { - this._layoutInfo = null; - this._rawMapping = null; - this._keyboardMapper = null; - this._initialized = false; - } - - public _onKeyboardLayoutChanged(): void { - if (this._initialized) { - this._setKeyboardData(nativeKeymap.getCurrentKeyboardLayout(), nativeKeymap.getKeyMap()); - } - } - - public getKeyboardMapper(dispatchConfig: DispatchConfig): IKeyboardMapper { - if (!this._initialized) { - this._setKeyboardData(nativeKeymap.getCurrentKeyboardLayout(), nativeKeymap.getKeyMap()); - } - if (dispatchConfig === DispatchConfig.KeyCode) { - // Forcefully set to use keyCode - return new MacLinuxFallbackKeyboardMapper(OS); - } - return this._keyboardMapper!; - } - - public getCurrentKeyboardLayout(): nativeKeymap.IKeyboardLayoutInfo | null { - if (!this._initialized) { - this._setKeyboardData(nativeKeymap.getCurrentKeyboardLayout(), nativeKeymap.getKeyMap()); - } - return this._layoutInfo; - } - - private static _isUSStandard(_kbInfo: nativeKeymap.IKeyboardLayoutInfo): boolean { - if (OS === OperatingSystem.Linux) { - const kbInfo = _kbInfo; - return (kbInfo && kbInfo.layout === 'us'); - } - - if (OS === OperatingSystem.Macintosh) { - const kbInfo = _kbInfo; - return (kbInfo && kbInfo.id === 'com.apple.keylayout.US'); - } - - if (OS === OperatingSystem.Windows) { - const kbInfo = _kbInfo; - return (kbInfo && kbInfo.name === '00000409'); - } - - return false; - } - - public getRawKeyboardMapping(): nativeKeymap.IKeyboardMapping | null { - if (!this._initialized) { - this._setKeyboardData(nativeKeymap.getCurrentKeyboardLayout(), nativeKeymap.getKeyMap()); - } - return this._rawMapping; - } - - private _setKeyboardData(layoutInfo: nativeKeymap.IKeyboardLayoutInfo, rawMapping: nativeKeymap.IKeyboardMapping): void { - this._layoutInfo = layoutInfo; - - if (this._initialized && KeyboardMapperFactory._equals(this._rawMapping, rawMapping)) { - // nothing to do... - return; - } - - this._initialized = true; - this._rawMapping = rawMapping; - this._keyboardMapper = new CachedKeyboardMapper( - KeyboardMapperFactory._createKeyboardMapper(this._layoutInfo, this._rawMapping) - ); - this._onDidChangeKeyboardMapper.fire(); - } - - private static _createKeyboardMapper(layoutInfo: nativeKeymap.IKeyboardLayoutInfo, rawMapping: nativeKeymap.IKeyboardMapping): IKeyboardMapper { - const isUSStandard = KeyboardMapperFactory._isUSStandard(layoutInfo); - if (OS === OperatingSystem.Windows) { - return new WindowsKeyboardMapper(isUSStandard, rawMapping); - } - - if (Object.keys(rawMapping).length === 0) { - // Looks like reading the mappings failed (most likely Mac + Japanese/Chinese keyboard layouts) - return new MacLinuxFallbackKeyboardMapper(OS); - } - - if (OS === OperatingSystem.Macintosh) { - const kbInfo = layoutInfo; - if (kbInfo.id === 'com.apple.keylayout.DVORAK-QWERTYCMD') { - // Use keyCode based dispatching for DVORAK - QWERTY ⌘ - return new MacLinuxFallbackKeyboardMapper(OS); - } - } - - return new MacLinuxKeyboardMapper(isUSStandard, rawMapping, OS); - } - - private static _equals(a: nativeKeymap.IKeyboardMapping | null, b: nativeKeymap.IKeyboardMapping | null): boolean { - if (OS === OperatingSystem.Windows) { - return windowsKeyboardMappingEquals(a, b); - } - - return macLinuxKeyboardMappingEquals(a, b); - } -} - -interface ContributedKeyBinding { - command: string; - args?: any; - key: string; - when?: string; - mac?: string; - linux?: string; - win?: string; -} - -function isContributedKeyBindingsArray(thing: ContributedKeyBinding | ContributedKeyBinding[]): thing is ContributedKeyBinding[] { - return Array.isArray(thing); -} - -function isValidContributedKeyBinding(keyBinding: ContributedKeyBinding, rejects: string[]): boolean { - if (!keyBinding) { - rejects.push(nls.localize('nonempty', "expected non-empty value.")); - return false; - } - if (typeof keyBinding.command !== 'string') { - rejects.push(nls.localize('requirestring', "property `{0}` is mandatory and must be of type `string`", 'command')); - return false; - } - if (keyBinding.key && typeof keyBinding.key !== 'string') { - rejects.push(nls.localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'key')); - return false; - } - if (keyBinding.when && typeof keyBinding.when !== 'string') { - rejects.push(nls.localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'when')); - return false; - } - if (keyBinding.mac && typeof keyBinding.mac !== 'string') { - rejects.push(nls.localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'mac')); - return false; - } - if (keyBinding.linux && typeof keyBinding.linux !== 'string') { - rejects.push(nls.localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'linux')); - return false; - } - if (keyBinding.win && typeof keyBinding.win !== 'string') { - rejects.push(nls.localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'win')); - return false; - } - return true; -} - -let keybindingType: IJSONSchema = { - type: 'object', - default: { command: '', key: '' }, - properties: { - command: { - description: nls.localize('vscode.extension.contributes.keybindings.command', 'Identifier of the command to run when keybinding is triggered.'), - type: 'string' - }, - args: { - description: nls.localize('vscode.extension.contributes.keybindings.args', "Arguments to pass to the command to execute.") - }, - key: { - description: nls.localize('vscode.extension.contributes.keybindings.key', 'Key or key sequence (separate keys with plus-sign and sequences with space, e.g Ctrl+O and Ctrl+L L for a chord).'), - type: 'string' - }, - mac: { - description: nls.localize('vscode.extension.contributes.keybindings.mac', 'Mac specific key or key sequence.'), - type: 'string' - }, - linux: { - description: nls.localize('vscode.extension.contributes.keybindings.linux', 'Linux specific key or key sequence.'), - type: 'string' - }, - win: { - description: nls.localize('vscode.extension.contributes.keybindings.win', 'Windows specific key or key sequence.'), - type: 'string' - }, - when: { - description: nls.localize('vscode.extension.contributes.keybindings.when', 'Condition when the key is active.'), - type: 'string' - }, - } -}; - -const keybindingsExtPoint = ExtensionsRegistry.registerExtensionPoint({ - extensionPoint: 'keybindings', - jsonSchema: { - description: nls.localize('vscode.extension.contributes.keybindings', "Contributes keybindings."), - oneOf: [ - keybindingType, - { - type: 'array', - items: keybindingType - } - ] - } -}); - -export const enum DispatchConfig { - Code, - KeyCode -} - -function getDispatchConfig(configurationService: IConfigurationService): DispatchConfig { - const keyboard = configurationService.getValue('keyboard'); - const r = (keyboard ? (keyboard).dispatch : null); - return (r === 'keyCode' ? DispatchConfig.KeyCode : DispatchConfig.Code); -} - -export class WorkbenchKeybindingService extends AbstractKeybindingService { - - private _keyboardMapper: IKeyboardMapper; - private _cachedResolver: KeybindingResolver | null; - private _firstTimeComputingResolver: boolean; - private userKeybindings: ConfigWatcher; - - constructor( - @IContextKeyService contextKeyService: IContextKeyService, - @ICommandService commandService: ICommandService, - @ITelemetryService telemetryService: ITelemetryService, - @INotificationService notificationService: INotificationService, - @IEnvironmentService environmentService: IEnvironmentService, - @IStatusbarService statusBarService: IStatusbarService, - @IConfigurationService configurationService: IConfigurationService, - @IWindowService private readonly windowService: IWindowService, - @IExtensionService extensionService: IExtensionService - ) { - super(contextKeyService, commandService, telemetryService, notificationService, statusBarService); - - updateSchema(); - - let dispatchConfig = getDispatchConfig(configurationService); - configurationService.onDidChangeConfiguration((e) => { - let newDispatchConfig = getDispatchConfig(configurationService); - if (dispatchConfig === newDispatchConfig) { - return; - } - - dispatchConfig = newDispatchConfig; - this._keyboardMapper = KeyboardMapperFactory.INSTANCE.getKeyboardMapper(dispatchConfig); - this.updateResolver({ source: KeybindingSource.Default }); - }); - - this._keyboardMapper = KeyboardMapperFactory.INSTANCE.getKeyboardMapper(dispatchConfig); - KeyboardMapperFactory.INSTANCE.onDidChangeKeyboardMapper(() => { - this._keyboardMapper = KeyboardMapperFactory.INSTANCE.getKeyboardMapper(dispatchConfig); - this.updateResolver({ source: KeybindingSource.Default }); - }); - - this._cachedResolver = null; - this._firstTimeComputingResolver = true; - - this.userKeybindings = this._register(new ConfigWatcher(environmentService.appKeybindingsPath, { defaultConfig: [], onError: error => onUnexpectedError(error) })); - - keybindingsExtPoint.setHandler((extensions) => { - - let keybindings: IKeybindingRule2[] = []; - for (let extension of extensions) { - this._handleKeybindingsExtensionPointUser(extension.description.isBuiltin, extension.value, extension.collector, keybindings); - } - - KeybindingsRegistry.setExtensionKeybindings(keybindings); - this.updateResolver({ source: KeybindingSource.Default }); - }); - - updateSchema(); - this._register(extensionService.onDidRegisterExtensions(() => updateSchema())); - - this._register(this.userKeybindings.onDidUpdateConfiguration(event => this.updateResolver({ - source: KeybindingSource.User, - keybindings: event.config - }))); - - this._register(dom.addDisposableListener(window, dom.EventType.KEY_DOWN, (e: KeyboardEvent) => { - let keyEvent = new StandardKeyboardEvent(e); - let shouldPreventDefault = this._dispatch(keyEvent, keyEvent.target); - if (shouldPreventDefault) { - keyEvent.preventDefault(); - } - })); - - keybindingsTelemetry(telemetryService, this); - let data = KeyboardMapperFactory.INSTANCE.getCurrentKeyboardLayout(); - /* __GDPR__ - "keyboardLayout" : { - "currentKeyboardLayout": { "${inline}": [ "${IKeyboardLayoutInfo}" ] } - } - */ - telemetryService.publicLog('keyboardLayout', { - currentKeyboardLayout: data - }); - } - - public _dumpDebugInfo(): string { - const layoutInfo = JSON.stringify(KeyboardMapperFactory.INSTANCE.getCurrentKeyboardLayout(), null, '\t'); - const mapperInfo = this._keyboardMapper.dumpDebugInfo(); - const rawMapping = JSON.stringify(KeyboardMapperFactory.INSTANCE.getRawKeyboardMapping(), null, '\t'); - return `Layout info:\n${layoutInfo}\n${mapperInfo}\n\nRaw mapping:\n${rawMapping}`; - } - - private _safeGetConfig(): IUserFriendlyKeybinding[] { - let rawConfig = this.userKeybindings.getConfig(); - if (Array.isArray(rawConfig)) { - return rawConfig; - } - return []; - } - - public customKeybindingsCount(): number { - let userKeybindings = this._safeGetConfig(); - - return userKeybindings.length; - } - - private updateResolver(event: IKeybindingEvent): void { - this._cachedResolver = null; - this._onDidUpdateKeybindings.fire(event); - } - - protected _getResolver(): KeybindingResolver { - if (!this._cachedResolver) { - const defaults = this._resolveKeybindingItems(KeybindingsRegistry.getDefaultKeybindings(), true); - const overrides = this._resolveUserKeybindingItems(this._getExtraKeybindings(this._firstTimeComputingResolver), false); - this._cachedResolver = new KeybindingResolver(defaults, overrides); - this._firstTimeComputingResolver = false; - } - return this._cachedResolver; - } - - protected _documentHasFocus(): boolean { - // it is possible that the document has lost focus, but the - // window is still focused, e.g. when a element - // has focus - return this.windowService.hasFocus; - } - - private _resolveKeybindingItems(items: IKeybindingItem[], isDefault: boolean): ResolvedKeybindingItem[] { - let result: ResolvedKeybindingItem[] = [], resultLen = 0; - for (const item of items) { - const when = (item.when ? item.when.normalize() : undefined); - const keybinding = item.keybinding; - if (!keybinding) { - // This might be a removal keybinding item in user settings => accept it - result[resultLen++] = new ResolvedKeybindingItem(null, item.command, item.commandArgs, when, isDefault); - } else { - const resolvedKeybindings = this.resolveKeybinding(keybinding); - for (const resolvedKeybinding of resolvedKeybindings) { - result[resultLen++] = new ResolvedKeybindingItem(resolvedKeybinding, item.command, item.commandArgs, when, isDefault); - } - } - } - - return result; - } - - private _resolveUserKeybindingItems(items: IUserKeybindingItem[], isDefault: boolean): ResolvedKeybindingItem[] { - let result: ResolvedKeybindingItem[] = [], resultLen = 0; - for (const item of items) { - const when = (item.when ? item.when.normalize() : undefined); - const parts = item.parts; - if (parts.length === 0) { - // This might be a removal keybinding item in user settings => accept it - result[resultLen++] = new ResolvedKeybindingItem(null, item.command, item.commandArgs, when, isDefault); - } else { - const resolvedKeybindings = this._keyboardMapper.resolveUserBinding(parts); - for (const resolvedKeybinding of resolvedKeybindings) { - result[resultLen++] = new ResolvedKeybindingItem(resolvedKeybinding, item.command, item.commandArgs, when, isDefault); - } - } - } - - return result; - } - - private _getExtraKeybindings(isFirstTime: boolean): IUserKeybindingItem[] { - let extraUserKeybindings: IUserFriendlyKeybinding[] = this._safeGetConfig(); - if (!isFirstTime) { - let cnt = extraUserKeybindings.length; - - /* __GDPR__ - "customKeybindingsChanged" : { - "keyCount" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } - } - */ - this._telemetryService.publicLog('customKeybindingsChanged', { - keyCount: cnt - }); - } - - return extraUserKeybindings.map((k) => KeybindingIO.readUserKeybindingItem(k)); - } - - public resolveKeybinding(kb: Keybinding): ResolvedKeybinding[] { - return this._keyboardMapper.resolveKeybinding(kb); - } - - public resolveKeyboardEvent(keyboardEvent: IKeyboardEvent): ResolvedKeybinding { - return this._keyboardMapper.resolveKeyboardEvent(keyboardEvent); - } - - public resolveUserBinding(userBinding: string): ResolvedKeybinding[] { - const parts = KeybindingParser.parseUserBinding(userBinding); - return this._keyboardMapper.resolveUserBinding(parts); - } - - private _handleKeybindingsExtensionPointUser(isBuiltin: boolean, keybindings: ContributedKeyBinding | ContributedKeyBinding[], collector: ExtensionMessageCollector, result: IKeybindingRule2[]): void { - if (isContributedKeyBindingsArray(keybindings)) { - for (let i = 0, len = keybindings.length; i < len; i++) { - this._handleKeybinding(isBuiltin, i + 1, keybindings[i], collector, result); - } - } else { - this._handleKeybinding(isBuiltin, 1, keybindings, collector, result); - } - } - - private _handleKeybinding(isBuiltin: boolean, idx: number, keybindings: ContributedKeyBinding, collector: ExtensionMessageCollector, result: IKeybindingRule2[]): void { - - let rejects: string[] = []; - - if (isValidContributedKeyBinding(keybindings, rejects)) { - let rule = this._asCommandRule(isBuiltin, idx++, keybindings); - if (rule) { - result.push(rule); - } - } - - if (rejects.length > 0) { - collector.error(nls.localize( - 'invalid.keybindings', - "Invalid `contributes.{0}`: {1}", - keybindingsExtPoint.name, - rejects.join('\n') - )); - } - } - - private _asCommandRule(isBuiltin: boolean, idx: number, binding: ContributedKeyBinding): IKeybindingRule2 | undefined { - - let { command, args, when, key, mac, linux, win } = binding; - - let weight: number; - if (isBuiltin) { - weight = KeybindingWeight.BuiltinExtension + idx; - } else { - weight = KeybindingWeight.ExternalExtension + idx; - } - - let desc: IKeybindingRule2 = { - id: command, - args, - when: ContextKeyExpr.deserialize(when), - weight: weight, - primary: KeybindingParser.parseKeybinding(key, OS), - mac: mac ? { primary: KeybindingParser.parseKeybinding(mac, OS) } : null, - linux: linux ? { primary: KeybindingParser.parseKeybinding(linux, OS) } : null, - win: win ? { primary: KeybindingParser.parseKeybinding(win, OS) } : null - }; - - if (!desc.primary && !desc.mac && !desc.linux && !desc.win) { - return undefined; - } - - return desc; - } - - public getDefaultKeybindingsContent(): string { - const resolver = this._getResolver(); - const defaultKeybindings = resolver.getDefaultKeybindings(); - const boundCommands = resolver.getDefaultBoundCommands(); - return ( - WorkbenchKeybindingService._getDefaultKeybindings(defaultKeybindings) - + '\n\n' - + WorkbenchKeybindingService._getAllCommandsAsComment(boundCommands) - ); - } - - private static _getDefaultKeybindings(defaultKeybindings: ResolvedKeybindingItem[]): string { - let out = new OutputBuilder(); - out.writeLine('['); - - let lastIndex = defaultKeybindings.length - 1; - defaultKeybindings.forEach((k, index) => { - KeybindingIO.writeKeybindingItem(out, k); - if (index !== lastIndex) { - out.writeLine(','); - } else { - out.writeLine(); - } - }); - out.writeLine(']'); - return out.toString(); - } - - private static _getAllCommandsAsComment(boundCommands: Map): string { - const unboundCommands = KeybindingResolver.getAllUnboundCommands(boundCommands); - let pretty = unboundCommands.sort().join('\n// - '); - return '// ' + nls.localize('unboundCommands', "Here are other available commands: ") + '\n// - ' + pretty; - } - - mightProducePrintableCharacter(event: IKeyboardEvent): boolean { - if (event.ctrlKey || event.metaKey) { - // ignore ctrl/cmd-combination but not shift/alt-combinatios - return false; - } - // consult the KeyboardMapperFactory to check the given event for - // a printable value. - const mapping = KeyboardMapperFactory.INSTANCE.getRawKeyboardMapping(); - if (!mapping) { - return false; - } - const keyInfo = mapping[event.code]; - if (!keyInfo) { - return false; - } - if (!keyInfo.value || /\s/.test(keyInfo.value)) { - return false; - } - return true; - } -} - -let schemaId = 'vscode://schemas/keybindings'; -let commandsSchemas: IJSONSchema[] = []; -let commandsEnum: string[] = []; -let commandsEnumDescriptions: (string | undefined)[] = []; -let schema: IJSONSchema = { - 'id': schemaId, - 'type': 'array', - 'title': nls.localize('keybindings.json.title', "Keybindings configuration"), - 'definitions': { - 'editorGroupsSchema': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'groups': { - '$ref': '#/definitions/editorGroupsSchema', - 'default': [{}, {}] - }, - 'size': { - 'type': 'number', - 'default': 0.5 - } - } - } - } - }, - 'items': { - 'required': ['key'], - 'type': 'object', - 'defaultSnippets': [{ 'body': { 'key': '$1', 'command': '$2', 'when': '$3' } }], - 'properties': { - 'key': { - 'type': 'string', - 'description': nls.localize('keybindings.json.key', "Key or key sequence (separated by space)"), - }, - 'command': { - 'type': 'string', - 'enum': commandsEnum, - 'enumDescriptions': commandsEnumDescriptions, - 'description': nls.localize('keybindings.json.command', "Name of the command to execute"), - }, - 'when': { - 'type': 'string', - 'description': nls.localize('keybindings.json.when', "Condition when the key is active.") - }, - 'args': { - 'description': nls.localize('keybindings.json.args', "Arguments to pass to the command to execute.") - } - }, - 'allOf': commandsSchemas - } -}; - -let schemaRegistry = Registry.as(Extensions.JSONContribution); -schemaRegistry.registerSchema(schemaId, schema); - -function updateSchema() { - commandsSchemas.length = 0; - commandsEnum.length = 0; - commandsEnumDescriptions.length = 0; - - const knownCommands = new Set(); - const addKnownCommand = (commandId: string, description?: string | undefined) => { - if (!/^_/.test(commandId)) { - if (!knownCommands.has(commandId)) { - knownCommands.add(commandId); - - commandsEnum.push(commandId); - commandsEnumDescriptions.push(description); - - // Also add the negative form for keybinding removal - commandsEnum.push(`-${commandId}`); - commandsEnumDescriptions.push(description); - } - } - }; - - const allCommands = CommandsRegistry.getCommands(); - for (let commandId in allCommands) { - const commandDescription = allCommands[commandId].description; - - addKnownCommand(commandId, commandDescription ? commandDescription.description : undefined); - - if (!commandDescription || !commandDescription.args || commandDescription.args.length !== 1 || !commandDescription.args[0].schema) { - continue; - } - - const argsSchema = commandDescription.args[0].schema; - const argsRequired = Array.isArray(argsSchema.required) && argsSchema.required.length > 0; - const addition = { - 'if': { - 'properties': { - 'command': { 'const': commandId } - } - }, - 'then': { - 'required': ([]).concat(argsRequired ? ['args'] : []), - 'properties': { - 'args': argsSchema - } - } - }; - - commandsSchemas.push(addition); - } - - const menuCommands = MenuRegistry.getCommands(); - for (let commandId in menuCommands) { - addKnownCommand(commandId); - } -} - -const configurationRegistry = Registry.as(ConfigExtensions.Configuration); -const keyboardConfiguration: IConfigurationNode = { - 'id': 'keyboard', - 'order': 15, - 'type': 'object', - 'title': nls.localize('keyboardConfigurationTitle', "Keyboard"), - 'overridable': true, - 'properties': { - 'keyboard.dispatch': { - 'type': 'string', - 'enum': ['code', 'keyCode'], - 'default': 'code', - 'markdownDescription': nls.localize('dispatch', "Controls the dispatching logic for key presses to use either `code` (recommended) or `keyCode`."), - 'included': OS === OperatingSystem.Macintosh || OS === OperatingSystem.Linux - }, - 'keyboard.touchbar.enabled': { - 'type': 'boolean', - 'default': true, - 'description': nls.localize('touchbar.enabled', "Enables the macOS touchbar buttons on the keyboard if available."), - 'included': OS === OperatingSystem.Macintosh && parseFloat(release()) >= 16 // Minimum: macOS Sierra (10.12.x = darwin 16.x) - } - } -}; - -configurationRegistry.registerConfiguration(keyboardConfiguration); - -registerSingleton(IKeybindingService, WorkbenchKeybindingService); \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/electron-browser/nativeKeymapService.ts b/src/vs/workbench/services/keybinding/electron-browser/nativeKeymapService.ts new file mode 100644 index 000000000..475c881af --- /dev/null +++ b/src/vs/workbench/services/keybinding/electron-browser/nativeKeymapService.ts @@ -0,0 +1,169 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as nativeKeymap from 'native-keymap'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { IKeymapService, IKeyboardLayoutInfo, IKeyboardMapping } from 'vs/workbench/services/keybinding/common/keymapInfo'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IKeyboardMapper, CachedKeyboardMapper } from 'vs/workbench/services/keybinding/common/keyboardMapper'; +import { Emitter, Event } from 'vs/base/common/event'; +import { DispatchConfig } from 'vs/workbench/services/keybinding/common/dispatchConfig'; +import { MacLinuxFallbackKeyboardMapper } from 'vs/workbench/services/keybinding/common/macLinuxFallbackKeyboardMapper'; +import { OS, OperatingSystem } from 'vs/base/common/platform'; +import { WindowsKeyboardMapper, windowsKeyboardMappingEquals } from 'vs/workbench/services/keybinding/common/windowsKeyboardMapper'; +import { MacLinuxKeyboardMapper, macLinuxKeyboardMappingEquals, IMacLinuxKeyboardMapping } from 'vs/workbench/services/keybinding/common/macLinuxKeyboardMapper'; +import { IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding'; + +export class KeyboardMapperFactory { + public static readonly INSTANCE = new KeyboardMapperFactory(); + + private _layoutInfo: nativeKeymap.IKeyboardLayoutInfo | null; + private _rawMapping: nativeKeymap.IKeyboardMapping | null; + private _keyboardMapper: IKeyboardMapper | null; + private _initialized: boolean; + + private readonly _onDidChangeKeyboardMapper = new Emitter(); + public readonly onDidChangeKeyboardMapper: Event = this._onDidChangeKeyboardMapper.event; + + private constructor() { + this._layoutInfo = null; + this._rawMapping = null; + this._keyboardMapper = null; + this._initialized = false; + } + + public _onKeyboardLayoutChanged(): void { + if (this._initialized) { + this._setKeyboardData(nativeKeymap.getCurrentKeyboardLayout(), nativeKeymap.getKeyMap()); + } + } + + public getKeyboardMapper(dispatchConfig: DispatchConfig): IKeyboardMapper { + if (!this._initialized) { + this._setKeyboardData(nativeKeymap.getCurrentKeyboardLayout(), nativeKeymap.getKeyMap()); + } + if (dispatchConfig === DispatchConfig.KeyCode) { + // Forcefully set to use keyCode + return new MacLinuxFallbackKeyboardMapper(OS); + } + return this._keyboardMapper!; + } + + public getCurrentKeyboardLayout(): nativeKeymap.IKeyboardLayoutInfo | null { + if (!this._initialized) { + this._setKeyboardData(nativeKeymap.getCurrentKeyboardLayout(), nativeKeymap.getKeyMap()); + } + return this._layoutInfo; + } + + private static _isUSStandard(_kbInfo: nativeKeymap.IKeyboardLayoutInfo): boolean { + if (OS === OperatingSystem.Linux) { + const kbInfo = _kbInfo; + return (kbInfo && kbInfo.layout === 'us'); + } + + if (OS === OperatingSystem.Macintosh) { + const kbInfo = _kbInfo; + return (kbInfo && kbInfo.id === 'com.apple.keylayout.US'); + } + + if (OS === OperatingSystem.Windows) { + const kbInfo = _kbInfo; + return (kbInfo && kbInfo.name === '00000409'); + } + + return false; + } + + public getRawKeyboardMapping(): nativeKeymap.IKeyboardMapping | null { + if (!this._initialized) { + this._setKeyboardData(nativeKeymap.getCurrentKeyboardLayout(), nativeKeymap.getKeyMap()); + } + return this._rawMapping; + } + + private _setKeyboardData(layoutInfo: nativeKeymap.IKeyboardLayoutInfo, rawMapping: nativeKeymap.IKeyboardMapping): void { + this._layoutInfo = layoutInfo; + + if (this._initialized && KeyboardMapperFactory._equals(this._rawMapping, rawMapping)) { + // nothing to do... + return; + } + + this._initialized = true; + this._rawMapping = rawMapping; + this._keyboardMapper = new CachedKeyboardMapper( + KeyboardMapperFactory._createKeyboardMapper(this._layoutInfo, this._rawMapping) + ); + this._onDidChangeKeyboardMapper.fire(); + } + + private static _createKeyboardMapper(layoutInfo: nativeKeymap.IKeyboardLayoutInfo, rawMapping: nativeKeymap.IKeyboardMapping): IKeyboardMapper { + const isUSStandard = KeyboardMapperFactory._isUSStandard(layoutInfo); + if (OS === OperatingSystem.Windows) { + return new WindowsKeyboardMapper(isUSStandard, rawMapping); + } + + if (Object.keys(rawMapping).length === 0) { + // Looks like reading the mappings failed (most likely Mac + Japanese/Chinese keyboard layouts) + return new MacLinuxFallbackKeyboardMapper(OS); + } + + if (OS === OperatingSystem.Macintosh) { + const kbInfo = layoutInfo; + if (kbInfo.id === 'com.apple.keylayout.DVORAK-QWERTYCMD') { + // Use keyCode based dispatching for DVORAK - QWERTY ⌘ + return new MacLinuxFallbackKeyboardMapper(OS); + } + } + + return new MacLinuxKeyboardMapper(isUSStandard, rawMapping, OS); + } + + private static _equals(a: nativeKeymap.IKeyboardMapping | null, b: nativeKeymap.IKeyboardMapping | null): boolean { + if (OS === OperatingSystem.Windows) { + return windowsKeyboardMappingEquals(a, b); + } + + return macLinuxKeyboardMappingEquals(a, b); + } +} + +class NativeKeymapService extends Disposable implements IKeymapService { + public _serviceBrand: any; + + private readonly _onDidChangeKeyboardMapper = new Emitter(); + public readonly onDidChangeKeyboardMapper: Event = this._onDidChangeKeyboardMapper.event; + + constructor() { + super(); + + this._register(KeyboardMapperFactory.INSTANCE.onDidChangeKeyboardMapper(() => { + this._onDidChangeKeyboardMapper.fire(); + })); + } + + getKeyboardMapper(dispatchConfig: DispatchConfig): IKeyboardMapper { + return KeyboardMapperFactory.INSTANCE.getKeyboardMapper(dispatchConfig); + } + + public getCurrentKeyboardLayout(): IKeyboardLayoutInfo | null { + return KeyboardMapperFactory.INSTANCE.getCurrentKeyboardLayout(); + } + + getAllKeyboardLayouts(): IKeyboardLayoutInfo[] { + return []; + } + + public getRawKeyboardMapping(): IKeyboardMapping | null { + return KeyboardMapperFactory.INSTANCE.getRawKeyboardMapping(); + } + + public validateCurrentKeyboardMapping(keyboardEvent: IKeyboardEvent): void { + return; + } +} + +registerSingleton(IKeymapService, NativeKeymapService, true); diff --git a/src/vs/workbench/services/keybinding/test/browserKeyboardMapper.test.ts b/src/vs/workbench/services/keybinding/test/browserKeyboardMapper.test.ts new file mode 100644 index 000000000..cbc20c365 --- /dev/null +++ b/src/vs/workbench/services/keybinding/test/browserKeyboardMapper.test.ts @@ -0,0 +1,150 @@ +/*--------------------------------------------------------------------------------------------- + * 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 'vs/workbench/services/keybinding/browser/keyboardLayouts/en.darwin'; // 15% +import 'vs/workbench/services/keybinding/browser/keyboardLayouts/de.darwin'; +import { KeyboardLayoutContribution } from 'vs/workbench/services/keybinding/browser/keyboardLayouts/_.contribution'; +import { BrowserKeyboardMapperFactoryBase } from '../browser/keymapService'; +import { KeymapInfo, IKeymapInfo } from '../common/keymapInfo'; +import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; +import { INotificationService } from 'vs/platform/notification/common/notification'; +import { ICommandService } from 'vs/platform/commands/common/commands'; +import { IStorageService } from 'vs/platform/storage/common/storage'; +import { TestStorageService } from 'vs/workbench/test/workbenchTestServices'; +import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService'; + +class TestKeyboardMapperFactory extends BrowserKeyboardMapperFactoryBase { + constructor(notificationService: INotificationService, storageService: IStorageService, commandService: ICommandService) { + // super(notificationService, storageService, commandService); + super(); + + const keymapInfos: IKeymapInfo[] = KeyboardLayoutContribution.INSTANCE.layoutInfos; + this._keymapInfos.push(...keymapInfos.map(info => (new KeymapInfo(info.layout, info.secondaryLayouts, info.mapping, info.isUserKeyboardLayout)))); + this._mru = this._keymapInfos; + this._initialized = true; + this.onKeyboardLayoutChanged(); + const usLayout = this.getUSStandardLayout(); + if (usLayout) { + this.setActiveKeyMapping(usLayout.mapping); + } + } +} + +suite('keyboard layout loader', () => { + let instantiationService: TestInstantiationService = new TestInstantiationService(); + let notitifcationService = instantiationService.stub(INotificationService, new TestNotificationService()); + let storageService = instantiationService.stub(IStorageService, new TestStorageService()); + + let commandService = instantiationService.stub(ICommandService, {}); + let instance = new TestKeyboardMapperFactory(notitifcationService, storageService, commandService); + + test('load default US keyboard layout', () => { + assert.notEqual(instance.activeKeyboardLayout, null); + assert.equal(instance.activeKeyboardLayout!.isUSStandard, true); + }); + + test('isKeyMappingActive', () => { + assert.equal(instance.isKeyMappingActive({ + KeyA: { + value: 'a', + valueIsDeadKey: false, + withShift: 'A', + withShiftIsDeadKey: false, + withAltGr: 'å', + withAltGrIsDeadKey: false, + withShiftAltGr: 'Å', + withShiftAltGrIsDeadKey: false + } + }), true); + + assert.equal(instance.isKeyMappingActive({ + KeyA: { + value: 'a', + valueIsDeadKey: false, + withShift: 'A', + withShiftIsDeadKey: false, + withAltGr: 'å', + withAltGrIsDeadKey: false, + withShiftAltGr: 'Å', + withShiftAltGrIsDeadKey: false + }, + KeyZ: { + value: 'z', + valueIsDeadKey: false, + withShift: 'Z', + withShiftIsDeadKey: false, + withAltGr: 'Ω', + withAltGrIsDeadKey: false, + withShiftAltGr: '¸', + withShiftAltGrIsDeadKey: false + } + }), true); + + assert.equal(instance.isKeyMappingActive({ + KeyZ: { + value: 'y', + valueIsDeadKey: false, + withShift: 'Y', + withShiftIsDeadKey: false, + withAltGr: '¥', + withAltGrIsDeadKey: false, + withShiftAltGr: 'Ÿ', + withShiftAltGrIsDeadKey: false + }, + }), false); + + }); + + test('Switch keymapping', () => { + instance.setActiveKeyMapping({ + KeyZ: { + value: 'y', + valueIsDeadKey: false, + withShift: 'Y', + withShiftIsDeadKey: false, + withAltGr: '¥', + withAltGrIsDeadKey: false, + withShiftAltGr: 'Ÿ', + withShiftAltGrIsDeadKey: false + } + }); + assert.equal(!!instance.activeKeyboardLayout!.isUSStandard, false); + assert.equal(instance.isKeyMappingActive({ + KeyZ: { + value: 'y', + valueIsDeadKey: false, + withShift: 'Y', + withShiftIsDeadKey: false, + withAltGr: '¥', + withAltGrIsDeadKey: false, + withShiftAltGr: 'Ÿ', + withShiftAltGrIsDeadKey: false + }, + }), true); + + instance.setUSKeyboardLayout(); + assert.equal(instance.activeKeyboardLayout!.isUSStandard, true); + }); + + test('Switch keyboard layout info', () => { + instance.setKeyboardLayout('com.apple.keylayout.German'); + assert.equal(!!instance.activeKeyboardLayout!.isUSStandard, false); + assert.equal(instance.isKeyMappingActive({ + KeyZ: { + value: 'y', + valueIsDeadKey: false, + withShift: 'Y', + withShiftIsDeadKey: false, + withAltGr: '¥', + withAltGrIsDeadKey: false, + withShiftAltGr: 'Ÿ', + withShiftAltGrIsDeadKey: false + }, + }), true); + + instance.setUSKeyboardLayout(); + assert.equal(instance.activeKeyboardLayout!.isUSStandard, true); + }); +}); diff --git a/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts b/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts index c9327d420..4ae911b01 100644 --- a/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts +++ b/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts @@ -40,10 +40,25 @@ import { KeybindingsEditingService } from 'vs/workbench/services/keybinding/comm import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { TextModelResolverService } from 'vs/workbench/services/textmodelResolver/common/textModelResolverService'; import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; -import { TestBackupFileService, TestContextService, TestEditorGroupsService, TestEditorService, TestLifecycleService, TestLogService, TestTextFileService, TestTextResourcePropertiesService } from 'vs/workbench/test/workbenchTestServices'; -import { FileService } from 'vs/workbench/services/files/common/fileService'; +import { TestBackupFileService, TestContextService, TestEditorGroupsService, TestEditorService, TestLifecycleService, TestTextFileService, TestTextResourcePropertiesService } from 'vs/workbench/test/workbenchTestServices'; +import { FileService } from 'vs/platform/files/common/fileService'; import { Schemas } from 'vs/base/common/network'; -import { DiskFileSystemProvider } from 'vs/workbench/services/files/node/diskFileSystemProvider'; +import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; +import { URI } from 'vs/base/common/uri'; +import { FileUserDataProvider } from 'vs/workbench/services/userData/common/fileUserDataProvider'; +import { parseArgs } from 'vs/platform/environment/node/argv'; +import { WorkbenchEnvironmentService } from 'vs/workbench/services/environment/node/environmentService'; +import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; + +class TestEnvironmentService extends WorkbenchEnvironmentService { + + constructor(private _appSettingsHome: URI) { + super(parseArgs(process.argv) as IWindowConfiguration, process.execPath); + } + + get appSettingsHome() { return this._appSettingsHome; } + +} interface Modifiers { metaKey?: boolean; @@ -65,7 +80,8 @@ suite('KeybindingsEditing', () => { instantiationService = new TestInstantiationService(); - instantiationService.stub(IEnvironmentService, { appKeybindingsPath: keybindingsFile, appSettingsPath: path.join(testDir, 'settings.json') }); + const environmentService = new TestEnvironmentService(URI.file(testDir)); + instantiationService.stub(IEnvironmentService, environmentService); instantiationService.stub(IConfigurationService, ConfigurationService); instantiationService.stub(IConfigurationService, 'getValue', { 'eol': '\n' }); instantiationService.stub(IConfigurationService, 'onDidUpdateConfiguration', () => { }); @@ -78,11 +94,13 @@ suite('KeybindingsEditing', () => { instantiationService.stub(IEditorService, new TestEditorService()); instantiationService.stub(ITelemetryService, NullTelemetryService); instantiationService.stub(IModeService, ModeServiceImpl); - instantiationService.stub(ILogService, new TestLogService()); + instantiationService.stub(ILogService, new NullLogService()); instantiationService.stub(ITextResourcePropertiesService, new TestTextResourcePropertiesService(instantiationService.get(IConfigurationService))); instantiationService.stub(IModelService, instantiationService.createInstance(ModelServiceImpl)); const fileService = new FileService(new NullLogService()); - fileService.registerProvider(Schemas.file, new DiskFileSystemProvider(new NullLogService())); + const diskFileSystemProvider = new DiskFileSystemProvider(new NullLogService()); + fileService.registerProvider(Schemas.file, diskFileSystemProvider); + fileService.registerProvider(Schemas.userData, new FileUserDataProvider(environmentService.appSettingsHome, environmentService.backupHome, diskFileSystemProvider, environmentService)); instantiationService.stub(IFileService, fileService); instantiationService.stub(IUntitledEditorService, instantiationService.createInstance(UntitledEditorService)); instantiationService.stub(ITextFileService, instantiationService.createInstance(TestTextFileService)); @@ -143,16 +161,6 @@ suite('KeybindingsEditing', () => { .then(() => assert.deepEqual(getUserKeybindings(), expected)); }); - test('edit a default keybinding to a non existing keybindings file', () => { - keybindingsFile = path.join(testDir, 'nonExistingFile.json'); - instantiationService.get(IEnvironmentService).appKeybindingsPath = keybindingsFile; - testObject = instantiationService.createInstance(KeybindingsEditingService); - - const expected: IUserFriendlyKeybinding[] = [{ key: 'alt+c', command: 'a' }, { key: 'escape', command: '-a' }]; - return testObject.editKeybinding(aResolvedKeybindingItem({ firstPart: { keyCode: KeyCode.Escape }, command: 'a' }), 'alt+c', undefined) - .then(() => assert.deepEqual(getUserKeybindings(), expected)); - }); - test('edit a default keybinding to an empty array', () => { writeToKeybindingsFile(); const expected: IUserFriendlyKeybinding[] = [{ key: 'alt+c', command: 'a' }, { key: 'escape', command: '-a' }]; @@ -274,7 +282,7 @@ suite('KeybindingsEditing', () => { parts.push(aSimpleKeybinding(chordPart)); } } - let keybinding = parts.length > 0 ? new USLayoutResolvedKeybinding(new ChordKeybinding(parts), OS) : null; + const keybinding = parts.length > 0 ? new USLayoutResolvedKeybinding(new ChordKeybinding(parts), OS) : undefined; return new ResolvedKeybindingItem(keybinding, command || 'some command', null, when ? ContextKeyExpr.deserialize(when) : undefined, isDefault === undefined ? true : isDefault); } diff --git a/src/vs/workbench/services/label/common/labelService.ts b/src/vs/workbench/services/label/common/labelService.ts index b4f9a8bd2..a8e2290be 100644 --- a/src/vs/workbench/services/label/common/labelService.ts +++ b/src/vs/workbench/services/label/common/labelService.ts @@ -68,7 +68,7 @@ const resourceLabelFormattersExtPoint = ExtensionsRegistry.registerExtensionPoin }); const sepRegexp = /\//g; -const labelMatchingRegexp = /\$\{scheme\}|\$\{authority\}|\$\{path\}/g; +const labelMatchingRegexp = /\$\{(scheme|authority|path|(query)\.(.+?))\}/g; function hasDriveLetter(path: string): boolean { return !!(isWindows && path && path[2] === ':'); @@ -222,12 +222,23 @@ export class LabelService implements ILabelService { } private formatUri(resource: URI, formatting: ResourceLabelFormatting, forceNoTildify?: boolean): string { - let label = formatting.label.replace(labelMatchingRegexp, match => { - switch (match) { - case '${scheme}': return resource.scheme; - case '${authority}': return resource.authority; - case '${path}': return resource.path; - default: return ''; + let label = formatting.label.replace(labelMatchingRegexp, (match, token, qsToken, qsValue) => { + switch (token) { + case 'scheme': return resource.scheme; + case 'authority': return resource.authority; + case 'path': return resource.path; + default: { + if (qsToken === 'query') { + const { query } = resource; + if (query && query[0] === '{' && query[query.length - 1] === '}') { + try { + return JSON.parse(query)[qsValue] || ''; + } + catch { } + } + } + return ''; + } } }); @@ -265,4 +276,4 @@ export class LabelService implements ILabelService { } } -registerSingleton(ILabelService, LabelService, true); \ No newline at end of file +registerSingleton(ILabelService, LabelService, true); diff --git a/src/vs/workbench/services/label/test/label.test.ts b/src/vs/workbench/services/label/test/label.test.ts index a610640c9..ee4650f4d 100644 --- a/src/vs/workbench/services/label/test/label.test.ts +++ b/src/vs/workbench/services/label/test/label.test.ts @@ -97,4 +97,64 @@ suite('URI Label', () => { const uri1 = URI.parse('vscode://microsoft.com/1/2/3/4/5'); assert.equal(labelService.getUriLabel(uri1, { relative: false }), 'second'); }); + + test('custom query', function () { + labelService.registerFormatter({ + scheme: 'vscode', + formatting: { + label: 'LABEL${query.prefix}: ${query.path}/END', + separator: '/', + tildify: true, + normalizeDriveLetter: true + } + }); + + const uri1 = URI.parse(`vscode://microsoft.com/1/2/3/4/5?${encodeURIComponent(JSON.stringify({ prefix: 'prefix', path: 'path' }))}`); + assert.equal(labelService.getUriLabel(uri1, { relative: false }), 'LABELprefix: path/END'); + }); + + test('custom query without value', function () { + labelService.registerFormatter({ + scheme: 'vscode', + formatting: { + label: 'LABEL${query.prefix}: ${query.path}/END', + separator: '/', + tildify: true, + normalizeDriveLetter: true + } + }); + + const uri1 = URI.parse(`vscode://microsoft.com/1/2/3/4/5?${encodeURIComponent(JSON.stringify({ path: 'path' }))}`); + assert.equal(labelService.getUriLabel(uri1, { relative: false }), 'LABEL: path/END'); + }); + + test('custom query without query json', function () { + labelService.registerFormatter({ + scheme: 'vscode', + formatting: { + label: 'LABEL${query.prefix}: ${query.path}/END', + separator: '/', + tildify: true, + normalizeDriveLetter: true + } + }); + + const uri1 = URI.parse('vscode://microsoft.com/1/2/3/4/5?path=foo'); + assert.equal(labelService.getUriLabel(uri1, { relative: false }), 'LABEL: /END'); + }); + + test('custom query without query', function () { + labelService.registerFormatter({ + scheme: 'vscode', + formatting: { + label: 'LABEL${query.prefix}: ${query.path}/END', + separator: '/', + tildify: true, + normalizeDriveLetter: true + } + }); + + const uri1 = URI.parse('vscode://microsoft.com/1/2/3/4/5'); + assert.equal(labelService.getUriLabel(uri1, { relative: false }), 'LABEL: /END'); + }); }); diff --git a/src/vs/workbench/services/layout/browser/layoutService.ts b/src/vs/workbench/services/layout/browser/layoutService.ts index 815af5ede..344c7657d 100644 --- a/src/vs/workbench/services/layout/browser/layoutService.ts +++ b/src/vs/workbench/services/layout/browser/layoutService.ts @@ -8,6 +8,7 @@ import { Event } from 'vs/base/common/event'; import { MenuBarVisibility } from 'vs/platform/windows/common/windows'; import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; import { Part } from 'vs/workbench/browser/part'; +import { Dimension } from 'vs/base/browser/dom'; export const IWorkbenchLayoutService = createDecorator('layoutService'); @@ -45,6 +46,21 @@ export interface IWorkbenchLayoutService extends ILayoutService { */ readonly onZenModeChange: Event; + /** + * Emits when fullscreen is enabled or disabled. + */ + readonly onFullscreenChange: Event; + + /** + * Emits when centered layout is enabled or disabled. + */ + readonly onCenteredLayoutChange: Event; + + /** + * Emit when panel position changes. + */ + readonly onPanelPositionChange: Event; + /** * Asks the part service if all parts have been fully restored. For editor part * this means that the contents of editors have loaded. @@ -66,6 +82,11 @@ export interface IWorkbenchLayoutService extends ILayoutService { */ isVisible(part: Parts): boolean; + /** + * Returns if the part is visible. + */ + getDimension(part: Parts): Dimension; + /** * Set activity bar hidden or not */ @@ -123,6 +144,11 @@ export interface IWorkbenchLayoutService extends ILayoutService { */ setPanelPosition(position: Position): void; + /** + * Returns the element that is parent of the workbench element. + */ + getWorkbenchContainer(): HTMLElement; + /** * Returns the element that contains the workbench. */ diff --git a/src/vs/workbench/services/notification/common/notificationService.ts b/src/vs/workbench/services/notification/common/notificationService.ts index 0861420e8..78280e20a 100644 --- a/src/vs/workbench/services/notification/common/notificationService.ts +++ b/src/vs/workbench/services/notification/common/notificationService.ts @@ -3,15 +3,17 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { INotificationService, INotification, INotificationHandle, Severity, NotificationMessage, INotificationActions, IPromptChoice, IPromptOptions } from 'vs/platform/notification/common/notification'; +import { INotificationService, INotification, INotificationHandle, Severity, NotificationMessage, INotificationActions, IPromptChoice, IPromptOptions, IStatusMessageOptions } from 'vs/platform/notification/common/notification'; import { INotificationsModel, NotificationsModel, ChoiceAction } from 'vs/workbench/common/notifications'; -import { dispose, Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; import { Event } from 'vs/base/common/event'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { IAction } from 'vs/base/common/actions'; export class NotificationService extends Disposable implements INotificationService { - _serviceBrand: any; + _serviceBrand: ServiceIdentifier; private _model: INotificationsModel = this._register(new NotificationsModel()); @@ -26,7 +28,7 @@ export class NotificationService extends Disposable implements INotificationServ return; } - this.model.notify({ severity: Severity.Info, message }); + this.model.addNotification({ severity: Severity.Info, message }); } warn(message: NotificationMessage | NotificationMessage[]): void { @@ -36,7 +38,7 @@ export class NotificationService extends Disposable implements INotificationServ return; } - this.model.notify({ severity: Severity.Warning, message }); + this.model.addNotification({ severity: Severity.Warning, message }); } error(message: NotificationMessage | NotificationMessage[]): void { @@ -46,37 +48,32 @@ export class NotificationService extends Disposable implements INotificationServ return; } - this.model.notify({ severity: Severity.Error, message }); + this.model.addNotification({ severity: Severity.Error, message }); } notify(notification: INotification): INotificationHandle { - return this.model.notify(notification); + return this.model.addNotification(notification); } prompt(severity: Severity, message: string, choices: IPromptChoice[], options?: IPromptOptions): INotificationHandle { - const toDispose: IDisposable[] = []; + const toDispose = new DisposableStore(); let choiceClicked = false; let handle: INotificationHandle; // Convert choices into primary/secondary actions - const actions: INotificationActions = { primary: [], secondary: [] }; + const primaryActions: IAction[] = []; + const secondaryActions: IAction[] = []; choices.forEach((choice, index) => { const action = new ChoiceAction(`workbench.dialog.choice.${index}`, choice); if (!choice.isSecondary) { - if (!actions.primary) { - actions.primary = []; - } - actions.primary.push(action); + primaryActions.push(action); } else { - if (!actions.secondary) { - actions.secondary = []; - } - actions.secondary.push(action); + secondaryActions.push(action); } // React to action being clicked - toDispose.push(action.onDidRun(() => { + toDispose.add(action.onDidRun(() => { choiceClicked = true; // Close notification unless we are told to keep open @@ -85,16 +82,17 @@ export class NotificationService extends Disposable implements INotificationServ } })); - toDispose.push(action); + toDispose.add(action); }); // Show notification with actions + const actions: INotificationActions = { primary: primaryActions, secondary: secondaryActions }; handle = this.notify({ severity, message, actions, sticky: options && options.sticky, silent: options && options.silent }); Event.once(handle.onDidClose)(() => { // Cleanup when notification gets disposed - dispose(toDispose); + toDispose.dispose(); // Indicate cancellation to the outside if no action was executed if (options && typeof options.onCancel === 'function' && !choiceClicked) { @@ -104,6 +102,10 @@ export class NotificationService extends Disposable implements INotificationServ return handle; } + + status(message: NotificationMessage, options?: IStatusMessageOptions): IDisposable { + return this.model.showStatusMessage(message, options); + } } registerSingleton(INotificationService, NotificationService, true); \ No newline at end of file diff --git a/src/vs/workbench/services/output/common/outputChannelModel.ts b/src/vs/workbench/services/output/common/outputChannelModel.ts index 007ead80d..be87bf1ae 100644 --- a/src/vs/workbench/services/output/common/outputChannelModel.ts +++ b/src/vs/workbench/services/output/common/outputChannelModel.ts @@ -51,10 +51,10 @@ export abstract class AsbtractOutputChannelModelService { export abstract class AbstractFileOutputChannelModel extends Disposable implements IOutputChannelModel { - protected _onDidAppendedContent = new Emitter(); + protected readonly _onDidAppendedContent = this._register(new Emitter()); readonly onDidAppendedContent: Event = this._onDidAppendedContent.event; - protected _onDispose = new Emitter(); + protected readonly _onDispose = this._register(new Emitter()); readonly onDispose: Event = this._onDispose.event; protected modelUpdater: RunOnceScheduler; @@ -96,12 +96,11 @@ export abstract class AbstractFileOutputChannelModel extends Disposable implemen } else { this.model = this.modelService.createModel(content, this.modeService.create(this.mimeType), this.modelUri); this.onModelCreated(this.model); - const disposables: IDisposable[] = []; - disposables.push(this.model.onWillDispose(() => { + const disposable = this.model.onWillDispose(() => { this.onModelWillDispose(this.model); this.model = null; - dispose(disposables); - })); + dispose(disposable); + }); } return this.model; } @@ -340,11 +339,10 @@ export class BufferredOutputChannel extends Disposable implements IOutputChannel private createModel(content: string): ITextModel { const model = this.modelService.createModel(content, this.modeService.create(this.mimeType), this.modelUri); - const disposables: IDisposable[] = []; - disposables.push(model.onWillDispose(() => { + const disposable = model.onWillDispose(() => { this.model = null; - dispose(disposables); - })); + dispose(disposable); + }); return model; } diff --git a/src/vs/workbench/services/output/node/outputChannelModelService.ts b/src/vs/workbench/services/output/node/outputChannelModelService.ts index 7f540132b..da44834ef 100644 --- a/src/vs/workbench/services/output/node/outputChannelModelService.ts +++ b/src/vs/workbench/services/output/node/outputChannelModelService.ts @@ -169,10 +169,7 @@ class DelegatedOutputChannelModel extends Disposable implements IOutputChannelMo } catch (e) { // Do not crash if spdlog rotating logger cannot be loaded (workaround for https://github.com/Microsoft/vscode/issues/47883) this.logService.error(e); - /* __GDPR__ - "output.channel.creation.error" : {} - */ - this.telemetryService.publicLog('output.channel.creation.error'); + this.telemetryService.publicLog2('output.channel.creation.error'); outputChannelModel = this.instantiationService.createInstance(BufferredOutputChannel, modelUri, mimeType); } this._register(outputChannelModel); diff --git a/src/vs/workbench/services/panel/common/panelService.ts b/src/vs/workbench/services/panel/common/panelService.ts index 4609cb5d2..9e957d617 100644 --- a/src/vs/workbench/services/panel/common/panelService.ts +++ b/src/vs/workbench/services/panel/common/panelService.ts @@ -8,6 +8,7 @@ import { IPanel } from 'vs/workbench/common/panel'; import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; import { IBadge } from 'vs/workbench/services/activity/common/activity'; import { IDisposable } from 'vs/base/common/lifecycle'; +import { IProgressIndicator } from 'vs/platform/progress/common/progress'; export const IPanelService = createDecorator('panelService'); @@ -18,11 +19,11 @@ export interface IPanelIdentifier { } export interface IPanelService { - _serviceBrand: ServiceIdentifier; - onDidPanelOpen: Event<{ panel: IPanel, focus: boolean }>; + _serviceBrand: ServiceIdentifier; - onDidPanelClose: Event; + readonly onDidPanelOpen: Event<{ panel: IPanel, focus: boolean }>; + readonly onDidPanelClose: Event; /** * Opens a panel with the given identifier and pass keyboard focus to it if specified. @@ -35,7 +36,12 @@ export interface IPanelService { getActivePanel(): IPanel | null; /** - * Returns all built-in panels following the default order (Problems - Output - Debug Console - Terminal) + * Returns the panel by id. + */ + getPanel(id: string): IPanelIdentifier | undefined; + + /** + * Returns all built-in panels following the default order */ getPanels(): IPanelIdentifier[]; @@ -44,6 +50,11 @@ export interface IPanelService { */ getPinnedPanels(): IPanelIdentifier[]; + /** + * Returns the progress indicator for the panel bar. + */ + getProgressIndicator(id: string): IProgressIndicator | null; + /** * Show an activity in a panel. */ diff --git a/src/vs/workbench/services/preferences/browser/preferencesService.ts b/src/vs/workbench/services/preferences/browser/preferencesService.ts index 0ca6f7d17..8788a4167 100644 --- a/src/vs/workbench/services/preferences/browser/preferencesService.ts +++ b/src/vs/workbench/services/preferences/browser/preferencesService.ts @@ -91,11 +91,15 @@ export class PreferencesService extends Disposable implements IPreferencesServic private readonly defaultSettingsRawResource = URI.from({ scheme: network.Schemas.vscode, authority: 'defaultsettings', path: '/defaultSettings.json' }); get userSettingsResource(): URI { - return this.getEditableSettingsURI(ConfigurationTarget.USER)!; + return this.environmentService.settingsResource; } get workspaceSettingsResource(): URI | null { - return this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE); + if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { + return null; + } + const workspace = this.contextService.getWorkspace(); + return workspace.configuration || workspace.folders[0].toResource(FOLDER_SETTINGS_PATH); } get settingsEditor2Input(): SettingsEditor2Input { @@ -103,7 +107,8 @@ export class PreferencesService extends Disposable implements IPreferencesServic } getFolderSettingsResource(resource: URI): URI | null { - return this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE_FOLDER, resource); + const folder = this.contextService.getWorkspaceFolder(resource); + return folder ? folder.toResource(FOLDER_SETTINGS_PATH) : null; } resolveModel(uri: URI): Promise { @@ -153,7 +158,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic return Promise.resolve(null); } - createPreferencesEditorModel(uri: URI): Promise> { + async createPreferencesEditorModel(uri: URI): Promise | null> { if (this.isDefaultSettingsResource(uri)) { return this.createDefaultSettingsEditorModel(uri); } @@ -162,16 +167,25 @@ export class PreferencesService extends Disposable implements IPreferencesServic return this.createEditableSettingsEditorModel(ConfigurationTarget.USER_LOCAL, uri); } - const workspaceSettingsUri = this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE); + const workspaceSettingsUri = await this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE); if (workspaceSettingsUri && workspaceSettingsUri.toString() === uri.toString()) { return this.createEditableSettingsEditorModel(ConfigurationTarget.WORKSPACE, workspaceSettingsUri); } if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) { - return this.createEditableSettingsEditorModel(ConfigurationTarget.WORKSPACE_FOLDER, uri); + const settingsUri = await this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE_FOLDER, uri); + if (settingsUri && settingsUri.toString() === uri.toString()) { + return this.createEditableSettingsEditorModel(ConfigurationTarget.WORKSPACE_FOLDER, uri); + } } - return Promise.reject(`unknown resource: ${uri.toString()}`); + const remoteEnvironment = await this.remoteAgentService.getEnvironment(); + const remoteSettingsUri = remoteEnvironment ? remoteEnvironment.settingsPath : null; + if (remoteSettingsUri && remoteSettingsUri.toString() === uri.toString()) { + return this.createEditableSettingsEditorModel(ConfigurationTarget.USER_REMOTE, uri); + } + + return null; } openRawDefaultSettings(): Promise { @@ -237,11 +251,11 @@ export class PreferencesService extends Disposable implements IPreferencesServic this.openOrSwitchSettings2(ConfigurationTarget.WORKSPACE, undefined, options, group); } - openFolderSettings(folder: URI, jsonEditor?: boolean, options?: ISettingsEditorOptions, group?: IEditorGroup): Promise { + async openFolderSettings(folder: URI, jsonEditor?: boolean, options?: ISettingsEditorOptions, group?: IEditorGroup): Promise { jsonEditor = typeof jsonEditor === 'undefined' ? this.configurationService.getValue('workbench.settings.editor') === 'json' : jsonEditor; - const folderSettingsUri = this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE_FOLDER, folder); + const folderSettingsUri = await this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE_FOLDER, folder); if (jsonEditor) { if (folderSettingsUri) { return this.openOrSwitchSettings(ConfigurationTarget.WORKSPACE_FOLDER, folderSettingsUri, options, group); @@ -265,15 +279,13 @@ export class PreferencesService extends Disposable implements IPreferencesServic } openGlobalKeybindingSettings(textual: boolean): Promise { - /* __GDPR__ - "openKeybindings" : { - "textual" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } - } - */ - this.telemetryService.publicLog('openKeybindings', { textual }); + type OpenKeybindingsClassification = { + textual: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + }; + this.telemetryService.publicLog2<{ textual: boolean }, OpenKeybindingsClassification>('openKeybindings', { textual }); if (textual) { const emptyContents = '// ' + nls.localize('emptyKeybindingsHeader', "Place your key bindings in this file to override the defaults") + '\n[\n]'; - const editableKeybindings = URI.file(this.environmentService.appKeybindingsPath); + const editableKeybindings = this.environmentService.keybindingsResource; const openDefaultKeybindings = !!this.configurationService.getValue('workbench.settings.openDefaultKeybindings'); // Create as needed and open in editor @@ -391,8 +403,8 @@ export class PreferencesService extends Disposable implements IPreferencesServic return this.editorService.openEditor(input, SettingsEditorOptions.create(settingsOptions), group); } - private doSwitchSettings(target: ConfigurationTarget, resource: URI, input: PreferencesEditorInput, group: IEditorGroup, options?: ISettingsEditorOptions): Promise { - const settingsURI = this.getEditableSettingsURI(target, resource); + private async doSwitchSettings(target: ConfigurationTarget, resource: URI, input: PreferencesEditorInput, group: IEditorGroup, options?: ISettingsEditorOptions): Promise { + const settingsURI = await this.getEditableSettingsURI(target, resource); if (!settingsURI) { return Promise.reject(`Invalid settings URI - ${resource.toString()}`); } @@ -479,18 +491,14 @@ export class PreferencesService extends Disposable implements IPreferencesServic .then(() => this.editorService.createInput({ resource })); } - private createEditableSettingsEditorModel(configurationTarget: ConfigurationTarget, resource: URI): Promise { - const settingsUri = this.getEditableSettingsURI(configurationTarget, resource); - if (settingsUri) { - const workspace = this.contextService.getWorkspace(); - if (workspace.configuration && workspace.configuration.toString() === settingsUri.toString()) { - return this.textModelResolverService.createModelReference(settingsUri) - .then(reference => this.instantiationService.createInstance(WorkspaceConfigurationEditorModel, reference, configurationTarget)); - } + private createEditableSettingsEditorModel(configurationTarget: ConfigurationTarget, settingsUri: URI): Promise { + const workspace = this.contextService.getWorkspace(); + if (workspace.configuration && workspace.configuration.toString() === settingsUri.toString()) { return this.textModelResolverService.createModelReference(settingsUri) - .then(reference => this.instantiationService.createInstance(SettingsEditorModel, reference, configurationTarget)); + .then(reference => this.instantiationService.createInstance(WorkspaceConfigurationEditorModel, reference, configurationTarget)); } - return Promise.reject(`unknown target: ${configurationTarget} and resource: ${resource.toString()}`); + return this.textModelResolverService.createModelReference(settingsUri) + .then(reference => this.instantiationService.createInstance(SettingsEditorModel, reference, configurationTarget)); } private createDefaultSettingsEditorModel(defaultSettingsUri: URI): Promise { @@ -520,23 +528,19 @@ export class PreferencesService extends Disposable implements IPreferencesServic return this._defaultUserSettingsContentModel; } - private getEditableSettingsURI(configurationTarget: ConfigurationTarget, resource?: URI): URI | null { + private async getEditableSettingsURI(configurationTarget: ConfigurationTarget, resource?: URI): Promise { switch (configurationTarget) { case ConfigurationTarget.USER: case ConfigurationTarget.USER_LOCAL: - return URI.file(this.environmentService.appSettingsPath); + return this.userSettingsResource; case ConfigurationTarget.USER_REMOTE: - return URI.file(this.environmentService.appSettingsPath); + const remoteEnvironment = await this.remoteAgentService.getEnvironment(); + return remoteEnvironment ? remoteEnvironment.settingsPath : null; case ConfigurationTarget.WORKSPACE: - if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { - return null; - } - const workspace = this.contextService.getWorkspace(); - return workspace.configuration || workspace.folders[0].toResource(FOLDER_SETTINGS_PATH); + return this.workspaceSettingsResource; case ConfigurationTarget.WORKSPACE_FOLDER: if (resource) { - const folder = this.contextService.getWorkspaceFolder(resource); - return folder ? folder.toResource(FOLDER_SETTINGS_PATH) : null; + return this.getFolderSettingsResource(resource); } } return null; diff --git a/src/vs/workbench/services/preferences/common/keybindingsEditorModel.ts b/src/vs/workbench/services/preferences/common/keybindingsEditorModel.ts index fed784141..01bf60c34 100644 --- a/src/vs/workbench/services/preferences/common/keybindingsEditorModel.ts +++ b/src/vs/workbench/services/preferences/common/keybindingsEditorModel.ts @@ -160,7 +160,7 @@ export class KeybindingsEditorModel extends EditorModel { return result; } - resolve(editorActionsLabels: { [id: string]: string; }): Promise { + resolve(editorActionsLabels: Map): Promise { const workbenchActionsRegistry = Registry.as(ActionExtensions.WorkbenchActions); this._keybindingItemsSortedByPrecedence = []; @@ -174,7 +174,7 @@ export class KeybindingsEditorModel extends EditorModel { const commandsWithDefaultKeybindings = this.keybindingsService.getDefaultKeybindings().map(keybinding => keybinding.command); for (const command of KeybindingResolver.getAllUnboundCommands(boundCommands)) { - const keybindingItem = new ResolvedKeybindingItem(null, command, null, undefined, commandsWithDefaultKeybindings.indexOf(command) === -1); + const keybindingItem = new ResolvedKeybindingItem(undefined, command, null, undefined, commandsWithDefaultKeybindings.indexOf(command) === -1); this._keybindingItemsSortedByPrecedence.push(KeybindingsEditorModel.toKeybindingEntry(command, keybindingItem, workbenchActionsRegistry, editorActionsLabels)); } this._keybindingItems = this._keybindingItemsSortedByPrecedence.slice(0).sort((a, b) => KeybindingsEditorModel.compareKeybindingData(a, b)); @@ -209,9 +209,9 @@ export class KeybindingsEditorModel extends EditorModel { return a.command.localeCompare(b.command); } - private static toKeybindingEntry(command: string, keybindingItem: ResolvedKeybindingItem, workbenchActionsRegistry: IWorkbenchActionRegistry, editorActions: { [id: string]: string; }): IKeybindingItem { - const menuCommand = MenuRegistry.getCommand(command); - const editorActionLabel = editorActions[command]; + private static toKeybindingEntry(command: string, keybindingItem: ResolvedKeybindingItem, workbenchActionsRegistry: IWorkbenchActionRegistry, editorActions: Map): IKeybindingItem { + const menuCommand = MenuRegistry.getCommand(command)!; + const editorActionLabel = editorActions.get(command)!; return { keybinding: keybindingItem.resolvedKeybinding, keybindingItem, diff --git a/src/vs/workbench/services/preferences/common/preferences.ts b/src/vs/workbench/services/preferences/common/preferences.ts index 008d85de8..abf288178 100644 --- a/src/vs/workbench/services/preferences/common/preferences.ts +++ b/src/vs/workbench/services/preferences/common/preferences.ts @@ -25,6 +25,7 @@ export enum SettingValueType { Integer = 'integer', Number = 'number', Boolean = 'boolean', + ArrayOfString = 'array-of-string', Exclude = 'exclude', Complex = 'complex', NullableInteger = 'nullable-integer', @@ -61,6 +62,7 @@ export interface ISetting { scope?: ConfigurationScope; type?: string | string[]; + arrayItemType?: string; enum?: string[]; enumDescriptions?: string[]; enumDescriptionsAreMarkdown?: boolean; @@ -196,7 +198,7 @@ export interface IPreferencesService { getFolderSettingsResource(resource: URI): URI | null; resolveModel(uri: URI): Promise; - createPreferencesEditorModel(uri: URI): Promise>; + createPreferencesEditorModel(uri: URI): Promise | null>; createSettings2EditorModel(): Settings2EditorModel; // TODO openRawDefaultSettings(): Promise; diff --git a/src/vs/workbench/services/preferences/common/preferencesEditorInput.ts b/src/vs/workbench/services/preferences/common/preferencesEditorInput.ts index 002a49d79..ee813e14f 100644 --- a/src/vs/workbench/services/preferences/common/preferencesEditorInput.ts +++ b/src/vs/workbench/services/preferences/common/preferencesEditorInput.ts @@ -31,7 +31,7 @@ export class DefaultPreferencesEditorInput extends ResourceEditorInput { constructor(defaultSettingsResource: URI, @ITextModelService textModelResolverService: ITextModelService ) { - super(nls.localize('settingsEditorName', "Default Settings"), '', defaultSettingsResource, textModelResolverService); + super(nls.localize('settingsEditorName', "Default Settings"), '', defaultSettingsResource, undefined, textModelResolverService); } getTypeId(): string { diff --git a/src/vs/workbench/services/preferences/common/preferencesModels.ts b/src/vs/workbench/services/preferences/common/preferencesModels.ts index 121cfeb9f..d24d2a53f 100644 --- a/src/vs/workbench/services/preferences/common/preferencesModels.ts +++ b/src/vs/workbench/services/preferences/common/preferencesModels.ts @@ -22,7 +22,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { Registry } from 'vs/platform/registry/common/platform'; import { EditorModel } from 'vs/workbench/common/editor'; import { IFilterMetadata, IFilterResult, IGroupFilter, IKeybindingsEditorModel, ISearchResultGroup, ISetting, ISettingMatch, ISettingMatcher, ISettingsEditorModel, ISettingsGroup } from 'vs/workbench/services/preferences/common/preferences'; -import { withNullAsUndefined } from 'vs/base/common/types'; +import { withNullAsUndefined, isArray } from 'vs/base/common/types'; export const nullRange: IRange = { startLineNumber: -1, startColumn: -1, endLineNumber: -1, endColumn: -1 }; export function isNullRange(range: IRange): boolean { return range.startLineNumber === -1 && range.startColumn === -1 && range.endLineNumber === -1 && range.endColumn === -1; } @@ -375,6 +375,7 @@ function parse(model: ITextModel, isSettingsProperty: (currentProperty: string, const position = model.getPositionAt(offset); range.endLineNumber = position.lineNumber; range.endColumn = position.column; + settingsPropertyIndex = -1; } }, onArrayBegin: (offset: number, length: number) => { @@ -613,6 +614,10 @@ export class DefaultSettings extends Disposable { const value = prop.default; const description = (prop.description || prop.markdownDescription || '').split('\n'); const overrides = OVERRIDE_PROPERTY_PATTERN.test(key) ? this.parseOverrideSettings(prop.default) : []; + const listItemType = prop.type === 'array' && prop.items && !isArray(prop.items) && prop.items.type && !isArray(prop.items.type) + ? prop.items.type + : undefined; + result.push({ key, value, @@ -625,6 +630,7 @@ export class DefaultSettings extends Disposable { overrides, scope: prop.scope, type: prop.type, + arrayItemType: listItemType, enum: prop.enum, enumDescriptions: prop.enumDescriptions || prop.markdownEnumDescriptions, enumDescriptionsAreMarkdown: !prop.enumDescriptions, diff --git a/src/vs/workbench/services/preferences/test/common/keybindingsEditorModel.test.ts b/src/vs/workbench/services/preferences/test/common/keybindingsEditorModel.test.ts index 4c256284b..675c17c8b 100644 --- a/src/vs/workbench/services/preferences/test/common/keybindingsEditorModel.test.ts +++ b/src/vs/workbench/services/preferences/test/common/keybindingsEditorModel.test.ts @@ -56,7 +56,7 @@ suite('KeybindingsEditorModel test', () => { aResolvedKeybindingItem({ command: 'b' + uuid.generateUuid(), firstPart: { keyCode: KeyCode.Escape }, chordPart: { keyCode: KeyCode.Escape } }) ); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actuals = asResolvedKeybindingItems(testObject.fetch('')); assertKeybindingItems(actuals, expected); }); @@ -67,7 +67,7 @@ suite('KeybindingsEditorModel test', () => { aResolvedKeybindingItem({ command: 'b' + uuid.generateUuid(), firstPart: { keyCode: KeyCode.Escape }, chordPart: { keyCode: KeyCode.Escape } }) ); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actuals = asResolvedKeybindingItems(testObject.fetch('').slice(0, 2), true); assertKeybindingItems(actuals, expected); }); @@ -80,7 +80,7 @@ suite('KeybindingsEditorModel test', () => { ); const expected = [keybindings[2], keybindings[0], keybindings[1]]; - await testObject.resolve({}); + await testObject.resolve(new Map()); const actuals = asResolvedKeybindingItems(testObject.fetch('')); assertKeybindingItems(actuals, expected); }); @@ -93,7 +93,7 @@ suite('KeybindingsEditorModel test', () => { ); const expected = [keybindings[1], keybindings[0]]; - await testObject.resolve({}); + await testObject.resolve(new Map()); const actuals = asResolvedKeybindingItems(testObject.fetch('')); assertKeybindingItems(actuals, expected); }); @@ -113,7 +113,7 @@ suite('KeybindingsEditorModel test', () => { instantiationService.stub(IKeybindingService, 'getKeybindings', () => keybindings); instantiationService.stub(IKeybindingService, 'getDefaultKeybindings', () => keybindings); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actuals = asResolvedKeybindingItems(testObject.fetch('')); assertKeybindingItems(actuals, expected); }); @@ -131,7 +131,7 @@ suite('KeybindingsEditorModel test', () => { registerCommandWithTitle(keybindings[3].command!, 'Same Title'); const expected = [keybindings[3], keybindings[1], keybindings[0], keybindings[2]]; - await testObject.resolve({}); + await testObject.resolve(new Map()); const actuals = asResolvedKeybindingItems(testObject.fetch('')); assertKeybindingItems(actuals, expected); }); @@ -143,7 +143,7 @@ suite('KeybindingsEditorModel test', () => { aResolvedKeybindingItem({ command: 'a' + uuid.generateUuid(), firstPart: { keyCode: KeyCode.Backspace } }) ); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actuals = asResolvedKeybindingItems(testObject.fetch('', true)); assertKeybindingItems(actuals, expected); }); @@ -152,7 +152,7 @@ suite('KeybindingsEditorModel test', () => { const expected = aResolvedKeybindingItem({ command: 'a' + uuid.generateUuid(), firstPart: { keyCode: KeyCode.Escape }, when: 'context1 && context2' }); prepareKeybindingService(expected); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('')[0]; assert.equal(actual.keybindingItem.command, expected.command); assert.equal(actual.keybindingItem.commandLabel, ''); @@ -166,7 +166,7 @@ suite('KeybindingsEditorModel test', () => { prepareKeybindingService(expected); registerCommandWithTitle(expected.command!, 'Some Title'); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('')[0]; assert.equal(actual.keybindingItem.command, expected.command); assert.equal(actual.keybindingItem.commandLabel, 'Some Title'); @@ -179,7 +179,7 @@ suite('KeybindingsEditorModel test', () => { CommandsRegistry.registerCommand('command_without_keybinding', () => { }); prepareKeybindingService(); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('').filter(element => element.keybindingItem.command === 'command_without_keybinding')[0]; assert.equal(actual.keybindingItem.command, 'command_without_keybinding'); assert.equal(actual.keybindingItem.commandLabel, ''); @@ -193,7 +193,7 @@ suite('KeybindingsEditorModel test', () => { registerCommandWithTitle(id, 'some title'); prepareKeybindingService(); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('').filter(element => element.keybindingItem.command === id)[0]; assert.equal(actual.keybindingItem.command, id); assert.equal(actual.keybindingItem.commandLabel, 'some title'); @@ -207,7 +207,7 @@ suite('KeybindingsEditorModel test', () => { registerCommandWithTitle(id, 'some title'); prepareKeybindingService(); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('workbench action view size').filter(element => element.keybindingItem.command === id)[0]; assert.ok(actual); }); @@ -217,7 +217,7 @@ suite('KeybindingsEditorModel test', () => { registerCommandWithTitle(id, 'Increase view size'); prepareKeybindingService(); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('increase size').filter(element => element.keybindingItem.command === id)[0]; assert.ok(actual); }); @@ -227,7 +227,7 @@ suite('KeybindingsEditorModel test', () => { const expected = aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape }, when: 'context1 && context2' }); prepareKeybindingService(expected); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('default').filter(element => element.keybindingItem.command === command)[0]; assert.ok(actual); }); @@ -237,7 +237,7 @@ suite('KeybindingsEditorModel test', () => { const expected = aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape }, when: 'context1 && context2', isDefault: false }); prepareKeybindingService(expected); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('user').filter(element => element.keybindingItem.command === command)[0]; assert.ok(actual); }); @@ -247,7 +247,7 @@ suite('KeybindingsEditorModel test', () => { const expected = aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape }, when: 'context1 && context2', isDefault: true }); prepareKeybindingService(expected); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('@source: default').filter(element => element.keybindingItem.command === command)[0]; assert.ok(actual); }); @@ -257,7 +257,7 @@ suite('KeybindingsEditorModel test', () => { const expected = aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape }, when: 'context1 && context2', isDefault: false }); prepareKeybindingService(expected); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('@source: user').filter(element => element.keybindingItem.command === command)[0]; assert.ok(actual); }); @@ -267,7 +267,7 @@ suite('KeybindingsEditorModel test', () => { const expected = aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape }, when: 'whenContext1 && whenContext2', isDefault: false }); prepareKeybindingService(expected); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('when context').filter(element => element.keybindingItem.command === command)[0]; assert.ok(actual); }); @@ -279,7 +279,7 @@ suite('KeybindingsEditorModel test', () => { const expected = aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { metaKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false }); prepareKeybindingService(expected); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('cmd').filter(element => element.keybindingItem.command === command); assert.equal(1, actual.length); assert.deepEqual(actual[0].keybindingMatches!.firstPart, { metaKey: true }); @@ -293,7 +293,7 @@ suite('KeybindingsEditorModel test', () => { const expected = aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { metaKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false }); prepareKeybindingService(expected, aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { shiftKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false })); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('meta').filter(element => element.keybindingItem.command === command); assert.equal(1, actual.length); assert.deepEqual(actual[0].keybindingMatches!.firstPart, { metaKey: true }); @@ -307,7 +307,7 @@ suite('KeybindingsEditorModel test', () => { const expected = aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { metaKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false }); prepareKeybindingService(expected, aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { altKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false })); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('command').filter(element => element.keybindingItem.command === command); assert.equal(1, actual.length); assert.deepEqual(actual[0].keybindingMatches!.firstPart, { metaKey: true }); @@ -321,7 +321,7 @@ suite('KeybindingsEditorModel test', () => { const expected = aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { metaKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false }); prepareKeybindingService(expected, aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { ctrlKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false })); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('windows').filter(element => element.keybindingItem.command === command); assert.equal(1, actual.length); assert.deepEqual(actual[0].keybindingMatches!.firstPart, { metaKey: true }); @@ -333,7 +333,7 @@ suite('KeybindingsEditorModel test', () => { const expected = aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { altKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false }); prepareKeybindingService(expected, aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { metaKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false })); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('alt').filter(element => element.keybindingItem.command === command); assert.equal(1, actual.length); assert.deepEqual(actual[0].keybindingMatches!.firstPart, { altKey: true }); @@ -345,7 +345,7 @@ suite('KeybindingsEditorModel test', () => { const expected = aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { altKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false }); prepareKeybindingService(expected, aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { metaKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false })); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('option').filter(element => element.keybindingItem.command === command); assert.equal(1, actual.length); assert.deepEqual(actual[0].keybindingMatches!.firstPart, { altKey: true }); @@ -357,7 +357,7 @@ suite('KeybindingsEditorModel test', () => { const expected = aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { ctrlKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false }); prepareKeybindingService(expected, aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { shiftKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false })); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('ctrl').filter(element => element.keybindingItem.command === command); assert.equal(1, actual.length); assert.deepEqual(actual[0].keybindingMatches!.firstPart, { ctrlKey: true }); @@ -369,7 +369,7 @@ suite('KeybindingsEditorModel test', () => { const expected = aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { ctrlKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false }); prepareKeybindingService(expected, aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { metaKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false })); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('control').filter(element => element.keybindingItem.command === command); assert.equal(1, actual.length); assert.deepEqual(actual[0].keybindingMatches!.firstPart, { ctrlKey: true }); @@ -381,7 +381,7 @@ suite('KeybindingsEditorModel test', () => { const expected = aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { shiftKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false }); prepareKeybindingService(expected, aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { metaKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false })); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('shift').filter(element => element.keybindingItem.command === command); assert.equal(1, actual.length); assert.deepEqual(actual[0].keybindingMatches!.firstPart, { shiftKey: true }); @@ -393,7 +393,7 @@ suite('KeybindingsEditorModel test', () => { const expected = aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.RightArrow, modifiers: { shiftKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false }); prepareKeybindingService(expected, aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { metaKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false })); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('arrow').filter(element => element.keybindingItem.command === command); assert.equal(1, actual.length); assert.deepEqual(actual[0].keybindingMatches!.firstPart, { keyCode: true }); @@ -405,7 +405,7 @@ suite('KeybindingsEditorModel test', () => { const expected = aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.RightArrow, modifiers: { altKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false }); prepareKeybindingService(expected, aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.RightArrow, modifiers: { metaKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false })); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('alt right').filter(element => element.keybindingItem.command === command); assert.equal(1, actual.length); assert.deepEqual(actual[0].keybindingMatches!.firstPart, { altKey: true, keyCode: true }); @@ -417,7 +417,7 @@ suite('KeybindingsEditorModel test', () => { const expected = aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.RightArrow, modifiers: { altKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false }); prepareKeybindingService(expected, aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.RightArrow, modifiers: { metaKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false })); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('right alt').filter(element => element.keybindingItem.command === command); assert.equal(0, actual.length); }); @@ -428,7 +428,7 @@ suite('KeybindingsEditorModel test', () => { const expected = aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { altKey: true, metaKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false }); prepareKeybindingService(expected, aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { metaKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false })); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('alt cmd esc').filter(element => element.keybindingItem.command === command); assert.equal(1, actual.length); assert.deepEqual(actual[0].keybindingMatches!.firstPart, { altKey: true, metaKey: true, keyCode: true }); @@ -441,7 +441,7 @@ suite('KeybindingsEditorModel test', () => { const expected = aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { shiftKey: true, metaKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false }); prepareKeybindingService(expected, aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { metaKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false })); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('cmd shift esc').filter(element => element.keybindingItem.command === command); assert.equal(1, actual.length); assert.deepEqual(actual[0].keybindingMatches!.firstPart, { metaKey: true, shiftKey: true, keyCode: true }); @@ -454,7 +454,7 @@ suite('KeybindingsEditorModel test', () => { const expected = aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { shiftKey: true, metaKey: true } }, chordPart: { keyCode: KeyCode.Delete }, when: 'whenContext1 && whenContext2', isDefault: false }); prepareKeybindingService(expected, aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { metaKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false })); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('cmd shift esc').filter(element => element.keybindingItem.command === command); assert.equal(1, actual.length); assert.deepEqual(actual[0].keybindingMatches!.firstPart, { metaKey: true, shiftKey: true, keyCode: true }); @@ -467,7 +467,7 @@ suite('KeybindingsEditorModel test', () => { const expected = aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { shiftKey: true, metaKey: true } }, chordPart: { keyCode: KeyCode.Delete }, when: 'whenContext1 && whenContext2', isDefault: false }); prepareKeybindingService(expected, aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { metaKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false })); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('cmd del').filter(element => element.keybindingItem.command === command); assert.equal(1, actual.length); assert.deepEqual(actual[0].keybindingMatches!.firstPart, { metaKey: true }); @@ -480,7 +480,7 @@ suite('KeybindingsEditorModel test', () => { const expected = aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { shiftKey: true, metaKey: true } }, chordPart: { keyCode: KeyCode.Delete }, when: 'whenContext1 && whenContext2', isDefault: false }); prepareKeybindingService(expected, aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { shiftKey: true, metaKey: true } }, chordPart: { keyCode: KeyCode.UpArrow }, when: 'whenContext1 && whenContext2', isDefault: false })); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('cmd shift esc del').filter(element => element.keybindingItem.command === command); assert.equal(1, actual.length); assert.deepEqual(actual[0].keybindingMatches!.firstPart, { shiftKey: true, metaKey: true, keyCode: true }); @@ -492,7 +492,7 @@ suite('KeybindingsEditorModel test', () => { const expected = aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.KEY_C, modifiers: { ctrlKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false }); prepareKeybindingService(expected, aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { shiftKey: true, metaKey: true } }, chordPart: { keyCode: KeyCode.KEY_C, modifiers: { ctrlKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false })); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('"ctrl c"').filter(element => element.keybindingItem.command === command); assert.equal(1, actual.length); assert.deepEqual(actual[0].keybindingMatches!.firstPart, { ctrlKey: true, keyCode: true }); @@ -504,7 +504,7 @@ suite('KeybindingsEditorModel test', () => { const expected = aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { shiftKey: true, metaKey: true } }, chordPart: { keyCode: KeyCode.KEY_C, modifiers: { ctrlKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false }); prepareKeybindingService(expected, aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.KEY_C, modifiers: { ctrlKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false })); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('"shift meta escape ctrl c"').filter(element => element.keybindingItem.command === command); assert.equal(1, actual.length); assert.deepEqual(actual[0].keybindingMatches!.firstPart, { shiftKey: true, metaKey: true, keyCode: true }); @@ -517,7 +517,7 @@ suite('KeybindingsEditorModel test', () => { const expected = aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { shiftKey: true, metaKey: true } }, chordPart: { keyCode: KeyCode.Delete, modifiers: { metaKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false }); prepareKeybindingService(expected, aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { shiftKey: true, metaKey: true } }, chordPart: { keyCode: KeyCode.UpArrow }, when: 'whenContext1 && whenContext2', isDefault: false })); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('"cmd shift esc del"').filter(element => element.keybindingItem.command === command); assert.equal(0, actual.length); }); @@ -527,7 +527,7 @@ suite('KeybindingsEditorModel test', () => { const expected = aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.KEY_C, modifiers: { ctrlKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false }); prepareKeybindingService(expected, aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { shiftKey: true, metaKey: true } }, chordPart: { keyCode: KeyCode.KEY_C, modifiers: { ctrlKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false })); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('"control+c"').filter(element => element.keybindingItem.command === command); assert.equal(1, actual.length); assert.deepEqual(actual[0].keybindingMatches!.firstPart, { ctrlKey: true, keyCode: true }); @@ -539,7 +539,7 @@ suite('KeybindingsEditorModel test', () => { const expected = aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Escape, modifiers: { shiftKey: true, metaKey: true } }, chordPart: { keyCode: KeyCode.KEY_C, modifiers: { ctrlKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false }); prepareKeybindingService(expected, aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.KEY_C, modifiers: { ctrlKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false })); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('"shift+meta+escape ctrl+c"').filter(element => element.keybindingItem.command === command); assert.equal(1, actual.length); assert.deepEqual(actual[0].keybindingMatches!.firstPart, { shiftKey: true, metaKey: true, keyCode: true }); @@ -551,7 +551,7 @@ suite('KeybindingsEditorModel test', () => { const expected = aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Space, modifiers: { ctrlKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false }); prepareKeybindingService(expected, aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.Backspace, modifiers: { ctrlKey: true } }, when: 'whenContext1 && whenContext2', isDefault: false })); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('"ctrl+space"').filter(element => element.keybindingItem.command === command); assert.equal(1, actual.length); }); @@ -562,7 +562,7 @@ suite('KeybindingsEditorModel test', () => { const expected = aResolvedKeybindingItem({ command, firstPart: { keyCode: KeyCode.DownArrow } }); prepareKeybindingService(expected, aResolvedKeybindingItem({ command: 'down', firstPart: { keyCode: KeyCode.Escape } })); - await testObject.resolve({}); + await testObject.resolve(new Map()); const actual = testObject.fetch('"down"').filter(element => element.keybindingItem.command === command); assert.equal(1, actual.length); assert.deepEqual(actual[0].keybindingMatches!.firstPart, { keyCode: true }); @@ -617,7 +617,7 @@ suite('KeybindingsEditorModel test', () => { parts.push(aSimpleKeybinding(chordPart)); } } - let keybinding = parts.length > 0 ? new USLayoutResolvedKeybinding(new ChordKeybinding(parts), OS) : null; + const keybinding = parts.length > 0 ? new USLayoutResolvedKeybinding(new ChordKeybinding(parts), OS) : undefined; return new ResolvedKeybindingItem(keybinding, command || 'some command', null, when ? ContextKeyExpr.deserialize(when) : undefined, isDefault === undefined ? true : isDefault); } diff --git a/src/vs/workbench/services/progress/browser/editorProgressService.ts b/src/vs/workbench/services/progress/browser/editorProgressService.ts new file mode 100644 index 000000000..7ea3daae1 --- /dev/null +++ b/src/vs/workbench/services/progress/browser/editorProgressService.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. + *--------------------------------------------------------------------------------------------*/ + +import { IEditorProgressService } from 'vs/platform/progress/common/progress'; +import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { ProgressBarIndicator } from 'vs/workbench/services/progress/browser/progressIndicator'; + +export class EditorProgressService extends ProgressBarIndicator { + + _serviceBrand: ServiceIdentifier; +} diff --git a/src/vs/workbench/services/progress/browser/media/progressService.css b/src/vs/workbench/services/progress/browser/media/progressService.css new file mode 100644 index 000000000..e9d6a1574 --- /dev/null +++ b/src/vs/workbench/services/progress/browser/media/progressService.css @@ -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. + *--------------------------------------------------------------------------------------------*/ + +.monaco-workbench .part.statusbar > .items-container > .statusbar-item.progress { + padding-left: 5px; +} + +.monaco-workbench .part.statusbar > .items-container > .statusbar-item.progress .spinner-container { + padding-right: 5px; +} + +.monaco-workbench .progress-badge > .badge-content { + background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNCIgaGVpZ2h0PSIxNCIgdmlld0JveD0iMiAyIDE0IDE0IiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDIgMiAxNCAxNCI+PHBhdGggZmlsbD0iI2ZmZiIgZD0iTTkgMTZjLTMuODYgMC03LTMuMTQtNy03czMuMTQtNyA3LTdjMy44NTkgMCA3IDMuMTQxIDcgN3MtMy4xNDEgNy03IDd6bTAtMTIuNmMtMy4wODggMC01LjYgMi41MTMtNS42IDUuNnMyLjUxMiA1LjYgNS42IDUuNiA1LjYtMi41MTIgNS42LTUuNi0yLjUxMi01LjYtNS42LTUuNnptMy44NiA3LjFsLTMuMTYtMS44OTZ2LTMuODA0aC0xLjR2NC41OTZsMy44NCAyLjMwNS43Mi0xLjIwMXoiLz48L3N2Zz4="); + background-position: center center; + background-repeat: no-repeat; +} diff --git a/src/vs/workbench/services/progress/browser/media/progressService2.css b/src/vs/workbench/services/progress/browser/media/progressService2.css deleted file mode 100644 index 850fdf2e3..000000000 --- a/src/vs/workbench/services/progress/browser/media/progressService2.css +++ /dev/null @@ -1,18 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -.monaco-workbench .part.statusbar > .statusbar-item.progress { - padding-left: 5px; -} - -.monaco-workbench .part.statusbar > .statusbar-item.progress .spinner-container { - padding-right: 5px; -} - -.monaco-workbench .progress-badge > .badge-content { - background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNCIgaGVpZ2h0PSIxNCIgdmlld0JveD0iMiAyIDE0IDE0IiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDIgMiAxNCAxNCI+PHBhdGggZmlsbD0iI2ZmZiIgZD0iTTkgMTZjLTMuODYgMC03LTMuMTQtNy03czMuMTQtNyA3LTdjMy44NTkgMCA3IDMuMTQxIDcgN3MtMy4xNDEgNy03IDd6bTAtMTIuNmMtMy4wODggMC01LjYgMi41MTMtNS42IDUuNnMyLjUxMiA1LjYgNS42IDUuNiA1LjYtMi41MTIgNS42LTUuNi0yLjUxMi01LjYtNS42LTUuNnptMy44NiA3LjFsLTMuMTYtMS44OTZ2LTMuODA0aC0xLjR2NC41OTZsMy44NCAyLjMwNS43Mi0xLjIwMXoiLz48L3N2Zz4="); - background-position: center center; - background-repeat: no-repeat; -} diff --git a/src/vs/workbench/services/progress/browser/progressIndicator.ts b/src/vs/workbench/services/progress/browser/progressIndicator.ts new file mode 100644 index 000000000..1d11c084f --- /dev/null +++ b/src/vs/workbench/services/progress/browser/progressIndicator.ts @@ -0,0 +1,300 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Disposable } from 'vs/base/common/lifecycle'; +import { isUndefinedOrNull } from 'vs/base/common/types'; +import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar'; +import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; +import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; +import { IProgressRunner, IProgressIndicator } from 'vs/platform/progress/common/progress'; + +export class ProgressBarIndicator implements IProgressIndicator { + + constructor(private progressbar: ProgressBar) { } + + show(infinite: true, delay?: number): IProgressRunner; + show(total: number, delay?: number): IProgressRunner; + show(infiniteOrTotal: true | number, delay?: number): IProgressRunner { + if (typeof infiniteOrTotal === 'boolean') { + this.progressbar.infinite().show(delay); + } else { + this.progressbar.total(infiniteOrTotal).show(delay); + } + + return { + total: (total: number) => { + this.progressbar.total(total); + }, + + worked: (worked: number) => { + if (this.progressbar.hasTotal()) { + this.progressbar.worked(worked); + } else { + this.progressbar.infinite().show(); + } + }, + + done: () => { + this.progressbar.stop().hide(); + } + }; + } + + async showWhile(promise: Promise, delay?: number): Promise { + try { + this.progressbar.infinite().show(delay); + + await promise; + } catch (error) { + // ignore + } finally { + this.progressbar.stop().hide(); + } + } +} + +namespace ProgressIndicatorState { + + export const enum Type { + None, + Done, + Infinite, + While, + Work + } + + export const None = new class { readonly type = Type.None; }; + export const Done = new class { readonly type = Type.Done; }; + export const Infinite = new class { readonly type = Type.Infinite; }; + + export class While { + readonly type = Type.While; + + constructor( + readonly whilePromise: Promise, + readonly whileStart: number, + readonly whileDelay: number, + ) { } + } + + export class Work { + readonly type = Type.Work; + + constructor( + readonly total: number | undefined, + readonly worked: number | undefined + ) { } + } + + export type State = + typeof None + | typeof Done + | typeof Infinite + | While + | Work; +} + +export abstract class CompositeScope extends Disposable { + + constructor( + private viewletService: IViewletService, + private panelService: IPanelService, + private scopeId: string + ) { + super(); + + this.registerListeners(); + } + + registerListeners(): void { + this._register(this.viewletService.onDidViewletOpen(viewlet => this.onScopeOpened(viewlet.getId()))); + this._register(this.panelService.onDidPanelOpen(({ panel }) => this.onScopeOpened(panel.getId()))); + + this._register(this.viewletService.onDidViewletClose(viewlet => this.onScopeClosed(viewlet.getId()))); + this._register(this.panelService.onDidPanelClose(panel => this.onScopeClosed(panel.getId()))); + } + + private onScopeClosed(scopeId: string) { + if (scopeId === this.scopeId) { + this.onScopeDeactivated(); + } + } + + private onScopeOpened(scopeId: string) { + if (scopeId === this.scopeId) { + this.onScopeActivated(); + } + } + + abstract onScopeActivated(): void; + + abstract onScopeDeactivated(): void; +} + +export class CompositeProgressIndicator extends CompositeScope implements IProgressIndicator { + private isActive: boolean; + private progressbar: ProgressBar; + private progressState: ProgressIndicatorState.State = ProgressIndicatorState.None; + + constructor( + progressbar: ProgressBar, + scopeId: string, + isActive: boolean, + @IViewletService viewletService: IViewletService, + @IPanelService panelService: IPanelService + ) { + super(viewletService, panelService, scopeId); + + this.progressbar = progressbar; + this.isActive = isActive || isUndefinedOrNull(scopeId); // If service is unscoped, enable by default + } + + onScopeDeactivated(): void { + this.isActive = false; + } + + onScopeActivated(): void { + this.isActive = true; + + // Return early if progress state indicates that progress is done + if (this.progressState.type === ProgressIndicatorState.Done.type) { + return; + } + + // Replay Infinite Progress from Promise + if (this.progressState.type === ProgressIndicatorState.Type.While) { + let delay: number | undefined; + 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 + else if (this.progressState.type === ProgressIndicatorState.Type.Infinite) { + this.progressbar.infinite().show(); + } + + // Replay Finite Progress (Total & Worked) + else if (this.progressState.type === ProgressIndicatorState.Type.Work) { + if (this.progressState.total) { + this.progressbar.total(this.progressState.total).show(); + } + + if (this.progressState.worked) { + this.progressbar.worked(this.progressState.worked).show(); + } + } + } + + show(infinite: true, delay?: number): IProgressRunner; + show(total: number, delay?: number): IProgressRunner; + show(infiniteOrTotal: true | number, delay?: number): IProgressRunner { + + // Sort out Arguments + if (typeof infiniteOrTotal === 'boolean') { + this.progressState = ProgressIndicatorState.Infinite; + } else { + this.progressState = new ProgressIndicatorState.Work(infiniteOrTotal, undefined); + } + + // Active: Show Progress + if (this.isActive) { + + // Infinite: Start Progressbar and Show after Delay + if (this.progressState.type === ProgressIndicatorState.Type.Infinite) { + this.progressbar.infinite().show(delay); + } + + // Finite: Start Progressbar and Show after Delay + else if (this.progressState.type === ProgressIndicatorState.Type.Work && typeof this.progressState.total === 'number') { + this.progressbar.total(this.progressState.total).show(delay); + } + } + + return { + total: (total: number) => { + this.progressState = new ProgressIndicatorState.Work( + total, + this.progressState.type === ProgressIndicatorState.Type.Work ? this.progressState.worked : undefined); + + if (this.isActive) { + this.progressbar.total(total); + } + }, + + worked: (worked: number) => { + + // Verify first that we are either not active or the progressbar has a total set + if (!this.isActive || this.progressbar.hasTotal()) { + this.progressState = new ProgressIndicatorState.Work( + this.progressState.type === ProgressIndicatorState.Type.Work ? this.progressState.total : undefined, + this.progressState.type === ProgressIndicatorState.Type.Work && typeof this.progressState.worked === 'number' ? this.progressState.worked + worked : worked); + + if (this.isActive) { + this.progressbar.worked(worked); + } + } + + // Otherwise the progress bar does not support worked(), we fallback to infinite() progress + else { + this.progressState = ProgressIndicatorState.Infinite; + this.progressbar.infinite().show(); + } + }, + + done: () => { + this.progressState = ProgressIndicatorState.Done; + + if (this.isActive) { + this.progressbar.stop().hide(); + } + } + }; + } + + async showWhile(promise: Promise, delay?: number): Promise { + + // Join with existing running promise to ensure progress is accurate + if (this.progressState.type === ProgressIndicatorState.Type.While) { + promise = Promise.all([promise, this.progressState.whilePromise]); + } + + // Keep Promise in State + this.progressState = new ProgressIndicatorState.While(promise, delay || 0, Date.now()); + + try { + this.doShowWhile(delay); + + await promise; + } catch (error) { + // ignore + } finally { + + // If this is not the last promise in the list of joined promises, skip this + if (this.progressState.type !== ProgressIndicatorState.Type.While || this.progressState.whilePromise === promise) { + + // The while promise is either null or equal the promise we last hooked on + this.progressState = ProgressIndicatorState.None; + + if (this.isActive) { + this.progressbar.stop().hide(); + } + } + } + } + + private doShowWhile(delay?: number): void { + + // Show Progress when active + if (this.isActive) { + this.progressbar.infinite().show(delay); + } + } +} diff --git a/src/vs/workbench/services/progress/browser/progressService.ts b/src/vs/workbench/services/progress/browser/progressService.ts index b3d3a5179..d7bb38745 100644 --- a/src/vs/workbench/services/progress/browser/progressService.ts +++ b/src/vs/workbench/services/progress/browser/progressService.ts @@ -3,290 +3,381 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Disposable } from 'vs/base/common/lifecycle'; -import * as types from 'vs/base/common/types'; -import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar'; +import 'vs/css!./media/progressService'; + +import { localize } from 'vs/nls'; +import { IDisposable, dispose, DisposableStore, MutableDisposable, Disposable } from 'vs/base/common/lifecycle'; +import { IProgressService, IProgressOptions, IProgressStep, ProgressLocation, IProgress, Progress, IProgressCompositeOptions, IProgressNotificationOptions, IProgressRunner, IProgressIndicator } from 'vs/platform/progress/common/progress'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; +import { StatusbarAlignment, IStatusbarService } from 'vs/platform/statusbar/common/statusbar'; +import { timeout } from 'vs/base/common/async'; +import { ProgressBadge, IActivityService } from 'vs/workbench/services/activity/common/activity'; +import { INotificationService, Severity, INotificationHandle, INotificationActions } from 'vs/platform/notification/common/notification'; +import { Action } from 'vs/base/common/actions'; +import { Event } from 'vs/base/common/event'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; +import { Dialog } from 'vs/base/browser/ui/dialog/dialog'; +import { attachDialogStyler } from 'vs/platform/theme/common/styler'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; +import { EventHelper } from 'vs/base/browser/dom'; +import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; -import { IProgressService, IProgressRunner } from 'vs/platform/progress/common/progress'; +export class ProgressService extends Disposable implements IProgressService { -namespace ProgressState { - export const enum Type { - None, - Done, - Infinite, - While, - Work - } + _serviceBrand: ServiceIdentifier; - export const None = new class { readonly type = Type.None; }; - export const Done = new class { readonly type = Type.Done; }; - export const Infinite = new class { readonly type = Type.Infinite; }; - - export class While { - public readonly type = Type.While; - constructor( - public readonly whilePromise: Promise, - public readonly whileStart: number, - public readonly whileDelay: number, - ) { } - } - - export class Work { - public readonly type = Type.Work; - constructor( - public readonly total: number | undefined, - public readonly worked: number | undefined - ) { } - } + private readonly stack: [IProgressOptions, Progress][] = []; + private readonly globalStatusEntry = this._register(new MutableDisposable()); - export type State = - typeof None - | typeof Done - | typeof Infinite - | While - | Work; -} - -export abstract class ScopedService extends Disposable { - - constructor(private viewletService: IViewletService, private panelService: IPanelService, private scopeId: string) { + constructor( + @IActivityService private readonly activityService: IActivityService, + @IViewletService private readonly viewletService: IViewletService, + @IPanelService private readonly panelService: IPanelService, + @INotificationService private readonly notificationService: INotificationService, + @IStatusbarService private readonly statusbarService: IStatusbarService, + @ILayoutService private readonly layoutService: ILayoutService, + @IThemeService private readonly themeService: IThemeService, + @IKeybindingService private readonly keybindingService: IKeybindingService + ) { super(); - - this.registerListeners(); } - registerListeners(): void { - this._register(this.viewletService.onDidViewletOpen(viewlet => this.onScopeOpened(viewlet.getId()))); - this._register(this.panelService.onDidPanelOpen(({ panel }) => this.onScopeOpened(panel.getId()))); + withProgress(options: IProgressOptions, task: (progress: IProgress) => Promise, onDidCancel?: () => void): Promise { + const { location } = options; + if (typeof location === 'string') { + if (this.viewletService.getProgressIndicator(location)) { + return this.withViewletProgress(location, task, { ...options, location }); + } - this._register(this.viewletService.onDidViewletClose(viewlet => this.onScopeClosed(viewlet.getId()))); - this._register(this.panelService.onDidPanelClose(panel => this.onScopeClosed(panel.getId()))); - } + if (this.panelService.getProgressIndicator(location)) { + return this.withPanelProgress(location, task, { ...options, location }); + } - private onScopeClosed(scopeId: string) { - if (scopeId === this.scopeId) { - this.onScopeDeactivated(); + return Promise.reject(new Error(`Bad progress location: ${location}`)); } - } - private onScopeOpened(scopeId: string) { - if (scopeId === this.scopeId) { - this.onScopeActivated(); + switch (location) { + case ProgressLocation.Notification: + return this.withNotificationProgress({ ...options, location }, task, onDidCancel); + case ProgressLocation.Window: + return this.withWindowProgress(options, task); + case ProgressLocation.Explorer: + return this.withViewletProgress('workbench.view.explorer', task, { ...options, location }); + case ProgressLocation.Scm: + return this.withViewletProgress('workbench.view.scm', task, { ...options, location }); + case ProgressLocation.Extensions: + return this.withViewletProgress('workbench.view.extensions', task, { ...options, location }); + case ProgressLocation.Dialog: + return this.withDialogProgress(options, task, onDidCancel); + default: + return Promise.reject(new Error(`Bad progress location: ${location}`)); } } - abstract onScopeActivated(): void; + private withWindowProgress(options: IProgressOptions, callback: (progress: IProgress<{ message?: string }>) => Promise): Promise { + const task: [IProgressOptions, Progress] = [options, new Progress(() => this.updateWindowProgress())]; + + const promise = callback(task[1]); + + let delayHandle: any = setTimeout(() => { + delayHandle = undefined; + this.stack.unshift(task); + this.updateWindowProgress(); + + // show progress for at least 150ms + Promise.all([ + timeout(150), + promise + ]).finally(() => { + const idx = this.stack.indexOf(task); + this.stack.splice(idx, 1); + this.updateWindowProgress(); + }); + }, 150); + + // cancel delay if promise finishes below 150ms + return promise.finally(() => clearTimeout(delayHandle)); + } - abstract onScopeDeactivated(): void; -} + private updateWindowProgress(idx: number = 0) { + this.globalStatusEntry.clear(); -export class ScopedProgressService extends ScopedService implements IProgressService { - _serviceBrand: any; - private isActive: boolean; - private progressbar: ProgressBar; - private progressState: ProgressState.State = ProgressState.None; + if (idx < this.stack.length) { + const [options, progress] = this.stack[idx]; - constructor( - progressbar: ProgressBar, - scopeId: string, - isActive: boolean, - @IViewletService viewletService: IViewletService, - @IPanelService panelService: IPanelService - ) { - super(viewletService, panelService, scopeId); + let progressTitle = options.title; + let progressMessage = progress.value && progress.value.message; + let text: string; + let title: string; - this.progressbar = progressbar; - this.isActive = isActive || types.isUndefinedOrNull(scopeId); // If service is unscoped, enable by default - } + if (progressTitle && progressMessage) { + // : <message> + text = localize('progress.text2', "{0}: {1}", progressTitle, progressMessage); + title = options.source ? localize('progress.title3', "[{0}] {1}: {2}", options.source, progressTitle, progressMessage) : text; - onScopeDeactivated(): void { - this.isActive = false; - } + } else if (progressTitle) { + // <title> + text = progressTitle; + title = options.source ? localize('progress.title2', "[{0}]: {1}", options.source, progressTitle) : text; - onScopeActivated(): void { - this.isActive = true; - - // Return early if progress state indicates that progress is done - if (this.progressState.type === ProgressState.Done.type) { - return; - } + } else if (progressMessage) { + // <message> + text = progressMessage; + title = options.source ? localize('progress.title2', "[{0}]: {1}", options.source, progressMessage) : text; - // Replay Infinite Progress from Promise - if (this.progressState.type === ProgressState.Type.While) { - let delay: number | undefined; - if (this.progressState.whileDelay > 0) { - const remainingDelay = this.progressState.whileDelay - (Date.now() - this.progressState.whileStart); - if (remainingDelay > 0) { - delay = remainingDelay; - } + } else { + // no title, no message -> no progress. try with next on stack + this.updateWindowProgress(idx + 1); + return; } - this.doShowWhile(delay); + this.globalStatusEntry.value = this.statusbarService.addEntry({ + text: `$(sync~spin) ${text}`, + tooltip: title + }, 'status.progress', localize('status.progress', "Progress Message"), StatusbarAlignment.LEFT); } + } - // Replay Infinite Progress - else if (this.progressState.type === ProgressState.Type.Infinite) { - this.progressbar.infinite().show(); - } + private withNotificationProgress<P extends Promise<R>, R = unknown>(options: IProgressNotificationOptions, callback: (progress: IProgress<{ message?: string, increment?: number }>) => P, onDidCancel?: () => void): P { + const toDispose = new DisposableStore(); - // Replay Finite Progress (Total & Worked) - else if (this.progressState.type === ProgressState.Type.Work) { - if (this.progressState.total) { - this.progressbar.total(this.progressState.total).show(); + const createNotification = (message: string | undefined, increment?: number): INotificationHandle | undefined => { + if (!message) { + return undefined; // we need a message at least } - if (this.progressState.worked) { - this.progressbar.worked(this.progressState.worked).show(); - } - } - } + const primaryActions = options.primaryActions ? Array.from(options.primaryActions) : []; + const secondaryActions = options.secondaryActions ? Array.from(options.secondaryActions) : []; + if (options.cancellable) { + const cancelAction = new class extends Action { + constructor() { + super('progress.cancel', localize('cancel', "Cancel"), undefined, true); + } - show(infinite: true, delay?: number): IProgressRunner; - show(total: number, delay?: number): IProgressRunner; - show(infiniteOrTotal: true | number, delay?: number): IProgressRunner { - // Sort out Arguments - if (typeof infiniteOrTotal === 'boolean') { - this.progressState = ProgressState.Infinite; - } else { - this.progressState = new ProgressState.Work(infiniteOrTotal, undefined); - } + run(): Promise<any> { + if (typeof onDidCancel === 'function') { + onDidCancel(); + } - // Active: Show Progress - if (this.isActive) { + return Promise.resolve(undefined); + } + }; + toDispose.add(cancelAction); - // Infinite: Start Progressbar and Show after Delay - if (this.progressState.type === ProgressState.Type.Infinite) { - this.progressbar.infinite().show(delay); + primaryActions.push(cancelAction); } - // Finite: Start Progressbar and Show after Delay - else if (this.progressState.type === ProgressState.Type.Work && typeof this.progressState.total === 'number') { - this.progressbar.total(this.progressState.total).show(delay); - } - } + const actions: INotificationActions = { primary: primaryActions, secondary: secondaryActions }; + const handle = this.notificationService.notify({ + severity: Severity.Info, + message, + source: options.source, + actions + }); - return { - total: (total: number) => { - this.progressState = new ProgressState.Work( - total, - this.progressState.type === ProgressState.Type.Work ? this.progressState.worked : undefined); + updateProgress(handle, increment); - if (this.isActive) { - this.progressbar.total(total); - } - }, + Event.once(handle.onDidClose)(() => { + toDispose.dispose(); + }); - worked: (worked: number) => { + return handle; + }; - // Verify first that we are either not active or the progressbar has a total set - if (!this.isActive || this.progressbar.hasTotal()) { - this.progressState = new ProgressState.Work( - this.progressState.type === ProgressState.Type.Work ? this.progressState.total : undefined, - this.progressState.type === ProgressState.Type.Work && typeof this.progressState.worked === 'number' ? this.progressState.worked + worked : worked); + const updateProgress = (notification: INotificationHandle, increment?: number): void => { + if (typeof increment === 'number' && increment >= 0) { + notification.progress.total(100); // always percentage based + notification.progress.worked(increment); + } else { + notification.progress.infinite(); + } + }; - if (this.isActive) { - this.progressbar.worked(worked); + let handle: INotificationHandle | undefined; + const updateNotification = (message?: string, increment?: number): void => { + if (!handle) { + handle = createNotification(message, increment); + } else { + if (typeof message === 'string') { + let newMessage: string; + if (typeof options.title === 'string') { + newMessage = `${options.title}: ${message}`; // always prefix with overall title if we have it (https://github.com/Microsoft/vscode/issues/50932) + } else { + newMessage = message; } - } - // Otherwise the progress bar does not support worked(), we fallback to infinite() progress - else { - this.progressState = ProgressState.Infinite; - this.progressbar.infinite().show(); + handle.updateMessage(newMessage); } - }, - done: () => { - this.progressState = ProgressState.Done; - - if (this.isActive) { - this.progressbar.stop().hide(); + if (typeof increment === 'number') { + updateProgress(handle, increment); } } }; - } - - showWhile(promise: Promise<any>, delay?: number): Promise<void> { - // Join with existing running promise to ensure progress is accurate - if (this.progressState.type === ProgressState.Type.While) { - promise = Promise.all([promise, this.progressState.whilePromise]); - } - // Keep Promise in State - this.progressState = new ProgressState.While(promise, delay || 0, Date.now()); + // Show initially + updateNotification(options.title); - let stop = () => { + // Update based on progress + const promise = callback({ + report: progress => { + updateNotification(progress.message, progress.increment); + } + }); - // If this is not the last promise in the list of joined promises, return early - if (this.progressState.type === ProgressState.Type.While && this.progressState.whilePromise !== promise) { - return; + // Show progress for at least 800ms and then hide once done or canceled + Promise.all([timeout(800), promise]).finally(() => { + if (handle) { + handle.close(); } + }); - // The while promise is either null or equal the promise we last hooked on - this.progressState = ProgressState.None; + return promise; + } - if (this.isActive) { - this.progressbar.stop().hide(); - } - }; + private withViewletProgress<P extends Promise<R>, R = unknown>(viewletId: string, task: (progress: IProgress<IProgressStep>) => P, options: IProgressCompositeOptions): P { + + // show in viewlet + const promise = this.withCompositeProgress(this.viewletService.getProgressIndicator(viewletId), task, options); + + // show activity bar + let activityProgress: IDisposable; + let delayHandle: any = setTimeout(() => { + delayHandle = undefined; + + const handle = this.activityService.showActivity( + viewletId, + new ProgressBadge(() => ''), + 'progress-badge', + 100 + ); + + 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(); + } + } + }; + }, options.delay || 300); - this.doShowWhile(delay); + promise.finally(() => { + clearTimeout(delayHandle); + dispose(activityProgress); + }); - return promise.then(stop, stop); + return promise; } - private doShowWhile(delay?: number): void { + private withPanelProgress<P extends Promise<R>, R = unknown>(panelid: string, task: (progress: IProgress<IProgressStep>) => P, options: IProgressCompositeOptions): P { - // Show Progress when active - if (this.isActive) { - this.progressbar.infinite().show(delay); - } + // show in panel + return this.withCompositeProgress(this.panelService.getProgressIndicator(panelid), task, options); } -} -export class ProgressService implements IProgressService { + private withCompositeProgress<P extends Promise<R>, R = unknown>(progressIndicator: IProgressIndicator | null, task: (progress: IProgress<IProgressStep>) => P, options: IProgressCompositeOptions): P { + let progressRunner: IProgressRunner | undefined = undefined; - _serviceBrand: any; + const promise = task({ + report: progress => { + if (!progressRunner) { + return; + } - constructor(private progressbar: ProgressBar) { } + if (typeof progress.increment === 'number') { + progressRunner.worked(progress.increment); + } - show(infinite: true, delay?: number): IProgressRunner; - show(total: number, delay?: number): IProgressRunner; - show(infiniteOrTotal: true | number, delay?: number): IProgressRunner { - if (typeof infiniteOrTotal === 'boolean') { - this.progressbar.infinite().show(delay); - } else { - this.progressbar.total(infiniteOrTotal).show(delay); + if (typeof progress.total === 'number') { + progressRunner.total(progress.total); + } + } + }); + + if (progressIndicator) { + if (typeof options.total === 'number') { + progressRunner = progressIndicator.show(options.total, options.delay); + promise.catch(() => undefined /* ignore */).finally(() => progressRunner ? progressRunner.done() : undefined); + } else { + progressIndicator.showWhile(promise, options.delay); + } } - return { - total: (total: number) => { - this.progressbar.total(total); - }, + return promise; + } - worked: (worked: number) => { - if (this.progressbar.hasTotal()) { - this.progressbar.worked(worked); - } else { - this.progressbar.infinite().show(); + private withDialogProgress<P extends Promise<R>, R = unknown>(options: IProgressOptions, task: (progress: IProgress<IProgressStep>) => P, onDidCancel?: () => void): P { + const disposables = new DisposableStore(); + const allowableCommands = [ + 'workbench.action.quit', + 'workbench.action.reloadWindow' + ]; + + let dialog: Dialog; + + const createDialog = (message: string) => { + dialog = new Dialog( + this.layoutService.container, + message, + [options.cancellable ? localize('cancel', "Cancel") : localize('dismiss', "Dismiss")], + { + type: 'pending', + keyEventProcessor: (event: StandardKeyboardEvent) => { + const resolved = this.keybindingService.softDispatch(event, this.layoutService.container); + if (resolved && resolved.commandId) { + if (allowableCommands.indexOf(resolved.commandId) === -1) { + EventHelper.stop(event, true); + } + } + } } - }, + ); - done: () => { - this.progressbar.stop().hide(); - } + disposables.add(dialog); + disposables.add(attachDialogStyler(dialog, this.themeService)); + + dialog.show().then(() => { + if (typeof onDidCancel === 'function') { + onDidCancel(); + } + + dispose(dialog); + }); + + return dialog; }; - } - showWhile(promise: Promise<any>, delay?: number): Promise<void> { - const stop = () => { - this.progressbar.stop().hide(); + const updateDialog = (message?: string) => { + if (message && !dialog) { + dialog = createDialog(message); + } else if (message) { + dialog.updateMessage(message); + } }; - this.progressbar.infinite().show(delay); + const promise = task({ + report: progress => { + updateDialog(progress.message); + } + }); + + promise.finally(() => { + dispose(disposables); + }); - return promise.then(stop, stop); + return promise; } } + +registerSingleton(IProgressService, ProgressService, true); diff --git a/src/vs/workbench/services/progress/browser/progressService2.ts b/src/vs/workbench/services/progress/browser/progressService2.ts deleted file mode 100644 index d2e4eee12..000000000 --- a/src/vs/workbench/services/progress/browser/progressService2.ts +++ /dev/null @@ -1,344 +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 'vs/css!./media/progressService2'; - -import { localize } from 'vs/nls'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { IProgressService2, IProgressOptions, IProgressStep, ProgressLocation, IProgress, emptyProgress, Progress, IProgressNotificationOptions } from 'vs/platform/progress/common/progress'; -import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; -import { StatusbarAlignment, IStatusbarService } from 'vs/platform/statusbar/common/statusbar'; -import { timeout } from 'vs/base/common/async'; -import { ProgressBadge, IActivityService } from 'vs/workbench/services/activity/common/activity'; -import { INotificationService, Severity, INotificationHandle, INotificationActions } from 'vs/platform/notification/common/notification'; -import { Action } from 'vs/base/common/actions'; -import { Event } from 'vs/base/common/event'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; -import { Dialog } from 'vs/base/browser/ui/dialog/dialog'; -import { attachDialogStyler } from 'vs/platform/theme/common/styler'; -import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import { EventHelper } from 'vs/base/browser/dom'; - -export class ProgressService2 implements IProgressService2 { - - _serviceBrand: any; - - private readonly _stack: [IProgressOptions, Progress<IProgressStep>][] = []; - private _globalStatusEntry: IDisposable; - - constructor( - @IActivityService private readonly _activityBar: IActivityService, - @IViewletService private readonly _viewletService: IViewletService, - @INotificationService private readonly _notificationService: INotificationService, - @IStatusbarService private readonly _statusbarService: IStatusbarService, - @ILayoutService private readonly _layoutService: ILayoutService, - @IThemeService private readonly _themeService: IThemeService, - @IKeybindingService private readonly _keybindingService: IKeybindingService - ) { } - - withProgress<R = unknown>(options: IProgressOptions, task: (progress: IProgress<IProgressStep>) => Promise<R>, onDidCancel?: () => void): Promise<R> { - - const { location } = options; - if (typeof location === 'string') { - const viewlet = this._viewletService.getViewlet(location); - if (viewlet) { - return this._withViewletProgress(location, task); - } - return Promise.reject(new Error(`Bad progress location: ${location}`)); - } - - switch (location) { - case ProgressLocation.Notification: - return this._withNotificationProgress({ ...options, location: ProgressLocation.Notification }, task, onDidCancel); - case ProgressLocation.Window: - return this._withWindowProgress(options, task); - case ProgressLocation.Explorer: - return this._withViewletProgress('workbench.view.explorer', task); - case ProgressLocation.Scm: - return this._withViewletProgress('workbench.view.scm', task); - case ProgressLocation.Extensions: - return this._withViewletProgress('workbench.view.extensions', task); - case ProgressLocation.Dialog: - return this._withDialogProgress(options, task, onDidCancel); - default: - return Promise.reject(new Error(`Bad progress location: ${location}`)); - } - } - - private _withWindowProgress<R = unknown>(options: IProgressOptions, callback: (progress: IProgress<{ message?: string }>) => Promise<R>): Promise<R> { - - const task: [IProgressOptions, Progress<IProgressStep>] = [options, new Progress<IProgressStep>(() => this._updateWindowProgress())]; - - const promise = callback(task[1]); - - let delayHandle: any = setTimeout(() => { - delayHandle = undefined; - this._stack.unshift(task); - this._updateWindowProgress(); - - // show progress for at least 150ms - Promise.all([ - timeout(150), - promise - ]).finally(() => { - const idx = this._stack.indexOf(task); - this._stack.splice(idx, 1); - this._updateWindowProgress(); - }); - - }, 150); - - // cancel delay if promise finishes below 150ms - return promise.finally(() => clearTimeout(delayHandle)); - } - - private _updateWindowProgress(idx: number = 0) { - - dispose(this._globalStatusEntry); - - if (idx < this._stack.length) { - - const [options, progress] = this._stack[idx]; - - let progressTitle = options.title; - let progressMessage = progress.value && progress.value.message; - let text: string; - let title: string; - - if (progressTitle && progressMessage) { - // <title>: <message> - text = localize('progress.text2', "{0}: {1}", progressTitle, progressMessage); - title = options.source ? localize('progress.title3', "[{0}] {1}: {2}", options.source, progressTitle, progressMessage) : text; - - } else if (progressTitle) { - // <title> - text = progressTitle; - title = options.source ? localize('progress.title2', "[{0}]: {1}", options.source, progressTitle) : text; - - } else if (progressMessage) { - // <message> - text = progressMessage; - title = options.source ? localize('progress.title2', "[{0}]: {1}", options.source, progressMessage) : text; - - } else { - // no title, no message -> no progress. try with next on stack - this._updateWindowProgress(idx + 1); - return; - } - - this._globalStatusEntry = this._statusbarService.addEntry({ - text: `$(sync~spin) ${text}`, - tooltip: title - }, StatusbarAlignment.LEFT); - } - } - - private _withNotificationProgress<P extends Promise<R>, R = unknown>(options: IProgressNotificationOptions, callback: (progress: IProgress<{ message?: string, increment?: number }>) => P, onDidCancel?: () => void): P { - const toDispose: IDisposable[] = []; - - const createNotification = (message: string | undefined, increment?: number): INotificationHandle | undefined => { - if (!message) { - return undefined; // we need a message at least - } - - const actions: INotificationActions = { primary: options.primaryActions || [], secondary: options.secondaryActions || [] }; - if (options.cancellable) { - const cancelAction = new class extends Action { - constructor() { - super('progress.cancel', localize('cancel', "Cancel"), undefined, true); - } - - run(): Promise<any> { - if (typeof onDidCancel === 'function') { - onDidCancel(); - } - - return Promise.resolve(undefined); - } - }; - toDispose.push(cancelAction); - - actions.primary!.push(cancelAction); - } - - const handle = this._notificationService.notify({ - severity: Severity.Info, - message, - source: options.source, - actions - }); - - updateProgress(handle, increment); - - Event.once(handle.onDidClose)(() => { - dispose(toDispose); - }); - - return handle; - }; - - const updateProgress = (notification: INotificationHandle, increment?: number): void => { - if (typeof increment === 'number' && increment >= 0) { - notification.progress.total(100); // always percentage based - notification.progress.worked(increment); - } else { - notification.progress.infinite(); - } - }; - - let handle: INotificationHandle | undefined; - const updateNotification = (message?: string, increment?: number): void => { - if (!handle) { - handle = createNotification(message, increment); - } else { - if (typeof message === 'string') { - let newMessage: string; - if (typeof options.title === 'string') { - newMessage = `${options.title}: ${message}`; // always prefix with overall title if we have it (https://github.com/Microsoft/vscode/issues/50932) - } else { - newMessage = message; - } - - handle.updateMessage(newMessage); - } - - if (typeof increment === 'number') { - updateProgress(handle, increment); - } - } - }; - - // Show initially - updateNotification(options.title); - - // Update based on progress - const p = callback({ - report: progress => { - updateNotification(progress.message, progress.increment); - } - }); - - // Show progress for at least 800ms and then hide once done or canceled - Promise.all([timeout(800), p]).finally(() => { - if (handle) { - handle.close(); - } - }); - - return p; - } - - private _withViewletProgress<P extends Promise<R>, R = unknown>(viewletId: string, task: (progress: IProgress<{ message?: string }>) => P): P { - - const promise = task(emptyProgress); - - // show in viewlet - const viewletProgress = this._viewletService.getProgressIndicator(viewletId); - if (viewletProgress) { - viewletProgress.showWhile(promise); - } - - // show activity bar - let activityProgress: IDisposable; - let delayHandle: any = setTimeout(() => { - delayHandle = undefined; - const handle = this._activityBar.showActivity( - viewletId, - new ProgressBadge(() => ''), - 'progress-badge', - 100 - ); - 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); - - const onDone = () => { - clearTimeout(delayHandle); - dispose(activityProgress); - }; - - promise.then(onDone, onDone); - return promise; - } - - private _withDialogProgress<P extends Promise<R>, R = unknown>(options: IProgressOptions, task: (progress: IProgress<{ message?: string, increment?: number }>) => P, onDidCancel?: () => void): P { - const disposables: IDisposable[] = []; - const allowableCommands = [ - 'workbench.action.quit', - 'workbench.action.reloadWindow' - ]; - - let dialog: Dialog; - - const createDialog = (message: string) => { - dialog = new Dialog( - this._layoutService.container, - message, - [options.cancellable ? localize('cancel', "Cancel") : localize('dismiss', "Dismiss")], - { - type: 'pending', - keyEventProcessor: (event: StandardKeyboardEvent) => { - const resolved = this._keybindingService.softDispatch(event, this._layoutService.container); - if (resolved && resolved.commandId) { - if (allowableCommands.indexOf(resolved.commandId) === -1) { - EventHelper.stop(event, true); - } - } - } - } - ); - - disposables.push(dialog); - disposables.push(attachDialogStyler(dialog, this._themeService)); - - dialog.show().then(() => { - if (typeof onDidCancel === 'function') { - onDidCancel(); - } - - dispose(dialog); - }); - - return dialog; - }; - - const updateDialog = (message?: string) => { - if (message && !dialog) { - dialog = createDialog(message); - } else if (message) { - dialog.updateMessage(message); - } - }; - - const p = task({ - report: progress => { - updateDialog(progress.message); - } - }); - - p.finally(() => { - dispose(disposables); - }); - - return p; - } -} - -registerSingleton(IProgressService2, ProgressService2, true); diff --git a/src/vs/workbench/services/progress/test/progressIndicator.test.ts b/src/vs/workbench/services/progress/test/progressIndicator.test.ts new file mode 100644 index 000000000..a8d2b740d --- /dev/null +++ b/src/vs/workbench/services/progress/test/progressIndicator.test.ts @@ -0,0 +1,167 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { IAction, IActionViewItem } from 'vs/base/common/actions'; +import { IEditorControl } from 'vs/workbench/common/editor'; +import { CompositeScope, CompositeProgressIndicator } from 'vs/workbench/services/progress/browser/progressIndicator'; +import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; +import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; +import { IViewlet } from 'vs/workbench/common/viewlet'; +import { TestViewletService, TestPanelService } from 'vs/workbench/test/workbenchTestServices'; + +class TestViewlet implements IViewlet { + + constructor(private id: string) { } + + getId(): string { return this.id; } + getTitle(): string { return this.id; } + getActions(): IAction[] { return []; } + getSecondaryActions(): IAction[] { return []; } + getContextMenuActions(): IAction[] { return []; } + getActionViewItem(action: IAction): IActionViewItem { return null!; } + getControl(): IEditorControl { return null!; } + focus(): void { } + getOptimalWidth(): number { return 10; } +} + +class TestCompositeScope extends CompositeScope { + isActive: boolean; + + constructor(viewletService: IViewletService, panelService: IPanelService, scopeId: string) { + super(viewletService, panelService, scopeId); + } + + onScopeActivated() { this.isActive = true; } + onScopeDeactivated() { this.isActive = false; } +} + +class TestProgressBar { + fTotal: number; + fWorked: number; + fInfinite: boolean; + fDone: boolean; + + constructor() { } + + infinite() { + this.fDone = null!; + this.fInfinite = true; + + return this; + } + + total(total: number) { + this.fDone = null!; + this.fTotal = total; + + return this; + } + + hasTotal() { + return !!this.fTotal; + } + + worked(worked: number) { + this.fDone = null!; + + if (this.fWorked) { + this.fWorked += worked; + } else { + this.fWorked = worked; + } + + return this; + } + + done() { + this.fDone = true; + + this.fInfinite = null!; + this.fWorked = null!; + this.fTotal = null!; + + return this; + } + + stop() { + return this.done(); + } + + show(): void { } + + hide(): void { } +} + +suite('Progress Indicator', () => { + + test('CompositeScope', () => { + let viewletService = new TestViewletService(); + let panelService = new TestPanelService(); + let service = new TestCompositeScope(viewletService, panelService, 'test.scopeId'); + const testViewlet = new TestViewlet('test.scopeId'); + + assert(!service.isActive); + viewletService.onDidViewletOpenEmitter.fire(testViewlet); + assert(service.isActive); + + viewletService.onDidViewletCloseEmitter.fire(testViewlet); + assert(!service.isActive); + + }); + + test('CompositeProgressIndicator', async () => { + let testProgressBar = new TestProgressBar(); + let viewletService = new TestViewletService(); + let panelService = new TestPanelService(); + let service = new CompositeProgressIndicator((<any>testProgressBar), 'test.scopeId', true, viewletService, panelService); + + // Active: Show (Infinite) + let fn = service.show(true); + assert.strictEqual(true, testProgressBar.fInfinite); + fn.done(); + assert.strictEqual(true, testProgressBar.fDone); + + // Active: Show (Total / Worked) + fn = service.show(100); + assert.strictEqual(false, !!testProgressBar.fInfinite); + assert.strictEqual(100, testProgressBar.fTotal); + fn.worked(20); + assert.strictEqual(20, testProgressBar.fWorked); + fn.total(80); + assert.strictEqual(80, testProgressBar.fTotal); + fn.done(); + assert.strictEqual(true, testProgressBar.fDone); + + // Inactive: Show (Infinite) + const testViewlet = new TestViewlet('test.scopeId'); + viewletService.onDidViewletCloseEmitter.fire(testViewlet); + service.show(true); + assert.strictEqual(false, !!testProgressBar.fInfinite); + viewletService.onDidViewletOpenEmitter.fire(testViewlet); + assert.strictEqual(true, testProgressBar.fInfinite); + + // Inactive: Show (Total / Worked) + viewletService.onDidViewletCloseEmitter.fire(testViewlet); + fn = service.show(100); + fn.total(80); + fn.worked(20); + assert.strictEqual(false, !!testProgressBar.fTotal); + viewletService.onDidViewletOpenEmitter.fire(testViewlet); + assert.strictEqual(20, testProgressBar.fWorked); + assert.strictEqual(80, testProgressBar.fTotal); + + // Acive: Show While + let p = Promise.resolve(null); + await service.showWhile(p); + assert.strictEqual(true, testProgressBar.fDone); + viewletService.onDidViewletCloseEmitter.fire(testViewlet); + p = Promise.resolve(null); + await service.showWhile(p); + assert.strictEqual(true, testProgressBar.fDone); + viewletService.onDidViewletOpenEmitter.fire(testViewlet); + assert.strictEqual(true, testProgressBar.fDone); + }); +}); diff --git a/src/vs/workbench/services/progress/test/progressService.test.ts b/src/vs/workbench/services/progress/test/progressService.test.ts deleted file mode 100644 index 58ac7214e..000000000 --- a/src/vs/workbench/services/progress/test/progressService.test.ts +++ /dev/null @@ -1,222 +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 { IAction, IActionItem } from 'vs/base/common/actions'; -import { IEditorControl } from 'vs/workbench/common/editor'; -import { ScopedProgressService, ScopedService } from 'vs/workbench/services/progress/browser/progressService'; -import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; -import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; -import { IViewlet } from 'vs/workbench/common/viewlet'; -import { TestViewletService, TestPanelService } from 'vs/workbench/test/workbenchTestServices'; - -class TestViewlet implements IViewlet { - - constructor(private id: string) { } - - getId(): string { - return this.id; - } - - /** - * Returns the name of this composite to show in the title area. - */ - getTitle(): string { - return this.id; - } - - /** - * Returns the primary actions of the composite. - */ - getActions(): IAction[] { - return []; - } - - /** - * Returns the secondary actions of the composite. - */ - getSecondaryActions(): IAction[] { - return []; - } - - /** - * Returns an array of actions to show in the context menu of the composite - */ - public getContextMenuActions(): IAction[] { - return []; - } - - /** - * Returns the action item for a specific action. - */ - getActionItem(action: IAction): IActionItem { - return null!; - } - - /** - * Returns the underlying control of this composite. - */ - getControl(): IEditorControl { - return null!; - } - - /** - * Asks the underlying control to focus. - */ - focus(): void { - } - - getOptimalWidth(): number { - return 10; - } -} - -class TestScopedService extends ScopedService { - public isActive: boolean; - - constructor(viewletService: IViewletService, panelService: IPanelService, scopeId: string) { - super(viewletService, panelService, scopeId); - } - public onScopeActivated() { - this.isActive = true; - } - - public onScopeDeactivated() { - this.isActive = false; - } -} - -class TestProgressBar { - public fTotal: number; - public fWorked: number; - public fInfinite: boolean; - public fDone: boolean; - - constructor() { - } - - public infinite() { - this.fDone = null!; - this.fInfinite = true; - - return this; - } - - public total(total: number) { - this.fDone = null!; - this.fTotal = total; - - return this; - } - - public hasTotal() { - return !!this.fTotal; - } - - public worked(worked: number) { - this.fDone = null!; - - if (this.fWorked) { - this.fWorked += worked; - } else { - this.fWorked = worked; - } - - return this; - } - - public done() { - this.fDone = true; - - this.fInfinite = null!; - this.fWorked = null!; - this.fTotal = null!; - - return this; - } - - public stop() { - return this.done(); - } - - public show(): void { - - } - - public hide(): void { - - } -} - -suite('Progress Service', () => { - - test('ScopedService', () => { - let viewletService = new TestViewletService(); - let panelService = new TestPanelService(); - let service = new TestScopedService(viewletService, panelService, 'test.scopeId'); - const testViewlet = new TestViewlet('test.scopeId'); - - assert(!service.isActive); - viewletService.onDidViewletOpenEmitter.fire(testViewlet); - assert(service.isActive); - - viewletService.onDidViewletCloseEmitter.fire(testViewlet); - assert(!service.isActive); - - }); - - test('WorkbenchProgressService', async () => { - let testProgressBar = new TestProgressBar(); - let viewletService = new TestViewletService(); - let panelService = new TestPanelService(); - let service = new ScopedProgressService((<any>testProgressBar), 'test.scopeId', true, viewletService, panelService); - - // Active: Show (Infinite) - let fn = service.show(true); - assert.strictEqual(true, testProgressBar.fInfinite); - fn.done(); - assert.strictEqual(true, testProgressBar.fDone); - - // Active: Show (Total / Worked) - fn = service.show(100); - assert.strictEqual(false, !!testProgressBar.fInfinite); - assert.strictEqual(100, testProgressBar.fTotal); - fn.worked(20); - assert.strictEqual(20, testProgressBar.fWorked); - fn.total(80); - assert.strictEqual(80, testProgressBar.fTotal); - fn.done(); - assert.strictEqual(true, testProgressBar.fDone); - - // Inactive: Show (Infinite) - const testViewlet = new TestViewlet('test.scopeId'); - viewletService.onDidViewletCloseEmitter.fire(testViewlet); - service.show(true); - assert.strictEqual(false, !!testProgressBar.fInfinite); - viewletService.onDidViewletOpenEmitter.fire(testViewlet); - assert.strictEqual(true, testProgressBar.fInfinite); - - // Inactive: Show (Total / Worked) - viewletService.onDidViewletCloseEmitter.fire(testViewlet); - fn = service.show(100); - fn.total(80); - fn.worked(20); - assert.strictEqual(false, !!testProgressBar.fTotal); - viewletService.onDidViewletOpenEmitter.fire(testViewlet); - assert.strictEqual(20, testProgressBar.fWorked); - assert.strictEqual(80, testProgressBar.fTotal); - - // Acive: Show While - let p = Promise.resolve(null); - await service.showWhile(p); - assert.strictEqual(true, testProgressBar.fDone); - viewletService.onDidViewletCloseEmitter.fire(testViewlet); - p = Promise.resolve(null); - await service.showWhile(p); - assert.strictEqual(true, testProgressBar.fDone); - viewletService.onDidViewletOpenEmitter.fire(testViewlet); - assert.strictEqual(true, testProgressBar.fDone); - }); -}); diff --git a/src/vs/workbench/services/remote/browser/remoteAgentServiceImpl.ts b/src/vs/workbench/services/remote/browser/remoteAgentServiceImpl.ts index c2e838965..4219ca539 100644 --- a/src/vs/workbench/services/remote/browser/remoteAgentServiceImpl.ts +++ b/src/vs/workbench/services/remote/browser/remoteAgentServiceImpl.ts @@ -3,23 +3,35 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { IRemoteAgentConnection } from 'vs/workbench/services/remote/common/remoteAgentService'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { IRemoteAgentConnection, IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; -import { AbstractRemoteAgentService } from 'vs/workbench/services/remote/common/abstractRemoteAgentService'; +import { AbstractRemoteAgentService, RemoteAgentConnection } from 'vs/workbench/services/remote/common/abstractRemoteAgentService'; import { IProductService } from 'vs/platform/product/common/product'; +import { IWebSocketFactory, BrowserSocketFactory } from 'vs/platform/remote/browser/browserSocketFactory'; +import { ISignService } from 'vs/platform/sign/common/sign'; +import { ISocketFactory } from 'vs/platform/remote/common/remoteAgentConnection'; -export class RemoteAgentService extends AbstractRemoteAgentService { +export class RemoteAgentService extends AbstractRemoteAgentService implements IRemoteAgentService { + + public readonly socketFactory: ISocketFactory; + + private readonly _connection: IRemoteAgentConnection | null = null; constructor( - @IEnvironmentService environmentService: IEnvironmentService, + webSocketFactory: IWebSocketFactory | null | undefined, + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, @IProductService productService: IProductService, - @IRemoteAuthorityResolverService remoteAuthorityResolverService: IRemoteAuthorityResolverService + @IRemoteAuthorityResolverService remoteAuthorityResolverService: IRemoteAuthorityResolverService, + @ISignService signService: ISignService ) { super(environmentService); + + this.socketFactory = new BrowserSocketFactory(webSocketFactory); + this._connection = this._register(new RemoteAgentConnection(environmentService.configuration.remoteAuthority!, productService.commit, this.socketFactory, environmentService, remoteAuthorityResolverService, signService)); } getConnection(): IRemoteAgentConnection | null { - return null; + return this._connection; } } diff --git a/src/vs/workbench/services/remote/common/abstractRemoteAgentService.ts b/src/vs/workbench/services/remote/common/abstractRemoteAgentService.ts index 79b10c15b..e48834a6a 100644 --- a/src/vs/workbench/services/remote/common/abstractRemoteAgentService.ts +++ b/src/vs/workbench/services/remote/common/abstractRemoteAgentService.ts @@ -8,7 +8,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { IChannel, IServerChannel, getDelayedChannel } from 'vs/base/parts/ipc/common/ipc'; import { Client } from 'vs/base/parts/ipc/common/ipc.net'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { connectRemoteAgentManagement, IConnectionOptions, IWebSocketFactory, PersistenConnectionEvent } from 'vs/platform/remote/common/remoteAgentConnection'; +import { connectRemoteAgentManagement, IConnectionOptions, ISocketFactory, PersistenConnectionEvent } from 'vs/platform/remote/common/remoteAgentConnection'; import { IRemoteAgentConnection, IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { IRemoteAuthorityResolverService, RemoteAuthorityResolverError } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; @@ -19,8 +19,9 @@ import { RemoteExtensionEnvironmentChannelClient } from 'vs/workbench/services/r import { INotificationService } from 'vs/platform/notification/common/notification'; import { IDiagnosticInfoOptions, IDiagnosticInfo } from 'vs/platform/diagnostics/common/diagnosticsService'; import { Emitter } from 'vs/base/common/event'; +import { ISignService } from 'vs/platform/sign/common/sign'; -export abstract class AbstractRemoteAgentService extends Disposable implements IRemoteAgentService { +export abstract class AbstractRemoteAgentService extends Disposable { _serviceBrand: any; @@ -82,9 +83,10 @@ export class RemoteAgentConnection extends Disposable implements IRemoteAgentCon constructor( remoteAuthority: string, private readonly _commit: string | undefined, - private readonly _webSocketFactory: IWebSocketFactory, + private readonly _socketFactory: ISocketFactory, private readonly _environmentService: IEnvironmentService, - private readonly _remoteAuthorityResolverService: IRemoteAuthorityResolverService + private readonly _remoteAuthorityResolverService: IRemoteAuthorityResolverService, + private readonly _signService: ISignService ) { super(); this.remoteAuthority = remoteAuthority; @@ -111,7 +113,7 @@ export class RemoteAgentConnection extends Disposable implements IRemoteAgentCon const options: IConnectionOptions = { isBuilt: this._environmentService.isBuilt, commit: this._commit, - webSocketFactory: this._webSocketFactory, + socketFactory: this._socketFactory, addressProvider: { getAddress: async () => { if (firstCall) { @@ -119,10 +121,11 @@ export class RemoteAgentConnection extends Disposable implements IRemoteAgentCon } else { this._onReconnecting.fire(undefined); } - const { host, port } = await this._remoteAuthorityResolverService.resolveAuthority(this.remoteAuthority); - return { host, port }; + const { authority } = await this._remoteAuthorityResolverService.resolveAuthority(this.remoteAuthority); + return { host: authority.host, port: authority.port }; } - } + }, + signService: this._signService }; const connection = this._register(await connectRemoteAgentManagement(options, this.remoteAuthority, `renderer`)); this._register(connection.onDidStateChange(e => this._onDidStateChange.fire(e))); diff --git a/src/vs/workbench/services/remote/common/remoteAgentEnvironmentChannel.ts b/src/vs/workbench/services/remote/common/remoteAgentEnvironmentChannel.ts index 09a5f3403..ae87e384b 100644 --- a/src/vs/workbench/services/remote/common/remoteAgentEnvironmentChannel.ts +++ b/src/vs/workbench/services/remote/common/remoteAgentEnvironmentChannel.ts @@ -34,28 +34,28 @@ export class RemoteExtensionEnvironmentChannelClient { constructor(private channel: IChannel) { } - getEnvironmentData(remoteAuthority: string, extensionDevelopmentPath?: URI[]): Promise<IRemoteAgentEnvironment> { + async getEnvironmentData(remoteAuthority: string, extensionDevelopmentPath?: URI[]): Promise<IRemoteAgentEnvironment> { const args: IGetEnvironmentDataArguments = { language: platform.language, remoteAuthority, extensionDevelopmentPath }; - return this.channel.call<IRemoteAgentEnvironmentDTO>('getEnvironmentData', args) - .then((data: IRemoteAgentEnvironmentDTO): IRemoteAgentEnvironment => { - return { - pid: data.pid, - appRoot: URI.revive(data.appRoot), - appSettingsHome: URI.revive(data.appSettingsHome), - settingsPath: URI.revive(data.settingsPath), - logsPath: URI.revive(data.logsPath), - extensionsPath: URI.revive(data.extensionsPath), - extensionHostLogsPath: URI.revive(data.extensionHostLogsPath), - globalStorageHome: URI.revive(data.globalStorageHome), - userHome: URI.revive(data.userHome), - extensions: data.extensions.map(ext => { (<any>ext).extensionLocation = URI.revive(ext.extensionLocation); return ext; }), - os: data.os - }; - }); + + const data = await this.channel.call<IRemoteAgentEnvironmentDTO>('getEnvironmentData', args); + + return { + pid: data.pid, + appRoot: URI.revive(data.appRoot), + appSettingsHome: URI.revive(data.appSettingsHome), + settingsPath: URI.revive(data.settingsPath), + logsPath: URI.revive(data.logsPath), + extensionsPath: URI.revive(data.extensionsPath), + extensionHostLogsPath: URI.revive(data.extensionHostLogsPath), + globalStorageHome: URI.revive(data.globalStorageHome), + userHome: URI.revive(data.userHome), + extensions: data.extensions.map(ext => { (<any>ext).extensionLocation = URI.revive(ext.extensionLocation); return ext; }), + os: data.os + }; } getDiagnosticInfo(options: IDiagnosticInfoOptions): Promise<IDiagnosticInfo> { diff --git a/src/vs/workbench/services/remote/common/remoteAgentService.ts b/src/vs/workbench/services/remote/common/remoteAgentService.ts index 6fd204af0..bc4d49641 100644 --- a/src/vs/workbench/services/remote/common/remoteAgentService.ts +++ b/src/vs/workbench/services/remote/common/remoteAgentService.ts @@ -8,7 +8,7 @@ import { RemoteAgentConnectionContext, IRemoteAgentEnvironment } from 'vs/platfo import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; import { IDiagnosticInfoOptions, IDiagnosticInfo } from 'vs/platform/diagnostics/common/diagnosticsService'; import { Event } from 'vs/base/common/event'; -import { PersistenConnectionEvent } from 'vs/platform/remote/common/remoteAgentConnection'; +import { PersistenConnectionEvent as PersistentConnectionEvent, ISocketFactory } from 'vs/platform/remote/common/remoteAgentConnection'; export const RemoteExtensionLogFileName = 'remoteagent'; @@ -17,6 +17,8 @@ export const IRemoteAgentService = createDecorator<IRemoteAgentService>('remoteA export interface IRemoteAgentService { _serviceBrand: any; + readonly socketFactory: ISocketFactory; + getConnection(): IRemoteAgentConnection | null; getEnvironment(bail?: boolean): Promise<IRemoteAgentEnvironment | null>; getDiagnosticInfo(options: IDiagnosticInfoOptions): Promise<IDiagnosticInfo | undefined>; @@ -27,7 +29,7 @@ export interface IRemoteAgentConnection { readonly remoteAuthority: string; readonly onReconnecting: Event<void>; - readonly onDidStateChange: Event<PersistenConnectionEvent>; + readonly onDidStateChange: Event<PersistentConnectionEvent>; getChannel<T extends IChannel>(channelName: string): T; registerChannel<T extends IServerChannel<RemoteAgentConnectionContext>>(channelName: string, channel: T): void; diff --git a/src/vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl.ts b/src/vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl.ts index 4415f1cf1..538fb1be8 100644 --- a/src/vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl.ts +++ b/src/vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl.ts @@ -5,23 +5,29 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; -import { IRemoteAgentConnection } from 'vs/workbench/services/remote/common/remoteAgentService'; +import { IRemoteAgentConnection, IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; import product from 'vs/platform/product/node/product'; -import { nodeWebSocketFactory } from 'vs/platform/remote/node/nodeWebSocketFactory'; +import { nodeSocketFactory } from 'vs/platform/remote/node/nodeSocketFactory'; import { AbstractRemoteAgentService, RemoteAgentConnection } from 'vs/workbench/services/remote/common/abstractRemoteAgentService'; +import { ISignService } from 'vs/platform/sign/common/sign'; +import { ISocketFactory } from 'vs/platform/remote/common/remoteAgentConnection'; -export class RemoteAgentService extends AbstractRemoteAgentService { +export class RemoteAgentService extends AbstractRemoteAgentService implements IRemoteAgentService { + + public readonly socketFactory: ISocketFactory; private readonly _connection: IRemoteAgentConnection | null = null; constructor({ remoteAuthority }: IWindowConfiguration, @IEnvironmentService environmentService: IEnvironmentService, - @IRemoteAuthorityResolverService remoteAuthorityResolverService: IRemoteAuthorityResolverService + @IRemoteAuthorityResolverService remoteAuthorityResolverService: IRemoteAuthorityResolverService, + @ISignService signService: ISignService ) { super(environmentService); + this.socketFactory = nodeSocketFactory; if (remoteAuthority) { - this._connection = this._register(new RemoteAgentConnection(remoteAuthority, product.commit, nodeWebSocketFactory, environmentService, remoteAuthorityResolverService)); + this._connection = this._register(new RemoteAgentConnection(remoteAuthority, product.commit, nodeSocketFactory, environmentService, remoteAuthorityResolverService, signService)); } } diff --git a/src/vs/workbench/services/remote/node/tunnelService.ts b/src/vs/workbench/services/remote/node/tunnelService.ts index 498b12773..9a359e44c 100644 --- a/src/vs/workbench/services/remote/node/tunnelService.ts +++ b/src/vs/workbench/services/remote/node/tunnelService.ts @@ -3,16 +3,114 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import * as net from 'net'; +import { Barrier } from 'vs/base/common/async'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { NodeSocket } from 'vs/base/parts/ipc/node/ipc.net'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import product from 'vs/platform/product/node/product'; +import { connectRemoteAgentTunnel, IConnectionOptions } from 'vs/platform/remote/common/remoteAgentConnection'; +import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { ITunnelService, RemoteTunnel } from 'vs/platform/remote/common/tunnel'; +import { nodeSocketFactory } from 'vs/platform/remote/node/nodeSocketFactory'; +import { ISignService } from 'vs/platform/sign/common/sign'; + +export async function createRemoteTunnel(options: IConnectionOptions, tunnelRemotePort: number): Promise<RemoteTunnel> { + const tunnel = new NodeRemoteTunnel(options, tunnelRemotePort); + return tunnel.waitForReady(); +} + +class NodeRemoteTunnel extends Disposable implements RemoteTunnel { + + public readonly tunnelRemotePort: number; + public readonly tunnelLocalPort: number; + + private readonly _options: IConnectionOptions; + private readonly _server: net.Server; + private readonly _barrier: Barrier; + + private readonly _listeningListener: () => void; + private readonly _connectionListener: (socket: net.Socket) => void; + + constructor(options: IConnectionOptions, tunnelRemotePort: number) { + super(); + this._options = options; + this._server = net.createServer(); + this._barrier = new Barrier(); + + this._listeningListener = () => this._barrier.open(); + this._server.on('listening', this._listeningListener); + + this._connectionListener = (socket) => this._onConnection(socket); + this._server.on('connection', this._connectionListener); + + this.tunnelRemotePort = tunnelRemotePort; + this.tunnelLocalPort = (<net.AddressInfo>this._server.listen(0).address()).port; + } + + public dispose(): void { + super.dispose(); + this._server.removeListener('listening', this._listeningListener); + this._server.removeListener('connection', this._connectionListener); + this._server.close(); + } + + public async waitForReady(): Promise<this> { + await this._barrier.wait(); + return this; + } + + private async _onConnection(localSocket: net.Socket): Promise<void> { + // pause reading on the socket until we have a chance to forward its data + localSocket.pause(); + + const protocol = await connectRemoteAgentTunnel(this._options, this.tunnelRemotePort); + const remoteSocket = (<NodeSocket>protocol.getSocket()).socket; + const dataChunk = protocol.readEntireBuffer(); + protocol.dispose(); + + if (dataChunk.byteLength > 0) { + localSocket.write(dataChunk.buffer); + } + + localSocket.on('end', () => remoteSocket.end()); + localSocket.on('close', () => remoteSocket.end()); + remoteSocket.on('end', () => localSocket.end()); + remoteSocket.on('close', () => localSocket.end()); + + localSocket.pipe(remoteSocket); + remoteSocket.pipe(localSocket); + } +} export class TunnelService implements ITunnelService { _serviceBrand: any; public constructor( + @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, + @IRemoteAuthorityResolverService private readonly remoteAuthorityResolverService: IRemoteAuthorityResolverService, + @ISignService private readonly signService: ISignService ) { } openTunnel(remotePort: number): Promise<RemoteTunnel> | undefined { - return undefined; + const remoteAuthority = this.environmentService.configuration.remoteAuthority; + if (!remoteAuthority) { + return undefined; + } + + const options: IConnectionOptions = { + isBuilt: this.environmentService.isBuilt, + commit: product.commit, + socketFactory: nodeSocketFactory, + addressProvider: { + getAddress: async () => { + const { authority } = await this.remoteAuthorityResolverService.resolveAuthority(remoteAuthority); + return { host: authority.host, port: authority.port }; + } + }, + signService: this.signService + }; + return createRemoteTunnel(options, remotePort); } } diff --git a/src/vs/workbench/services/request/browser/requestService.ts b/src/vs/workbench/services/request/browser/requestService.ts new file mode 100644 index 000000000..dca97347c --- /dev/null +++ b/src/vs/workbench/services/request/browser/requestService.ts @@ -0,0 +1,48 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IRequestOptions, IRequestContext } from 'vs/platform/request/common/request'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { ILogService } from 'vs/platform/log/common/log'; +import { RequestChannelClient } from 'vs/platform/request/common/requestIpc'; +import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; +import { RequestService as BrowserRequestService } from 'vs/platform/request/browser/requestService'; + +export class RequestService extends BrowserRequestService { + + private readonly remoteRequestChannel: RequestChannelClient | null; + + constructor( + private readonly requestHandler: ((options: IRequestOptions) => Promise<IRequestContext>) | undefined, + @IRemoteAgentService remoteAgentService: IRemoteAgentService, + @IConfigurationService configurationService: IConfigurationService, + @ILogService logService: ILogService + ) { + super(configurationService, logService); + const connection = remoteAgentService.getConnection(); + this.remoteRequestChannel = connection ? new RequestChannelClient(connection.getChannel('request')) : null; + } + + async request(options: IRequestOptions, token: CancellationToken): Promise<IRequestContext> { + if (this.requestHandler) { + return this.requestHandler(options); + } + try { + const context = await super.request(options, token); + if (this.remoteRequestChannel && context.res.statusCode === 405) { + return this.remoteRequestChannel.request(options, token); + } + return context; + } catch (error) { + if (this.remoteRequestChannel) { + const result = await this.remoteRequestChannel.request(options, token); + return result; + } + throw error; + } + } + +} \ No newline at end of file diff --git a/src/vs/workbench/services/search/common/searchService.ts b/src/vs/workbench/services/search/common/searchService.ts new file mode 100644 index 000000000..53a811751 --- /dev/null +++ b/src/vs/workbench/services/search/common/searchService.ts @@ -0,0 +1,455 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as arrays from 'vs/base/common/arrays'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { canceled } from 'vs/base/common/errors'; +import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { keys, ResourceMap, values } from 'vs/base/common/map'; +import { Schemas } from 'vs/base/common/network'; +import { StopWatch } from 'vs/base/common/stopwatch'; +import { URI as uri } from 'vs/base/common/uri'; +import { IModelService } from 'vs/editor/common/services/modelService'; +import { IFileService } from 'vs/platform/files/common/files'; +import { ILogService } from 'vs/platform/log/common/log'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; +import { deserializeSearchError, FileMatch, ICachedSearchStats, IFileMatch, IFileQuery, IFileSearchStats, IFolderQuery, IProgressMessage, ISearchComplete, ISearchEngineStats, ISearchProgressItem, ISearchQuery, ISearchResultProvider, ISearchService, ITextQuery, pathIncludedInQuery, QueryType, SearchError, SearchErrorCode, SearchProviderType, isFileMatch, isProgressMessage } from 'vs/workbench/services/search/common/search'; +import { addContextToEditorMatches, editorMatchesToTextSearchResults } from 'vs/workbench/services/search/common/searchHelpers'; +import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; + +export class SearchService extends Disposable implements ISearchService { + _serviceBrand: any; + + protected diskSearch: ISearchResultProvider; + private readonly fileSearchProviders = new Map<string, ISearchResultProvider>(); + private readonly textSearchProviders = new Map<string, ISearchResultProvider>(); + + constructor( + private readonly modelService: IModelService, + private readonly untitledEditorService: IUntitledEditorService, + private readonly editorService: IEditorService, + private readonly telemetryService: ITelemetryService, + private readonly logService: ILogService, + private readonly extensionService: IExtensionService, + private readonly fileService: IFileService + ) { + super(); + } + + registerSearchResultProvider(scheme: string, type: SearchProviderType, provider: ISearchResultProvider): IDisposable { + let list: Map<string, ISearchResultProvider>; + if (type === SearchProviderType.file) { + list = this.fileSearchProviders; + } else if (type === SearchProviderType.text) { + list = this.textSearchProviders; + } else { + throw new Error('Unknown SearchProviderType'); + } + + list.set(scheme, provider); + + return toDisposable(() => { + list.delete(scheme); + }); + } + + textSearch(query: ITextQuery, token?: CancellationToken, onProgress?: (item: ISearchProgressItem) => void): Promise<ISearchComplete> { + // Get local results from dirty/untitled + const localResults = this.getLocalResults(query); + + if (onProgress) { + arrays.coalesce(localResults.values()).forEach(onProgress); + } + + const onProviderProgress = (progress: ISearchProgressItem) => { + if (isFileMatch(progress)) { + // Match + if (!localResults.has(progress.resource) && onProgress) { // don't override local results + onProgress(progress); + } + } else if (onProgress) { + // Progress + onProgress(<IProgressMessage>progress); + } + + if (isProgressMessage(progress)) { + this.logService.debug('SearchService#search', progress.message); + } + }; + + return this.doSearch(query, token, onProviderProgress); + } + + fileSearch(query: IFileQuery, token?: CancellationToken): Promise<ISearchComplete> { + return this.doSearch(query, token); + } + + private doSearch(query: ISearchQuery, token?: CancellationToken, onProgress?: (item: ISearchProgressItem) => void): Promise<ISearchComplete> { + this.logService.trace('SearchService#search', JSON.stringify(query)); + + const schemesInQuery = this.getSchemesInQuery(query); + + const providerActivations: Promise<any>[] = [Promise.resolve(null)]; + schemesInQuery.forEach(scheme => providerActivations.push(this.extensionService.activateByEvent(`onSearch:${scheme}`))); + providerActivations.push(this.extensionService.activateByEvent('onSearch:file')); + + const providerPromise = Promise.all(providerActivations) + .then(() => this.extensionService.whenInstalledExtensionsRegistered()) + .then(() => { + // Cancel faster if search was canceled while waiting for extensions + if (token && token.isCancellationRequested) { + return Promise.reject(canceled()); + } + + const progressCallback = (item: ISearchProgressItem) => { + if (token && token.isCancellationRequested) { + return; + } + + if (onProgress) { + onProgress(item); + } + }; + + return this.searchWithProviders(query, progressCallback, token); + }) + .then(completes => { + completes = arrays.coalesce(completes); + if (!completes.length) { + return { + limitHit: false, + results: [] + }; + } + + return <ISearchComplete>{ + limitHit: completes[0] && completes[0].limitHit, + stats: completes[0].stats, + results: arrays.flatten(completes.map((c: ISearchComplete) => c.results)) + }; + }); + + return new Promise((resolve, reject) => { + if (token) { + token.onCancellationRequested(() => { + reject(canceled()); + }); + } + + providerPromise.then(resolve, reject); + }); + } + + private getSchemesInQuery(query: ISearchQuery): Set<string> { + const schemes = new Set<string>(); + if (query.folderQueries) { + query.folderQueries.forEach(fq => schemes.add(fq.folder.scheme)); + } + + if (query.extraFileResources) { + query.extraFileResources.forEach(extraFile => schemes.add(extraFile.scheme)); + } + + return schemes; + } + + private searchWithProviders(query: ISearchQuery, onProviderProgress: (progress: ISearchProgressItem) => void, token?: CancellationToken) { + const e2eSW = StopWatch.create(false); + + const diskSearchQueries: IFolderQuery[] = []; + const searchPs: Promise<ISearchComplete>[] = []; + + const fqs = this.groupFolderQueriesByScheme(query); + keys(fqs).forEach(scheme => { + const schemeFQs = fqs.get(scheme)!; + const provider = query.type === QueryType.File ? + this.fileSearchProviders.get(scheme) : + this.textSearchProviders.get(scheme); + + if (!provider && scheme === 'file') { + diskSearchQueries.push(...schemeFQs); + } else if (!provider) { + console.warn('No search provider registered for scheme: ' + scheme); + } else { + const oneSchemeQuery: ISearchQuery = { + ...query, + ...{ + folderQueries: schemeFQs + } + }; + + searchPs.push(query.type === QueryType.File ? + provider.fileSearch(<IFileQuery>oneSchemeQuery, token) : + provider.textSearch(<ITextQuery>oneSchemeQuery, onProviderProgress, token)); + } + }); + + const diskSearchExtraFileResources = query.extraFileResources && query.extraFileResources.filter(res => res.scheme === Schemas.file); + + if (diskSearchQueries.length || diskSearchExtraFileResources) { + const diskSearchQuery: ISearchQuery = { + ...query, + ...{ + folderQueries: diskSearchQueries + }, + extraFileResources: diskSearchExtraFileResources + }; + + + if (this.diskSearch) { + searchPs.push(diskSearchQuery.type === QueryType.File ? + this.diskSearch.fileSearch(diskSearchQuery, token) : + this.diskSearch.textSearch(diskSearchQuery, onProviderProgress, token)); + } + } + + return Promise.all(searchPs).then(completes => { + const endToEndTime = e2eSW.elapsed(); + this.logService.trace(`SearchService#search: ${endToEndTime}ms`); + completes.forEach(complete => { + this.sendTelemetry(query, endToEndTime, complete); + }); + return completes; + }, err => { + const endToEndTime = e2eSW.elapsed(); + this.logService.trace(`SearchService#search: ${endToEndTime}ms`); + const searchError = deserializeSearchError(err.message); + this.sendTelemetry(query, endToEndTime, undefined, searchError); + + throw searchError; + }); + } + + private groupFolderQueriesByScheme(query: ISearchQuery): Map<string, IFolderQuery[]> { + const queries = new Map<string, IFolderQuery[]>(); + + query.folderQueries.forEach(fq => { + const schemeFQs = queries.get(fq.folder.scheme) || []; + schemeFQs.push(fq); + + queries.set(fq.folder.scheme, schemeFQs); + }); + + return queries; + } + + private sendTelemetry(query: ISearchQuery, endToEndTime: number, complete?: ISearchComplete, err?: SearchError): void { + const fileSchemeOnly = query.folderQueries.every(fq => fq.folder.scheme === 'file'); + const otherSchemeOnly = query.folderQueries.every(fq => fq.folder.scheme !== 'file'); + const scheme = fileSchemeOnly ? 'file' : + otherSchemeOnly ? 'other' : + 'mixed'; + + if (query.type === QueryType.File && complete && complete.stats) { + const fileSearchStats = complete.stats as IFileSearchStats; + if (fileSearchStats.fromCache) { + const cacheStats: ICachedSearchStats = fileSearchStats.detailStats as ICachedSearchStats; + + type CachedSearchCompleteClassifcation = { + reason?: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth' }; + resultCount: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; + workspaceFolderCount: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; + type: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth' }; + endToEndTime: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; + sortingTime?: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; + cacheWasResolved: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth' }; + cacheLookupTime: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; + cacheFilterTime: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; + cacheEntryCount: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; + scheme: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth' }; + }; + type CachedSearchCompleteEvent = { + reason?: string; + resultCount: number; + workspaceFolderCount: number; + type: 'fileSearchProvider' | 'searchProcess'; + endToEndTime: number; + sortingTime?: number; + cacheWasResolved: boolean; + cacheLookupTime: number; + cacheFilterTime: number; + cacheEntryCount: number; + scheme: string; + }; + this.telemetryService.publicLog2<CachedSearchCompleteEvent, CachedSearchCompleteClassifcation>('cachedSearchComplete', { + reason: query._reason, + resultCount: fileSearchStats.resultCount, + workspaceFolderCount: query.folderQueries.length, + type: fileSearchStats.type, + endToEndTime: endToEndTime, + sortingTime: fileSearchStats.sortingTime, + cacheWasResolved: cacheStats.cacheWasResolved, + cacheLookupTime: cacheStats.cacheLookupTime, + cacheFilterTime: cacheStats.cacheFilterTime, + cacheEntryCount: cacheStats.cacheEntryCount, + scheme + }); + } else { + const searchEngineStats: ISearchEngineStats = fileSearchStats.detailStats as ISearchEngineStats; + + type SearchCompleteClassification = { + reason?: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth' }; + resultCount: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; + workspaceFolderCount: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; + type: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth' }; + endToEndTime: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; + sortingTime?: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; + fileWalkTime: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; + directoriesWalked: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; + filesWalked: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; + cmdTime: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; + cmdResultCount?: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; + scheme: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth' }; + }; + type SearchCompleteEvent = { + reason?: string; + resultCount: number; + workspaceFolderCount: number; + type: 'fileSearchProvider' | 'searchProcess'; + endToEndTime: number; + sortingTime?: number; + fileWalkTime: number + directoriesWalked: number; + filesWalked: number; + cmdTime: number; + cmdResultCount?: number; + scheme: string; + + }; + + this.telemetryService.publicLog2<SearchCompleteEvent, SearchCompleteClassification>('searchComplete', { + reason: query._reason, + resultCount: fileSearchStats.resultCount, + workspaceFolderCount: query.folderQueries.length, + type: fileSearchStats.type, + endToEndTime: endToEndTime, + sortingTime: fileSearchStats.sortingTime, + fileWalkTime: searchEngineStats.fileWalkTime, + directoriesWalked: searchEngineStats.directoriesWalked, + filesWalked: searchEngineStats.filesWalked, + cmdTime: searchEngineStats.cmdTime, + cmdResultCount: searchEngineStats.cmdResultCount, + scheme + }); + } + } else if (query.type === QueryType.Text) { + let errorType: string | undefined; + if (err) { + errorType = err.code === SearchErrorCode.regexParseError ? 'regex' : + err.code === SearchErrorCode.unknownEncoding ? 'encoding' : + err.code === SearchErrorCode.globParseError ? 'glob' : + err.code === SearchErrorCode.invalidLiteral ? 'literal' : + err.code === SearchErrorCode.other ? 'other' : + 'unknown'; + } + + type TextSearchCompleteClassification = { + reason?: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth' }; + workspaceFolderCount: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; + endToEndTime: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth', isMeasurement: true }; + scheme: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth' }; + error?: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth' }; + usePCRE2: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth' }; + }; + type TextSearchCompleteEvent = { + reason?: string; + workspaceFolderCount: number; + endToEndTime: number; + scheme: string; + error?: string; + usePCRE2: boolean; + }; + this.telemetryService.publicLog2<TextSearchCompleteEvent, TextSearchCompleteClassification>('textSearchComplete', { + reason: query._reason, + workspaceFolderCount: query.folderQueries.length, + endToEndTime: endToEndTime, + scheme, + error: errorType, + usePCRE2: !!query.usePCRE2 + }); + } + } + + private getLocalResults(query: ITextQuery): ResourceMap<IFileMatch | null> { + const localResults = new ResourceMap<IFileMatch | null>(); + + if (query.type === QueryType.Text) { + const models = this.modelService.getModels(); + models.forEach((model) => { + const resource = model.uri; + if (!resource) { + return; + } + + if (!this.editorService.isOpen({ resource })) { + return; + } + + // Support untitled files + if (resource.scheme === Schemas.untitled) { + if (!this.untitledEditorService.exists(resource)) { + return; + } + } + + // Block walkthrough, webview, etc. + else if (!this.fileService.canHandleResource(resource)) { + return; + } + + if (!this.matches(resource, query)) { + return; // respect user filters + } + + // Use editor API to find matches + const matches = model.findMatches(query.contentPattern.pattern, false, !!query.contentPattern.isRegExp, !!query.contentPattern.isCaseSensitive, query.contentPattern.isWordMatch ? query.contentPattern.wordSeparators! : null, false, query.maxResults); + if (matches.length) { + const fileMatch = new FileMatch(resource); + localResults.set(resource, fileMatch); + + const textSearchResults = editorMatchesToTextSearchResults(matches, model, query.previewOptions); + fileMatch.results = addContextToEditorMatches(textSearchResults, model, query); + } else { + localResults.set(resource, null); + } + }); + } + + return localResults; + } + + private matches(resource: uri, query: ITextQuery): boolean { + return pathIncludedInQuery(query, resource.fsPath); + } + + clearCache(cacheKey: string): Promise<void> { + const clearPs = [ + this.diskSearch, + ...values(this.fileSearchProviders) + ].map(provider => provider && provider.clearCache(cacheKey)); + + return Promise.all(clearPs) + .then(() => { }); + } +} + +export class RemoteSearchService extends SearchService { + constructor( + @IModelService modelService: IModelService, + @IUntitledEditorService untitledEditorService: IUntitledEditorService, + @IEditorService editorService: IEditorService, + @ITelemetryService telemetryService: ITelemetryService, + @ILogService logService: ILogService, + @IExtensionService extensionService: IExtensionService, + @IFileService fileService: IFileService + ) { + super(modelService, untitledEditorService, editorService, telemetryService, logService, extensionService, fileService); + } +} + +registerSingleton(ISearchService, RemoteSearchService, true); diff --git a/src/vs/workbench/services/search/node/fileSearch.ts b/src/vs/workbench/services/search/node/fileSearch.ts index 612bd746d..5ade08b60 100644 --- a/src/vs/workbench/services/search/node/fileSearch.ts +++ b/src/vs/workbench/services/search/node/fileSearch.ts @@ -22,6 +22,7 @@ import { URI } from 'vs/base/common/uri'; import { readdir } from 'vs/base/node/pfs'; import { IFileQuery, IFolderQuery, IProgressMessage, ISearchEngineStats, IRawFileMatch, ISearchEngine, ISearchEngineSuccess } from 'vs/workbench/services/search/common/search'; import { spawnRipgrepCmd } from './ripgrepFileSearch'; +import { prepareQuery } from 'vs/base/parts/quickopen/common/quickOpenScorer'; interface IDirectoryEntry { base: string; @@ -76,7 +77,7 @@ export class FileWalker { this.errors = []; if (this.filePattern) { - this.normalizedFilePatternLowercase = strings.stripWildcards(this.filePattern).toLowerCase(); + this.normalizedFilePatternLowercase = prepareQuery(this.filePattern).lowercase; } this.globalExcludePattern = config.excludePattern && glob.parse(config.excludePattern); diff --git a/src/vs/workbench/services/search/node/rawSearchService.ts b/src/vs/workbench/services/search/node/rawSearchService.ts index 1d5ed2ca5..2a27d205a 100644 --- a/src/vs/workbench/services/search/node/rawSearchService.ts +++ b/src/vs/workbench/services/search/node/rawSearchService.ts @@ -16,7 +16,7 @@ import { StopWatch } from 'vs/base/common/stopwatch'; import * as strings from 'vs/base/common/strings'; import { URI, UriComponents } from 'vs/base/common/uri'; import { compareItemsByScore, IItemAccessor, prepareQuery, ScorerCache } from 'vs/base/parts/quickopen/common/quickOpenScorer'; -import { MAX_FILE_SIZE } from 'vs/platform/files/node/fileConstants'; +import { MAX_FILE_SIZE } from 'vs/base/node/pfs'; import { ICachedSearchStats, IFileQuery, IFileSearchStats, IFolderQuery, IProgressMessage, IRawFileQuery, IRawQuery, IRawTextQuery, ITextQuery, IFileSearchProgressItem, IRawFileMatch, IRawSearchService, ISearchEngine, ISearchEngineSuccess, ISerializedFileMatch, ISerializedSearchComplete, ISerializedSearchProgressItem, ISerializedSearchSuccess } from 'vs/workbench/services/search/common/search'; import { Engine as FileSearchEngine } from 'vs/workbench/services/search/node/fileSearch'; import { TextSearchEngineAdapter } from 'vs/workbench/services/search/node/textSearchAdapter'; @@ -312,7 +312,7 @@ export class SearchService implements IRawSearchService { // Pattern match on results const results: IRawFileMatch[] = []; - const normalizedSearchValueLowercase = strings.stripWildcards(searchValue).toLowerCase(); + const normalizedSearchValueLowercase = prepareQuery(searchValue).lowercase; for (const entry of cachedEntries) { // Check if this entry is a match for the search value diff --git a/src/vs/workbench/services/search/node/ripgrepTextSearchEngine.ts b/src/vs/workbench/services/search/node/ripgrepTextSearchEngine.ts index 12e027284..ee39b55b8 100644 --- a/src/vs/workbench/services/search/node/ripgrepTextSearchEngine.ts +++ b/src/vs/workbench/services/search/node/ripgrepTextSearchEngine.ts @@ -121,9 +121,10 @@ export class RipgrepTextSearchEngine { * "failed" when a fatal error was produced. */ export function rgErrorMsgForDisplay(msg: string): Maybe<SearchError> { - const firstLine = msg.split('\n')[0].trim(); + const lines = msg.split('\n'); + const firstLine = lines[0].trim(); - if (startsWith(firstLine, 'regex parse error')) { + if (lines.some(l => startsWith(l, 'regex parse error'))) { return new SearchError('Regex parse error', SearchErrorCode.regexParseError); } @@ -209,7 +210,7 @@ export class RipgrepParser extends EventEmitter { newlineIdx = dataStr.indexOf('\n', prevIdx); } - this.remainder = dataStr.substring(prevIdx).trim(); + this.remainder = dataStr.substring(prevIdx); } private handleLine(outputLine: string): void { @@ -409,24 +410,25 @@ function getRgArgs(query: TextSearchQuery, options: TextSearchOptions): string[] if ((<IExtendedExtensionSearchOptions>options).usePCRE2) { args.push('--pcre2'); + } - if (query.isRegExp) { - pattern = unicodeEscapesToPCRE2(pattern); - } + if (query.isRegExp) { + pattern = unicodeEscapesToPCRE2(pattern); } + // Allow $ to match /r/n + args.push('--crlf'); + let searchPatternAfterDoubleDashes: Maybe<string>; if (query.isWordMatch) { const regexp = createRegExp(pattern, !!query.isRegExp, { wholeWord: query.isWordMatch }); const regexpStr = regexp.source.replace(/\\\//g, '/'); // RegExp.source arbitrarily returns escaped slashes. Search and destroy. args.push('--regexp', regexpStr); } else if (query.isRegExp) { - let fixedRegexpQuery = fixRegexEndingPattern(query.pattern); - fixedRegexpQuery = fixRegexNewline(fixedRegexpQuery); + let fixedRegexpQuery = fixRegexNewline(query.pattern); fixedRegexpQuery = fixNewline(fixedRegexpQuery); - fixedRegexpQuery = fixRegexCRMatchingNonWordClass(fixedRegexpQuery, !!query.isMultiline); - fixedRegexpQuery = fixRegexCRMatchingWhitespaceClass(fixedRegexpQuery, !!query.isMultiline); args.push('--regexp', fixedRegexpQuery); + args.push('--auto-hybrid-regex'); } else { searchPatternAfterDoubleDashes = pattern; args.push('--fixed-strings'); @@ -508,32 +510,12 @@ export interface IRgSubmatch { export type IRgBytesOrText = { bytes: string } | { text: string }; -export function fixRegexEndingPattern(pattern: string): string { - // Replace an unescaped $ at the end of the pattern with \r?$ - // Match $ preceeded by none or even number of literal \ - return pattern.match(/([^\\]|^)(\\\\)*\$$/) ? - pattern.replace(/\$$/, '\\r?$') : - pattern; -} - export function fixRegexNewline(pattern: string): string { // Replace an unescaped $ at the end of the pattern with \r?$ // Match $ preceeded by none or even number of literal \ return pattern.replace(/([^\\]|^)(\\\\)*\\n/g, '$1$2\\r?\\n'); } -export function fixRegexCRMatchingWhitespaceClass(pattern: string, isMultiline: boolean): string { - return isMultiline ? - pattern.replace(/([^\\]|^)((?:\\\\)*)\\s/g, '$1$2(\\r?\\n|[^\\S\\r])') : - pattern.replace(/([^\\]|^)((?:\\\\)*)\\s/g, '$1$2[ \\t\\f]'); -} - -export function fixRegexCRMatchingNonWordClass(pattern: string, isMultiline: boolean): string { - return isMultiline ? - pattern.replace(/([^\\]|^)((?:\\\\)*)\\W/g, '$1$2(\\r?\\n|[^\\w\\r])') : - pattern.replace(/([^\\]|^)((?:\\\\)*)\\W/g, '$1$2[^\\w\\r]'); -} - export function fixNewline(pattern: string): string { return pattern.replace(/\n/g, '\\r?\\n'); } diff --git a/src/vs/workbench/services/search/node/searchService.ts b/src/vs/workbench/services/search/node/searchService.ts index fcef06a15..53de732e0 100644 --- a/src/vs/workbench/services/search/node/searchService.ts +++ b/src/vs/workbench/services/search/node/searchService.ts @@ -4,416 +4,44 @@ *--------------------------------------------------------------------------------------------*/ import { getPathFromAmdModule } from 'vs/base/common/amd'; -import * as arrays from 'vs/base/common/arrays'; import { CancellationToken } from 'vs/base/common/cancellation'; import { canceled } from 'vs/base/common/errors'; import { Event } from 'vs/base/common/event'; -import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; -import { keys, ResourceMap, values } from 'vs/base/common/map'; -import { Schemas } from 'vs/base/common/network'; -import { StopWatch } from 'vs/base/common/stopwatch'; +import { IDisposable } from 'vs/base/common/lifecycle'; import { URI as uri } from 'vs/base/common/uri'; -import * as pfs from 'vs/base/node/pfs'; import { getNextTickChannel } from 'vs/base/parts/ipc/common/ipc'; import { Client, IIPCOptions } from 'vs/base/parts/ipc/node/ipc.cp'; -import { IModelService } from 'vs/editor/common/services/modelService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IDebugParams, IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IFileService } from 'vs/platform/files/common/files'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/platform/log/common/log'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { FileMatch, IFileMatch, IFileQuery, IProgressMessage, IRawSearchService, ISearchComplete, ISearchConfiguration, ISearchProgressItem, ISearchResultProvider, ISerializedFileMatch, ISerializedSearchComplete, ISerializedSearchProgressItem, isSerializedSearchComplete, isSerializedSearchSuccess, ITextQuery, ISearchService } from 'vs/workbench/services/search/common/search'; +import { SearchChannelClient } from './searchIpc'; +import { SearchService } from 'vs/workbench/services/search/common/searchService'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { IModelService } from 'vs/editor/common/services/modelService'; +import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { deserializeSearchError, FileMatch, ICachedSearchStats, IFileMatch, IFileQuery, IFileSearchStats, IFolderQuery, IProgressMessage, IRawSearchService, ISearchComplete, ISearchConfiguration, ISearchEngineStats, ISearchProgressItem, ISearchQuery, ISearchResultProvider, ISearchService, ISerializedFileMatch, ISerializedSearchComplete, ISerializedSearchProgressItem, isSerializedSearchComplete, isSerializedSearchSuccess, ITextQuery, pathIncludedInQuery, QueryType, SearchError, SearchErrorCode, SearchProviderType, isFileMatch, isProgressMessage } from 'vs/workbench/services/search/common/search'; -import { addContextToEditorMatches, editorMatchesToTextSearchResults } from 'vs/workbench/services/search/common/searchHelpers'; -import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; -import { SearchChannelClient } from './searchIpc'; - -export class SearchService extends Disposable implements ISearchService { - _serviceBrand: any; - - private diskSearch: DiskSearch; - private readonly fileSearchProviders = new Map<string, ISearchResultProvider>(); - private readonly textSearchProviders = new Map<string, ISearchResultProvider>(); +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +export class LocalSearchService extends SearchService { constructor( - @IInstantiationService private readonly instantiationService: IInstantiationService, - @IModelService private readonly modelService: IModelService, - @IUntitledEditorService private readonly untitledEditorService: IUntitledEditorService, - @IEditorService private readonly editorService: IEditorService, - @IEnvironmentService environmentService: IEnvironmentService, - @ITelemetryService private readonly telemetryService: ITelemetryService, - @ILogService private readonly logService: ILogService, - @IExtensionService private readonly extensionService: IExtensionService, - @IFileService private readonly fileService: IFileService + @IModelService modelService: IModelService, + @IUntitledEditorService untitledEditorService: IUntitledEditorService, + @IEditorService editorService: IEditorService, + @ITelemetryService telemetryService: ITelemetryService, + @ILogService logService: ILogService, + @IExtensionService extensionService: IExtensionService, + @IFileService fileService: IFileService, + @IEnvironmentService readonly environmentService: IEnvironmentService, + @IInstantiationService readonly instantiationService: IInstantiationService ) { - super(); - this.diskSearch = this.instantiationService.createInstance(DiskSearch, !environmentService.isBuilt || environmentService.verbose, environmentService.debugSearch); - } - - registerSearchResultProvider(scheme: string, type: SearchProviderType, provider: ISearchResultProvider): IDisposable { - let list: Map<string, ISearchResultProvider>; - if (type === SearchProviderType.file) { - list = this.fileSearchProviders; - } else if (type === SearchProviderType.text) { - list = this.textSearchProviders; - } else { - throw new Error('Unknown SearchProviderType'); - } - - list.set(scheme, provider); - - return toDisposable(() => { - list.delete(scheme); - }); - } - - textSearch(query: ITextQuery, token?: CancellationToken, onProgress?: (item: ISearchProgressItem) => void): Promise<ISearchComplete> { - // Get local results from dirty/untitled - const localResults = this.getLocalResults(query); - - if (onProgress) { - arrays.coalesce(localResults.values()).forEach(onProgress); - } - - const onProviderProgress = (progress: ISearchProgressItem) => { - if (isFileMatch(progress)) { - // Match - if (!localResults.has(progress.resource) && onProgress) { // don't override local results - onProgress(progress); - } - } else if (onProgress) { - // Progress - onProgress(<IProgressMessage>progress); - } - - if (isProgressMessage(progress)) { - this.logService.debug('SearchService#search', progress.message); - } - }; - - return this.doSearch(query, token, onProviderProgress); - } - - fileSearch(query: IFileQuery, token?: CancellationToken): Promise<ISearchComplete> { - return this.doSearch(query, token); - } - - private doSearch(query: ISearchQuery, token?: CancellationToken, onProgress?: (item: ISearchProgressItem) => void): Promise<ISearchComplete> { - this.logService.trace('SearchService#search', JSON.stringify(query)); - - const schemesInQuery = this.getSchemesInQuery(query); - - const providerActivations: Promise<any>[] = [Promise.resolve(null)]; - schemesInQuery.forEach(scheme => providerActivations.push(this.extensionService.activateByEvent(`onSearch:${scheme}`))); - providerActivations.push(this.extensionService.activateByEvent('onSearch:file')); - - const providerPromise = Promise.all(providerActivations) - .then(() => this.extensionService.whenInstalledExtensionsRegistered()) - .then(() => { - // Cancel faster if search was canceled while waiting for extensions - if (token && token.isCancellationRequested) { - return Promise.reject(canceled()); - } - - const progressCallback = (item: ISearchProgressItem) => { - if (token && token.isCancellationRequested) { - return; - } - - if (onProgress) { - onProgress(item); - } - }; - - return this.searchWithProviders(query, progressCallback, token); - }) - .then(completes => { - completes = arrays.coalesce(completes); - if (!completes.length) { - return { - limitHit: false, - results: [] - }; - } - - return <ISearchComplete>{ - limitHit: completes[0] && completes[0].limitHit, - stats: completes[0].stats, - results: arrays.flatten(completes.map((c: ISearchComplete) => c.results)) - }; - }); - - return new Promise((resolve, reject) => { - if (token) { - token.onCancellationRequested(() => { - reject(canceled()); - }); - } - - providerPromise.then(resolve, reject); - }); - } - - private getSchemesInQuery(query: ISearchQuery): Set<string> { - const schemes = new Set<string>(); - if (query.folderQueries) { - query.folderQueries.forEach(fq => schemes.add(fq.folder.scheme)); - } - - if (query.extraFileResources) { - query.extraFileResources.forEach(extraFile => schemes.add(extraFile.scheme)); - } + super(modelService, untitledEditorService, editorService, telemetryService, logService, extensionService, fileService); - return schemes; - } - - private searchWithProviders(query: ISearchQuery, onProviderProgress: (progress: ISearchProgressItem) => void, token?: CancellationToken) { - const e2eSW = StopWatch.create(false); - - const diskSearchQueries: IFolderQuery[] = []; - const searchPs: Promise<ISearchComplete>[] = []; - const fqs = this.groupFolderQueriesByScheme(query); - keys(fqs).forEach(scheme => { - const schemeFQs = fqs.get(scheme)!; - const provider = query.type === QueryType.File ? - this.fileSearchProviders.get(scheme) : - this.textSearchProviders.get(scheme); - - if (!provider && scheme === 'file') { - diskSearchQueries.push(...schemeFQs); - } else if (!provider) { - console.warn('No search provider registered for scheme: ' + scheme); - } else { - const oneSchemeQuery: ISearchQuery = { - ...query, - ...{ - folderQueries: schemeFQs - } - }; - - searchPs.push(query.type === QueryType.File ? - provider.fileSearch(<IFileQuery>oneSchemeQuery, token) : - provider.textSearch(<ITextQuery>oneSchemeQuery, onProviderProgress, token)); - } - }); - - const diskSearchExtraFileResources = query.extraFileResources && query.extraFileResources.filter(res => res.scheme === Schemas.file); - - if (diskSearchQueries.length || diskSearchExtraFileResources) { - const diskSearchQuery: ISearchQuery = { - ...query, - ...{ - folderQueries: diskSearchQueries - }, - extraFileResources: diskSearchExtraFileResources - }; - - searchPs.push(diskSearchQuery.type === QueryType.File ? - this.diskSearch.fileSearch(diskSearchQuery, token) : - this.diskSearch.textSearch(diskSearchQuery, onProviderProgress, token)); - } - - return Promise.all(searchPs).then(completes => { - const endToEndTime = e2eSW.elapsed(); - this.logService.trace(`SearchService#search: ${endToEndTime}ms`); - completes.forEach(complete => { - this.sendTelemetry(query, endToEndTime, complete); - }); - return completes; - }, err => { - const endToEndTime = e2eSW.elapsed(); - this.logService.trace(`SearchService#search: ${endToEndTime}ms`); - const searchError = deserializeSearchError(err.message); - this.sendTelemetry(query, endToEndTime, undefined, searchError); - - throw searchError; - }); - } - - private groupFolderQueriesByScheme(query: ISearchQuery): Map<string, IFolderQuery[]> { - const queries = new Map<string, IFolderQuery[]>(); - - query.folderQueries.forEach(fq => { - const schemeFQs = queries.get(fq.folder.scheme) || []; - schemeFQs.push(fq); - - queries.set(fq.folder.scheme, schemeFQs); - }); - - return queries; - } - - private sendTelemetry(query: ISearchQuery, endToEndTime: number, complete?: ISearchComplete, err?: SearchError): void { - const fileSchemeOnly = query.folderQueries.every(fq => fq.folder.scheme === 'file'); - const otherSchemeOnly = query.folderQueries.every(fq => fq.folder.scheme !== 'file'); - const scheme = fileSchemeOnly ? 'file' : - otherSchemeOnly ? 'other' : - 'mixed'; - - if (query.type === QueryType.File && complete && complete.stats) { - const fileSearchStats = complete.stats as IFileSearchStats; - if (fileSearchStats.fromCache) { - const cacheStats: ICachedSearchStats = fileSearchStats.detailStats as ICachedSearchStats; - - /* __GDPR__ - "cachedSearchComplete" : { - "reason" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, - "resultCount" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "workspaceFolderCount" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "type" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, - "endToEndTime" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "sortingTime" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "cacheWasResolved" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, - "cacheLookupTime" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "cacheFilterTime" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "cacheEntryCount" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "scheme" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } - } - */ - this.telemetryService.publicLog('cachedSearchComplete', { - reason: query._reason, - resultCount: fileSearchStats.resultCount, - workspaceFolderCount: query.folderQueries.length, - type: fileSearchStats.type, - endToEndTime: endToEndTime, - sortingTime: fileSearchStats.sortingTime, - cacheWasResolved: cacheStats.cacheWasResolved, - cacheLookupTime: cacheStats.cacheLookupTime, - cacheFilterTime: cacheStats.cacheFilterTime, - cacheEntryCount: cacheStats.cacheEntryCount, - scheme - }); - } else { - const searchEngineStats: ISearchEngineStats = fileSearchStats.detailStats as ISearchEngineStats; - - /* __GDPR__ - "searchComplete" : { - "reason" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, - "resultCount" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "workspaceFolderCount" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "type" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, - "endToEndTime" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "sortingTime" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "fileWalkTime" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "directoriesWalked" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "filesWalked" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "cmdTime" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "cmdResultCount" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "scheme" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } - } - */ - this.telemetryService.publicLog('searchComplete', { - reason: query._reason, - resultCount: fileSearchStats.resultCount, - workspaceFolderCount: query.folderQueries.length, - type: fileSearchStats.type, - endToEndTime: endToEndTime, - sortingTime: fileSearchStats.sortingTime, - fileWalkTime: searchEngineStats.fileWalkTime, - directoriesWalked: searchEngineStats.directoriesWalked, - filesWalked: searchEngineStats.filesWalked, - cmdTime: searchEngineStats.cmdTime, - cmdResultCount: searchEngineStats.cmdResultCount, - scheme - }); - } - } else if (query.type === QueryType.Text) { - let errorType: string | undefined; - if (err) { - errorType = err.code === SearchErrorCode.regexParseError ? 'regex' : - err.code === SearchErrorCode.unknownEncoding ? 'encoding' : - err.code === SearchErrorCode.globParseError ? 'glob' : - err.code === SearchErrorCode.invalidLiteral ? 'literal' : - err.code === SearchErrorCode.other ? 'other' : - 'unknown'; - } - - /* __GDPR__ - "textSearchComplete" : { - "reason" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, - "workspaceFolderCount" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "endToEndTime" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "scheme" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, - "error" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, - "useRipgrep" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, - "usePCRE2" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } - } - */ - this.telemetryService.publicLog('textSearchComplete', { - reason: query._reason, - workspaceFolderCount: query.folderQueries.length, - endToEndTime: endToEndTime, - scheme, - error: errorType, - usePCRE2: !!query.usePCRE2 - }); - } - } - - private getLocalResults(query: ITextQuery): ResourceMap<IFileMatch | null> { - const localResults = new ResourceMap<IFileMatch | null>(); - - if (query.type === QueryType.Text) { - const models = this.modelService.getModels(); - models.forEach((model) => { - const resource = model.uri; - if (!resource) { - return; - } - - if (!this.editorService.isOpen({ resource })) { - return; - } - - // Support untitled files - if (resource.scheme === Schemas.untitled) { - if (!this.untitledEditorService.exists(resource)) { - return; - } - } - - // Block walkthrough, webview, etc. - else if (!this.fileService.canHandleResource(resource)) { - return; - } - - if (!this.matches(resource, query)) { - return; // respect user filters - } - - // Use editor API to find matches - const matches = model.findMatches(query.contentPattern.pattern, false, !!query.contentPattern.isRegExp, !!query.contentPattern.isCaseSensitive, query.contentPattern.isWordMatch ? query.contentPattern.wordSeparators! : null, false, query.maxResults); - if (matches.length) { - const fileMatch = new FileMatch(resource); - localResults.set(resource, fileMatch); - - const textSearchResults = editorMatchesToTextSearchResults(matches, model, query.previewOptions); - fileMatch.results = addContextToEditorMatches(textSearchResults, model, query); - } else { - localResults.set(resource, null); - } - }); - } - - return localResults; - } - - private matches(resource: uri, query: ITextQuery): boolean { - return pathIncludedInQuery(query, resource.fsPath); - } - - clearCache(cacheKey: string): Promise<void> { - const clearPs = [ - this.diskSearch, - ...values(this.fileSearchProviders) - ].map(provider => provider && provider.clearCache(cacheKey)); - - return Promise.all(clearPs) - .then(() => { }); + this.diskSearch = instantiationService.createInstance(DiskSearch, !environmentService.isBuilt || environmentService.verbose, environmentService.debugSearch); } } @@ -425,6 +53,7 @@ export class DiskSearch implements ISearchResultProvider { searchDebug: IDebugParams | undefined, @ILogService private readonly logService: ILogService, @IConfigurationService private readonly configService: IConfigurationService, + @IFileService private readonly fileService: IFileService ) { const timeout = this.configService.getValue<ISearchConfiguration>().search.maintainFileSearchCache ? Number.MAX_VALUE : @@ -465,7 +94,7 @@ export class DiskSearch implements ISearchResultProvider { textSearch(query: ITextQuery, onProgress?: (p: ISearchProgressItem) => void, token?: CancellationToken): Promise<ISearchComplete> { const folderQueries = query.folderQueries || []; - return Promise.all(folderQueries.map(q => q.folder.scheme === Schemas.file && pfs.exists(q.folder.fsPath))) + return Promise.all(folderQueries.map(q => this.fileService.exists(q.folder))) .then(exists => { if (token && token.isCancellationRequested) { throw canceled(); @@ -480,7 +109,7 @@ export class DiskSearch implements ISearchResultProvider { fileSearch(query: IFileQuery, token?: CancellationToken): Promise<ISearchComplete> { const folderQueries = query.folderQueries || []; - return Promise.all(folderQueries.map(q => q.folder.scheme === Schemas.file && pfs.exists(q.folder.fsPath))) + return Promise.all(folderQueries.map(q => this.fileService.exists(q.folder))) .then(exists => { if (token && token.isCancellationRequested) { throw canceled(); @@ -575,4 +204,4 @@ export class DiskSearch implements ISearchResultProvider { } } -registerSingleton(ISearchService, SearchService, true); \ No newline at end of file +registerSingleton(ISearchService, LocalSearchService, true); \ No newline at end of file diff --git a/src/vs/workbench/services/search/test/node/ripgrepTextSearchEngine.test.ts b/src/vs/workbench/services/search/test/node/ripgrepTextSearchEngine.test.ts index 262074bf0..fb307c68b 100644 --- a/src/vs/workbench/services/search/test/node/ripgrepTextSearchEngine.test.ts +++ b/src/vs/workbench/services/search/test/node/ripgrepTextSearchEngine.test.ts @@ -6,7 +6,7 @@ import * as assert from 'assert'; import { joinPath } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; -import { fixRegexCRMatchingNonWordClass, fixRegexCRMatchingWhitespaceClass, fixRegexEndingPattern, fixRegexNewline, IRgMatch, IRgMessage, RipgrepParser, unicodeEscapesToPCRE2, fixNewline } from 'vs/workbench/services/search/node/ripgrepTextSearchEngine'; +import { fixRegexNewline, IRgMatch, IRgMessage, RipgrepParser, unicodeEscapesToPCRE2, fixNewline } from 'vs/workbench/services/search/node/ripgrepTextSearchEngine'; import { Range, TextSearchResult } from 'vs/workbench/services/search/common/searchExtTypes'; suite('RipgrepTextSearchEngine', () => { @@ -24,70 +24,6 @@ suite('RipgrepTextSearchEngine', () => { assert.equal(unicodeEscapesToPCRE2(''), ''); }); - test('fixRegexEndingPattern', () => { - function testFixRegexEndingPattern([input, expectedResult]: string[]): void { - assert.equal(fixRegexEndingPattern(input), expectedResult); - } - - [ - ['foo', 'foo'], - ['', ''], - ['^foo.*bar\\s+', '^foo.*bar\\s+'], - ['foo$', 'foo\\r?$'], - ['$', '\\r?$'], - ['foo\\$', 'foo\\$'], - ['foo\\\\$', 'foo\\\\\\r?$'], - ].forEach(testFixRegexEndingPattern); - }); - - test('fixRegexCRMatchingWhitespaceClass', () => { - function testFixRegexCRMatchingWhitespaceClass([inputReg, isMultiline, testStr, shouldMatch]: [string, boolean, string, boolean]): void { - const fixed = fixRegexCRMatchingWhitespaceClass(inputReg, isMultiline); - const reg = new RegExp(fixed); - assert.equal(reg.test(testStr), shouldMatch, `${inputReg} => ${reg}, ${testStr}, ${shouldMatch}`); - } - - [ - ['foo', false, 'foo', true], - - ['foo\\s', false, 'foo\r\n', false], - ['foo\\sabc', true, 'foo\r\nabc', true], - - ['foo\\s', false, 'foo\n', false], - ['foo\\s', true, 'foo\n', true], - - ['foo\\s\\n', true, 'foo\r\n', false], - ['foo\\r\\s', true, 'foo\r\n', true], - - ['foo\\s+abc', true, 'foo \r\nabc', true], - ['foo\\s+abc', false, 'foo \t abc', true], - ].forEach(testFixRegexCRMatchingWhitespaceClass); - }); - - test('fixRegexCRMatchingNonWordClass', () => { - function testRegexCRMatchingNonWordClass([inputReg, isMultiline, testStr, shouldMatch]: [string, boolean, string, boolean]): void { - const fixed = fixRegexCRMatchingNonWordClass(inputReg, isMultiline); - const reg = new RegExp(fixed); - assert.equal(reg.test(testStr), shouldMatch, `${inputReg} => ${reg}, ${testStr}, ${shouldMatch}`); - } - - [ - ['foo', false, 'foo', true], - - ['foo\\W', false, 'foo\r\n', false], - ['foo\\Wabc', true, 'foo\r\nabc', true], - - ['foo\\W', false, 'foo\n', true], - ['foo\\W', true, 'foo\n', true], - - ['foo\\W\\n', true, 'foo\r\n', false], - ['foo\\r\\W', true, 'foo\r\n', true], - - ['foo\\W+abc', true, 'foo \r\nabc', true], - ['foo\\W+abc', false, 'foo .-\t abc', true], - ].forEach(testRegexCRMatchingNonWordClass); - }); - test('fixRegexNewline', () => { function testFixRegexNewline([inputReg, testStr, shouldMatch]: [string, string, boolean]): void { const fixed = fixRegexNewline(inputReg); @@ -223,15 +159,16 @@ suite('RipgrepTextSearchEngine', () => { test('chopped-up input chunks', () => { const dataStrs = [ - makeRgMatch('file1.js', 'foobar', 4, [{ start: 3, end: 6 }]), + makeRgMatch('file1.js', 'foo bar', 4, [{ start: 3, end: 7 }]), makeRgMatch('app/file2.js', 'foobar', 4, [{ start: 3, end: 6 }]), makeRgMatch('app2/file3.js', 'foobar', 4, [{ start: 3, end: 6 }]), ]; + const dataStr0Space = dataStrs[0].indexOf(' '); testParser( [ - dataStrs[0].substring(0, 5), - dataStrs[0].substring(5), + dataStrs[0].substring(0, dataStr0Space + 1), + dataStrs[0].substring(dataStr0Space + 1), '\n', dataStrs[1].trim(), '\n' + dataStrs[2].substring(0, 25), @@ -240,11 +177,11 @@ suite('RipgrepTextSearchEngine', () => { [ { preview: { - text: 'foobar', - matches: [new Range(0, 3, 0, 6)] + text: 'foo bar', + matches: [new Range(0, 3, 0, 7)] }, uri: joinPath(TEST_FOLDER, 'file1.js'), - ranges: [new Range(3, 3, 3, 6)] + ranges: [new Range(3, 3, 3, 7)] }, { preview: { 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 b751b3b0c..6f39df772 100644 --- a/src/vs/workbench/services/search/test/node/textSearch.integrationTest.ts +++ b/src/vs/workbench/services/search/test/node/textSearch.integrationTest.ts @@ -378,7 +378,7 @@ suite('Search-integration', function () { folderQueries: ROOT_FOLDER_QUERY, contentPattern: { pattern: 'foo' }, includePattern: { - '***': true + '{{}': true } }; @@ -386,26 +386,10 @@ suite('Search-integration', function () { throw new Error('expected fail'); }, err => { const searchError = deserializeSearchError(err.message); - assert.equal(searchError.message, 'Error parsing glob \'***\': invalid use of **; must be one path component'); + assert.equal(searchError.message, 'Error parsing glob \'/{{}\': nested alternate groups are not allowed'); assert.equal(searchError.code, SearchErrorCode.globParseError); }); }); - - test('invalid literal', () => { - const config: ITextQuery = { - type: QueryType.Text, - folderQueries: ROOT_FOLDER_QUERY, - contentPattern: { pattern: 'foo\nbar', isRegExp: true } - }; - - return doSearchTest(config, 0).then(() => { - throw new Error('expected fail'); - }, err => { - const searchError = deserializeSearchError(err.message); - assert.equal(searchError.message, 'The literal \'"\\n"\' is not allowed in a regex'); - assert.equal(searchError.code, SearchErrorCode.invalidLiteral); - }); - }); }); }); diff --git a/src/vs/workbench/services/telemetry/browser/telemetryService.ts b/src/vs/workbench/services/telemetry/browser/telemetryService.ts new file mode 100644 index 000000000..652aaf3a2 --- /dev/null +++ b/src/vs/workbench/services/telemetry/browser/telemetryService.ts @@ -0,0 +1,170 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ITelemetryService, ITelemetryInfo, ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; +import { NullTelemetryService, combinedAppender, LogAppender, ITelemetryAppender, validateTelemetryData } from 'vs/platform/telemetry/common/telemetryUtils'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { ILogService } from 'vs/platform/log/common/log'; +import { TelemetryService as BaseTelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings'; +import { IStorageService } from 'vs/platform/storage/common/storage'; +import { resolveWorkbenchCommonProperties } from 'vs/platform/telemetry/browser/workbenchCommonProperties'; +import { IProductService } from 'vs/platform/product/common/product'; + +interface IConfig { + instrumentationKey?: string; + endpointUrl?: string; + emitLineDelimitedJson?: boolean; + accountId?: string; + sessionRenewalMs?: number; + sessionExpirationMs?: number; + maxBatchSizeInBytes?: number; + maxBatchInterval?: number; + enableDebug?: boolean; + disableExceptionTracking?: boolean; + disableTelemetry?: boolean; + verboseLogging?: boolean; + diagnosticLogInterval?: number; + samplingPercentage?: number; + autoTrackPageVisitTime?: boolean; + disableAjaxTracking?: boolean; + overridePageViewDuration?: boolean; + maxAjaxCallsPerView?: number; + disableDataLossAnalysis?: boolean; + disableCorrelationHeaders?: boolean; + correlationHeaderExcludedDomains?: string[]; + disableFlushOnBeforeUnload?: boolean; + enableSessionStorageBuffer?: boolean; + isCookieUseDisabled?: boolean; + cookieDomain?: string; + isRetryDisabled?: boolean; + url?: string; + isStorageUseDisabled?: boolean; + isBeaconApiDisabled?: boolean; + sdkExtension?: string; + isBrowserLinkTrackingEnabled?: boolean; + appId?: string; + enableCorsCorrelation?: boolean; +} + +declare class Microsoft { + public static ApplicationInsights: { + Initialization: { + new(init: { config: IConfig }): AppInsights; + } + }; +} + +declare interface IAppInsightsClient { + config: IConfig; + + /** Log a user action or other occurrence. */ + trackEvent: (name: string, properties?: { [key: string]: string }, measurements?: { [key: string]: number }) => void; + + /** Immediately send all queued telemetry. Synchronous. */ + flush(): void; +} + +interface AppInsights { + loadAppInsights: () => IAppInsightsClient; +} + +export class WebTelemetryAppender implements ITelemetryAppender { + private _aiClient?: IAppInsightsClient; + + constructor(aiKey: string, private _logService: ILogService) { + const initConfig = { + config: { + instrumentationKey: aiKey, + endpointUrl: 'https://vortex.data.microsoft.com/collect/v1', + emitLineDelimitedJson: true, + autoTrackPageVisitTime: false, + disableExceptionTracking: true, + disableAjaxTracking: true + } + }; + + const appInsights = new Microsoft.ApplicationInsights.Initialization(initConfig); + this._aiClient = appInsights.loadAppInsights(); + } + + log(eventName: string, data: any): void { + if (!this._aiClient) { + return; + } + + data = validateTelemetryData(data); + this._logService.trace(`telemetry/${eventName}`, data); + + this._aiClient.trackEvent('monacoworkbench/' + eventName, data.properties, data.measurements); + } + + flush(): Promise<void> { + if (this._aiClient) { + return new Promise(resolve => { + this._aiClient!.flush(); + this._aiClient = undefined; + resolve(undefined); + }); + } + + return Promise.resolve(); + } +} + +export class TelemetryService extends Disposable implements ITelemetryService { + + _serviceBrand: any; + + private impl: ITelemetryService; + + constructor( + @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, + @ILogService logService: ILogService, + @IConfigurationService configurationService: IConfigurationService, + @IStorageService storageService: IStorageService, + @IProductService productService: IProductService + ) { + super(); + + const aiKey = productService.aiConfig && productService.aiConfig.asimovKey; + if (!environmentService.isExtensionDevelopment && !environmentService.args['disable-telemetry'] && !!productService.enableTelemetry && !!aiKey) { + const config: ITelemetryServiceConfig = { + appender: combinedAppender(new WebTelemetryAppender(aiKey, logService), new LogAppender(logService)), + commonProperties: resolveWorkbenchCommonProperties(storageService, productService.commit, productService.version, environmentService.configuration.machineId, environmentService.configuration.remoteAuthority), + piiPaths: [environmentService.appRoot] + }; + + this.impl = this._register(new BaseTelemetryService(config, configurationService)); + } else { + this.impl = NullTelemetryService; + } + } + + setEnabled(value: boolean): void { + return this.impl.setEnabled(value); + } + + get isOptedIn(): boolean { + return this.impl.isOptedIn; + } + + publicLog(eventName: string, data?: ITelemetryData, anonymizeFilePaths?: boolean): Promise<void> { + return this.impl.publicLog(eventName, data, anonymizeFilePaths); + } + + publicLog2<E extends ClassifiedEvent<T> = never, T extends GDPRClassification<T> = never>(eventName: string, data?: StrictPropertyCheck<T, E>, anonymizeFilePaths?: boolean) { + return this.publicLog(eventName, data as ITelemetryData, anonymizeFilePaths); + } + + getTelemetryInfo(): Promise<ITelemetryInfo> { + return this.impl.getTelemetryInfo(); + } +} + +registerSingleton(ITelemetryService, TelemetryService); \ No newline at end of file diff --git a/src/vs/workbench/services/telemetry/electron-browser/telemetryService.ts b/src/vs/workbench/services/telemetry/electron-browser/telemetryService.ts index d905178fc..6eaaf220c 100644 --- a/src/vs/workbench/services/telemetry/electron-browser/telemetryService.ts +++ b/src/vs/workbench/services/telemetry/electron-browser/telemetryService.ts @@ -16,6 +16,7 @@ import { IStorageService } from 'vs/platform/storage/common/storage'; import { resolveWorkbenchCommonProperties } from 'vs/platform/telemetry/node/workbenchCommonProperties'; import { TelemetryService as BaseTelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings'; export class TelemetryService extends Disposable implements ITelemetryService { @@ -37,8 +38,8 @@ export class TelemetryService extends Disposable implements ITelemetryService { const channel = sharedProcessService.getChannel('telemetryAppender'); const config: ITelemetryServiceConfig = { appender: combinedAppender(new TelemetryAppenderClient(channel), new LogAppender(logService)), - commonProperties: resolveWorkbenchCommonProperties(storageService, productService.commit, productService.version, environmentService.configuration.machineId, environmentService.installSourcePath), - piiPaths: [environmentService.appRoot, environmentService.extensionsPath] + commonProperties: resolveWorkbenchCommonProperties(storageService, productService.commit, productService.version, environmentService.configuration.machineId, environmentService.installSourcePath, environmentService.configuration.remoteAuthority), + piiPaths: environmentService.extensionsPath ? [environmentService.appRoot, environmentService.extensionsPath] : [environmentService.appRoot] }; this.impl = this._register(new BaseTelemetryService(config, configurationService)); @@ -59,6 +60,10 @@ export class TelemetryService extends Disposable implements ITelemetryService { return this.impl.publicLog(eventName, data, anonymizeFilePaths); } + publicLog2<E extends ClassifiedEvent<T> = never, T extends GDPRClassification<T> = never>(eventName: string, data?: StrictPropertyCheck<T, E>, anonymizeFilePaths?: boolean) { + return this.publicLog(eventName, data as ITelemetryData, anonymizeFilePaths); + } + getTelemetryInfo(): Promise<ITelemetryInfo> { return this.impl.getTelemetryInfo(); } diff --git a/src/vs/workbench/services/textMate/browser/abstractTextMateService.ts b/src/vs/workbench/services/textMate/browser/abstractTextMateService.ts new file mode 100644 index 000000000..d73ffc2fa --- /dev/null +++ b/src/vs/workbench/services/textMate/browser/abstractTextMateService.ts @@ -0,0 +1,448 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { Color } from 'vs/base/common/color'; +import { onUnexpectedError } from 'vs/base/common/errors'; +import { Emitter, Event } from 'vs/base/common/event'; +import * as resources from 'vs/base/common/resources'; +import * as types from 'vs/base/common/types'; +import { URI } from 'vs/base/common/uri'; +import { TokenizationResult, TokenizationResult2 } from 'vs/editor/common/core/token'; +import { IState, ITokenizationSupport, LanguageId, TokenMetadata, TokenizationRegistry, StandardTokenType, LanguageIdentifier } from 'vs/editor/common/modes'; +import { nullTokenize2 } from 'vs/editor/common/modes/nullMode'; +import { generateTokensCSSForColorMap } from 'vs/editor/common/modes/supports/tokenization'; +import { IModeService } from 'vs/editor/common/services/modeService'; +import { IFileService } from 'vs/platform/files/common/files'; +import { ILogService } from 'vs/platform/log/common/log'; +import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; +import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; +import { ExtensionMessageCollector } from 'vs/workbench/services/extensions/common/extensionsRegistry'; +import { ITMSyntaxExtensionPoint, grammarsExtPoint } from 'vs/workbench/services/textMate/common/TMGrammars'; +import { ITextMateService } from 'vs/workbench/services/textMate/common/textMateService'; +import { ITokenColorizationRule, IWorkbenchThemeService, IColorTheme } from 'vs/workbench/services/themes/common/workbenchThemeService'; +import { IGrammar, StackElement, IOnigLib, IRawTheme } from 'vscode-textmate'; +import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IValidGrammarDefinition, IValidEmbeddedLanguagesMap, IValidTokenTypeMap } from 'vs/workbench/services/textMate/common/TMScopeRegistry'; +import { TMGrammarFactory } from 'vs/workbench/services/textMate/common/TMGrammarFactory'; + +export abstract class AbstractTextMateService extends Disposable implements ITextMateService { + public _serviceBrand: any; + + private readonly _onDidEncounterLanguage: Emitter<LanguageId> = this._register(new Emitter<LanguageId>()); + public readonly onDidEncounterLanguage: Event<LanguageId> = this._onDidEncounterLanguage.event; + + private readonly _styleElement: HTMLStyleElement; + private readonly _createdModes: string[]; + private readonly _encounteredLanguages: boolean[]; + + private _grammarDefinitions: IValidGrammarDefinition[] | null; + private _grammarFactory: TMGrammarFactory | null; + private _tokenizersRegistrations: IDisposable[]; + protected _currentTheme: IRawTheme | null; + + constructor( + @IModeService private readonly _modeService: IModeService, + @IWorkbenchThemeService private readonly _themeService: IWorkbenchThemeService, + @IFileService protected readonly _fileService: IFileService, + @INotificationService private readonly _notificationService: INotificationService, + @ILogService private readonly _logService: ILogService, + @IConfigurationService private readonly _configurationService: IConfigurationService, + @IStorageService private readonly _storageService: IStorageService + ) { + super(); + this._styleElement = dom.createStyleSheet(); + this._styleElement.className = 'vscode-tokens-styles'; + this._createdModes = []; + this._encounteredLanguages = []; + + this._grammarDefinitions = null; + this._grammarFactory = null; + this._tokenizersRegistrations = []; + + this._currentTheme = null; + + grammarsExtPoint.setHandler((extensions) => { + this._grammarDefinitions = null; + if (this._grammarFactory) { + this._grammarFactory.dispose(); + this._grammarFactory = null; + this._onDidDisposeGrammarFactory(); + } + this._tokenizersRegistrations = dispose(this._tokenizersRegistrations); + + this._grammarDefinitions = []; + for (const extension of extensions) { + const grammars = extension.value; + for (const grammar of grammars) { + if (!this._validateGrammarExtensionPoint(extension.description.extensionLocation, grammar, extension.collector)) { + continue; + } + const grammarLocation = resources.joinPath(extension.description.extensionLocation, grammar.path); + + const embeddedLanguages: IValidEmbeddedLanguagesMap = Object.create(null); + if (grammar.embeddedLanguages) { + let scopes = Object.keys(grammar.embeddedLanguages); + for (let i = 0, len = scopes.length; i < len; i++) { + let scope = scopes[i]; + let language = grammar.embeddedLanguages[scope]; + if (typeof language !== 'string') { + // never hurts to be too careful + continue; + } + let languageIdentifier = this._modeService.getLanguageIdentifier(language); + if (languageIdentifier) { + embeddedLanguages[scope] = languageIdentifier.id; + } + } + } + + const tokenTypes: IValidTokenTypeMap = Object.create(null); + if (grammar.tokenTypes) { + const scopes = Object.keys(grammar.tokenTypes); + for (const scope of scopes) { + const tokenType = grammar.tokenTypes[scope]; + switch (tokenType) { + case 'string': + tokenTypes[scope] = StandardTokenType.String; + break; + case 'other': + tokenTypes[scope] = StandardTokenType.Other; + break; + case 'comment': + tokenTypes[scope] = StandardTokenType.Comment; + break; + } + } + } + + let languageIdentifier: LanguageIdentifier | null = null; + if (grammar.language) { + languageIdentifier = this._modeService.getLanguageIdentifier(grammar.language); + } + + this._grammarDefinitions.push({ + location: grammarLocation, + language: languageIdentifier ? languageIdentifier.id : undefined, + scopeName: grammar.scopeName, + embeddedLanguages: embeddedLanguages, + tokenTypes: tokenTypes, + injectTo: grammar.injectTo, + }); + } + } + + for (const createMode of this._createdModes) { + this._registerDefinitionIfAvailable(createMode); + } + }); + + this._register(this._themeService.onDidColorThemeChange(() => { + if (this._grammarFactory) { + this._updateTheme(this._grammarFactory, this._themeService.getColorTheme(), false); + } + })); + + // Generate some color map until the grammar registry is loaded + let colorTheme = this._themeService.getColorTheme(); + let defaultForeground: Color = Color.transparent; + let defaultBackground: Color = Color.transparent; + for (let i = 0, len = colorTheme.tokenColors.length; i < len; i++) { + let rule = colorTheme.tokenColors[i]; + if (!rule.scope && rule.settings) { + if (rule.settings.foreground) { + defaultForeground = Color.fromHex(rule.settings.foreground); + } + if (rule.settings.background) { + defaultBackground = Color.fromHex(rule.settings.background); + } + } + } + TokenizationRegistry.setColorMap([null!, defaultForeground, defaultBackground]); + + this._modeService.onDidCreateMode((mode) => { + let modeId = mode.getId(); + this._createdModes.push(modeId); + this._registerDefinitionIfAvailable(modeId); + }); + } + + private _canCreateGrammarFactory(): boolean { + // Check if extension point is ready + return (this._grammarDefinitions ? true : false); + } + + private async _getOrCreateGrammarFactory(): Promise<TMGrammarFactory> { + if (this._grammarFactory) { + return this._grammarFactory; + } + + const vscodeTextmate = await this._loadVSCodeTextmate(); + + // Avoid duplicate instantiations + if (this._grammarFactory) { + return this._grammarFactory; + } + + this._grammarFactory = new TMGrammarFactory({ + logTrace: (msg: string) => this._logService.trace(msg), + logError: (msg: string, err: any) => this._logService.error(msg, err), + readFile: async (resource: URI) => { + const content = await this._fileService.readFile(resource); + return content.value.toString(); + } + }, this._grammarDefinitions || [], vscodeTextmate, this._loadOnigLib()); + this._onDidCreateGrammarFactory(this._grammarDefinitions || []); + + this._updateTheme(this._grammarFactory, this._themeService.getColorTheme(), true); + + return this._grammarFactory; + } + + private async _registerDefinitionIfAvailable(modeId: string): Promise<void> { + const languageIdentifier = this._modeService.getLanguageIdentifier(modeId); + if (!languageIdentifier) { + return; + } + const languageId = languageIdentifier.id; + try { + if (!this._canCreateGrammarFactory()) { + return; + } + const grammarFactory = await this._getOrCreateGrammarFactory(); + if (grammarFactory.has(languageId)) { + const promise = grammarFactory.createGrammar(languageId).then((r) => { + const tokenization = new TMTokenization(r.grammar, r.initialState, r.containsEmbeddedLanguages); + tokenization.onDidEncounterLanguage((languageId) => { + if (!this._encounteredLanguages[languageId]) { + this._encounteredLanguages[languageId] = true; + this._onDidEncounterLanguage.fire(languageId); + } + }); + return new TMTokenizationSupport(r.languageId, tokenization, this._notificationService, this._configurationService, this._storageService); + }, e => { + onUnexpectedError(e); + return null; + }); + this._tokenizersRegistrations.push(TokenizationRegistry.registerPromise(modeId, promise)); + } + } catch (err) { + onUnexpectedError(err); + } + } + + private static _toColorMap(colorMap: string[]): Color[] { + let result: Color[] = [null!]; + for (let i = 1, len = colorMap.length; i < len; i++) { + result[i] = Color.fromHex(colorMap[i]); + } + return result; + } + + private _updateTheme(grammarFactory: TMGrammarFactory, colorTheme: IColorTheme, forceUpdate: boolean): void { + if (!forceUpdate && this._currentTheme && AbstractTextMateService.equalsTokenRules(this._currentTheme.settings, colorTheme.tokenColors)) { + return; + } + this._currentTheme = { name: colorTheme.label, settings: colorTheme.tokenColors }; + this._doUpdateTheme(grammarFactory, this._currentTheme); + } + + protected _doUpdateTheme(grammarFactory: TMGrammarFactory, theme: IRawTheme): void { + grammarFactory.setTheme(theme); + let colorMap = AbstractTextMateService._toColorMap(grammarFactory.getColorMap()); + let cssRules = generateTokensCSSForColorMap(colorMap); + this._styleElement.innerHTML = cssRules; + TokenizationRegistry.setColorMap(colorMap); + } + + private static equalsTokenRules(a: ITokenColorizationRule[] | null, b: ITokenColorizationRule[] | null): boolean { + if (!b || !a || b.length !== a.length) { + return false; + } + for (let i = b.length - 1; i >= 0; i--) { + let r1 = b[i]; + let r2 = a[i]; + if (r1.scope !== r2.scope) { + return false; + } + let s1 = r1.settings; + let s2 = r2.settings; + if (s1 && s2) { + if (s1.fontStyle !== s2.fontStyle || s1.foreground !== s2.foreground || s1.background !== s2.background) { + return false; + } + } else if (!s1 || !s2) { + return false; + } + } + return true; + } + + private _validateGrammarExtensionPoint(extensionLocation: URI, syntax: ITMSyntaxExtensionPoint, collector: ExtensionMessageCollector): boolean { + if (syntax.language && ((typeof syntax.language !== 'string') || !this._modeService.isRegisteredMode(syntax.language))) { + collector.error(nls.localize('invalid.language', "Unknown language in `contributes.{0}.language`. Provided value: {1}", grammarsExtPoint.name, String(syntax.language))); + return false; + } + if (!syntax.scopeName || (typeof syntax.scopeName !== 'string')) { + collector.error(nls.localize('invalid.scopeName', "Expected string in `contributes.{0}.scopeName`. Provided value: {1}", grammarsExtPoint.name, String(syntax.scopeName))); + return false; + } + if (!syntax.path || (typeof syntax.path !== 'string')) { + collector.error(nls.localize('invalid.path.0', "Expected string in `contributes.{0}.path`. Provided value: {1}", grammarsExtPoint.name, String(syntax.path))); + return false; + } + if (syntax.injectTo && (!Array.isArray(syntax.injectTo) || syntax.injectTo.some(scope => typeof scope !== 'string'))) { + collector.error(nls.localize('invalid.injectTo', "Invalid value in `contributes.{0}.injectTo`. Must be an array of language scope names. Provided value: {1}", grammarsExtPoint.name, JSON.stringify(syntax.injectTo))); + return false; + } + if (syntax.embeddedLanguages && !types.isObject(syntax.embeddedLanguages)) { + collector.error(nls.localize('invalid.embeddedLanguages', "Invalid value in `contributes.{0}.embeddedLanguages`. Must be an object map from scope name to language. Provided value: {1}", grammarsExtPoint.name, JSON.stringify(syntax.embeddedLanguages))); + return false; + } + + if (syntax.tokenTypes && !types.isObject(syntax.tokenTypes)) { + collector.error(nls.localize('invalid.tokenTypes', "Invalid value in `contributes.{0}.tokenTypes`. Must be an object map from scope name to token type. Provided value: {1}", grammarsExtPoint.name, JSON.stringify(syntax.tokenTypes))); + return false; + } + + const grammarLocation = resources.joinPath(extensionLocation, syntax.path); + if (!resources.isEqualOrParent(grammarLocation, extensionLocation)) { + 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.", grammarsExtPoint.name, grammarLocation.path, extensionLocation.path)); + } + return true; + } + + public async createGrammar(modeId: string): Promise<IGrammar> { + const grammarFactory = await this._getOrCreateGrammarFactory(); + const { grammar } = await grammarFactory.createGrammar(this._modeService.getLanguageIdentifier(modeId)!.id); + return grammar; + } + + protected _onDidCreateGrammarFactory(grammarDefinitions: IValidGrammarDefinition[]): void { + } + + protected _onDidDisposeGrammarFactory(): void { + } + + protected abstract _loadVSCodeTextmate(): Promise<typeof import('vscode-textmate')>; + protected abstract _loadOnigLib(): Promise<IOnigLib> | undefined; +} + +const donotAskUpdateKey = 'editor.maxTokenizationLineLength.donotask'; + +class TMTokenizationSupport implements ITokenizationSupport { + private readonly _languageId: LanguageId; + private readonly _actual: TMTokenization; + private _tokenizationWarningAlreadyShown: boolean; + private _maxTokenizationLineLength: number; + + constructor( + languageId: LanguageId, + actual: TMTokenization, + @INotificationService private readonly _notificationService: INotificationService, + @IConfigurationService private readonly _configurationService: IConfigurationService, + @IStorageService private readonly _storageService: IStorageService + ) { + this._languageId = languageId; + this._actual = actual; + this._tokenizationWarningAlreadyShown = !!(this._storageService.getBoolean(donotAskUpdateKey, StorageScope.GLOBAL)); + this._maxTokenizationLineLength = this._configurationService.getValue<number>('editor.maxTokenizationLineLength'); + this._configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('editor.maxTokenizationLineLength')) { + this._maxTokenizationLineLength = this._configurationService.getValue<number>('editor.maxTokenizationLineLength'); + } + }); + } + + getInitialState(): IState { + return this._actual.getInitialState(); + } + + tokenize(line: string, state: IState, offsetDelta: number): TokenizationResult { + throw new Error('Not supported!'); + } + + tokenize2(line: string, state: StackElement, offsetDelta: number): TokenizationResult2 { + if (offsetDelta !== 0) { + throw new Error('Unexpected: offsetDelta should be 0.'); + } + + // Do not attempt to tokenize if a line is too long + if (line.length >= this._maxTokenizationLineLength) { + if (!this._tokenizationWarningAlreadyShown) { + this._tokenizationWarningAlreadyShown = true; + this._notificationService.prompt( + Severity.Warning, + nls.localize('too many characters', "Tokenization is skipped for long lines for performance reasons. The length of a long line can be configured via `editor.maxTokenizationLineLength`."), + [{ + label: nls.localize('neverAgain', "Don't Show Again"), + isSecondary: true, + run: () => this._storageService.store(donotAskUpdateKey, true, StorageScope.GLOBAL) + }] + ); + } + console.log(`Line (${line.substr(0, 15)}...): longer than ${this._maxTokenizationLineLength} characters, tokenization skipped.`); + return nullTokenize2(this._languageId, line, state, offsetDelta); + } + + return this._actual.tokenize2(line, state); + } +} + +class TMTokenization extends Disposable { + + private readonly _grammar: IGrammar; + private readonly _containsEmbeddedLanguages: boolean; + private readonly _seenLanguages: boolean[]; + private readonly _initialState: StackElement; + + private readonly _onDidEncounterLanguage: Emitter<LanguageId> = this._register(new Emitter<LanguageId>()); + public readonly onDidEncounterLanguage: Event<LanguageId> = this._onDidEncounterLanguage.event; + + constructor(grammar: IGrammar, initialState: StackElement, containsEmbeddedLanguages: boolean) { + super(); + this._grammar = grammar; + this._initialState = initialState; + this._containsEmbeddedLanguages = containsEmbeddedLanguages; + this._seenLanguages = []; + } + + public getInitialState(): IState { + return this._initialState; + } + + public tokenize2(line: string, state: StackElement): TokenizationResult2 { + let textMateResult = this._grammar.tokenizeLine2(line, state); + + if (this._containsEmbeddedLanguages) { + let seenLanguages = this._seenLanguages; + let tokens = textMateResult.tokens; + + // Must check if any of the embedded languages was hit + for (let i = 0, len = (tokens.length >>> 1); i < len; i++) { + let metadata = tokens[(i << 1) + 1]; + let languageId = TokenMetadata.getLanguageId(metadata); + + if (!seenLanguages[languageId]) { + seenLanguages[languageId] = true; + this._onDidEncounterLanguage.fire(languageId); + } + } + } + + let endState: StackElement; + // try to save an object if possible + if (state.equals(textMateResult.ruleStack)) { + endState = state; + } else { + endState = textMateResult.ruleStack; + + } + + return new TokenizationResult2(textMateResult.tokens, endState); + } +} diff --git a/src/vs/workbench/services/textMate/browser/textMateService.ts b/src/vs/workbench/services/textMate/browser/textMateService.ts new file mode 100644 index 000000000..37e0f9725 --- /dev/null +++ b/src/vs/workbench/services/textMate/browser/textMateService.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. + *--------------------------------------------------------------------------------------------*/ + +import { ITextMateService } from 'vs/workbench/services/textMate/common/textMateService'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { AbstractTextMateService } from 'vs/workbench/services/textMate/browser/abstractTextMateService'; +import * as vscodeTextmate from 'vscode-textmate'; +import * as onigasm from 'onigasm-umd'; +import { IModeService } from 'vs/editor/common/services/modeService'; +import { IFileService } from 'vs/platform/files/common/files'; +import { ILogService } from 'vs/platform/log/common/log'; +import { INotificationService } from 'vs/platform/notification/common/notification'; +import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IStorageService } from 'vs/platform/storage/common/storage'; + +export class TextMateService extends AbstractTextMateService { + + constructor( + @IModeService modeService: IModeService, + @IWorkbenchThemeService themeService: IWorkbenchThemeService, + @IFileService fileService: IFileService, + @INotificationService notificationService: INotificationService, + @ILogService logService: ILogService, + @IConfigurationService configurationService: IConfigurationService, + @IStorageService storageService: IStorageService + ) { + super(modeService, themeService, fileService, notificationService, logService, configurationService, storageService); + } + + protected _loadVSCodeTextmate(): Promise<typeof import('vscode-textmate')> { + return import('vscode-textmate'); + } + + protected _loadOnigLib(): Promise<vscodeTextmate.IOnigLib> | undefined { + return loadOnigasm(); + } +} + +let onigasmPromise: Promise<vscodeTextmate.IOnigLib> | null = null; +async function loadOnigasm(): Promise<vscodeTextmate.IOnigLib> { + if (!onigasmPromise) { + onigasmPromise = doLoadOnigasm(); + } + return onigasmPromise; +} + +async function doLoadOnigasm(): Promise<vscodeTextmate.IOnigLib> { + const wasmBytes = await loadOnigasmWASM(); + await onigasm.loadWASM(wasmBytes); + return { + createOnigScanner(patterns: string[]) { return new onigasm.OnigScanner(patterns); }, + createOnigString(s: string) { return new onigasm.OnigString(s); } + }; +} + +async function loadOnigasmWASM(): Promise<ArrayBuffer> { + const wasmPath = require.toUrl('onigasm-umd/../onigasm.wasm'); + const response = await fetch(wasmPath); + const bytes = await response.arrayBuffer(); + return bytes; +} + +registerSingleton(ITextMateService, TextMateService); diff --git a/src/vs/workbench/services/textMate/common/TMGrammarFactory.ts b/src/vs/workbench/services/textMate/common/TMGrammarFactory.ts new file mode 100644 index 000000000..1ea687898 --- /dev/null +++ b/src/vs/workbench/services/textMate/common/TMGrammarFactory.ts @@ -0,0 +1,147 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { URI } from 'vs/base/common/uri'; +import { LanguageId } from 'vs/editor/common/modes'; +import { IGrammar, Registry, StackElement, IRawTheme, IOnigLib } from 'vscode-textmate'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { TMScopeRegistry, IValidGrammarDefinition, IValidEmbeddedLanguagesMap } from 'vs/workbench/services/textMate/common/TMScopeRegistry'; + +interface ITMGrammarFactoryHost { + logTrace(msg: string): void; + logError(msg: string, err: any): void; + readFile(resource: URI): Promise<string>; +} + +export interface ICreateGrammarResult { + languageId: LanguageId; + grammar: IGrammar; + initialState: StackElement; + containsEmbeddedLanguages: boolean; +} + +export class TMGrammarFactory extends Disposable { + + private readonly _host: ITMGrammarFactoryHost; + private readonly _initialState: StackElement; + private readonly _scopeRegistry: TMScopeRegistry; + private readonly _injections: { [scopeName: string]: string[]; }; + private readonly _injectedEmbeddedLanguages: { [scopeName: string]: IValidEmbeddedLanguagesMap[]; }; + private readonly _languageToScope2: string[]; + private readonly _grammarRegistry: Registry; + + constructor(host: ITMGrammarFactoryHost, grammarDefinitions: IValidGrammarDefinition[], vscodeTextmate: typeof import('vscode-textmate'), onigLib: Promise<IOnigLib> | undefined) { + super(); + this._host = host; + this._initialState = vscodeTextmate.INITIAL; + this._scopeRegistry = this._register(new TMScopeRegistry()); + this._injections = {}; + this._injectedEmbeddedLanguages = {}; + this._languageToScope2 = []; + this._grammarRegistry = new vscodeTextmate.Registry({ + getOnigLib: (typeof onigLib === 'undefined' ? undefined : () => onigLib), + loadGrammar: async (scopeName: string) => { + const grammarDefinition = this._scopeRegistry.getGrammarDefinition(scopeName); + if (!grammarDefinition) { + this._host.logTrace(`No grammar found for scope ${scopeName}`); + return null; + } + const location = grammarDefinition.location; + try { + const content = await this._host.readFile(location); + return vscodeTextmate.parseRawGrammar(content, location.path); + } catch (e) { + this._host.logError(`Unable to load and parse grammar for scope ${scopeName} from ${location}`, e); + return null; + } + }, + getInjections: (scopeName: string) => { + const scopeParts = scopeName.split('.'); + let injections: string[] = []; + for (let i = 1; i <= scopeParts.length; i++) { + const subScopeName = scopeParts.slice(0, i).join('.'); + injections = [...injections, ...(this._injections[subScopeName] || [])]; + } + return injections; + } + }); + + for (const validGrammar of grammarDefinitions) { + this._scopeRegistry.register(validGrammar); + + if (validGrammar.injectTo) { + for (let injectScope of validGrammar.injectTo) { + let injections = this._injections[injectScope]; + if (!injections) { + this._injections[injectScope] = injections = []; + } + injections.push(validGrammar.scopeName); + } + + if (validGrammar.embeddedLanguages) { + for (let injectScope of validGrammar.injectTo) { + let injectedEmbeddedLanguages = this._injectedEmbeddedLanguages[injectScope]; + if (!injectedEmbeddedLanguages) { + this._injectedEmbeddedLanguages[injectScope] = injectedEmbeddedLanguages = []; + } + injectedEmbeddedLanguages.push(validGrammar.embeddedLanguages); + } + } + } + + if (validGrammar.language) { + this._languageToScope2[validGrammar.language] = validGrammar.scopeName; + } + } + } + + public has(languageId: LanguageId): boolean { + return this._languageToScope2[languageId] ? true : false; + } + + public setTheme(theme: IRawTheme): void { + this._grammarRegistry.setTheme(theme); + } + + public getColorMap(): string[] { + return this._grammarRegistry.getColorMap(); + } + + public async createGrammar(languageId: LanguageId): Promise<ICreateGrammarResult> { + const scopeName = this._languageToScope2[languageId]; + if (typeof scopeName !== 'string') { + // No TM grammar defined + return Promise.reject(new Error(nls.localize('no-tm-grammar', "No TM Grammar registered for this language."))); + } + + const grammarDefinition = this._scopeRegistry.getGrammarDefinition(scopeName); + if (!grammarDefinition) { + // No TM grammar defined + return Promise.reject(new Error(nls.localize('no-tm-grammar', "No TM Grammar registered for this language."))); + } + + let embeddedLanguages = grammarDefinition.embeddedLanguages; + if (this._injectedEmbeddedLanguages[scopeName]) { + const injectedEmbeddedLanguages = this._injectedEmbeddedLanguages[scopeName]; + for (const injected of injectedEmbeddedLanguages) { + for (const scope of Object.keys(injected)) { + embeddedLanguages[scope] = injected[scope]; + } + } + } + + const containsEmbeddedLanguages = (Object.keys(embeddedLanguages).length > 0); + + const grammar = await this._grammarRegistry.loadGrammarWithConfiguration(scopeName, languageId, { embeddedLanguages, tokenTypes: <any>grammarDefinition.tokenTypes }); + + return { + languageId: languageId, + grammar: grammar, + initialState: this._initialState, + containsEmbeddedLanguages: containsEmbeddedLanguages + }; + } +} diff --git a/src/vs/workbench/services/textMate/common/TMScopeRegistry.ts b/src/vs/workbench/services/textMate/common/TMScopeRegistry.ts new file mode 100644 index 000000000..4c352da67 --- /dev/null +++ b/src/vs/workbench/services/textMate/common/TMScopeRegistry.ts @@ -0,0 +1,58 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as resources from 'vs/base/common/resources'; +import { URI } from 'vs/base/common/uri'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { StandardTokenType, LanguageId } from 'vs/editor/common/modes'; + +export interface IValidGrammarDefinition { + location: URI; + language?: LanguageId; + scopeName: string; + embeddedLanguages: IValidEmbeddedLanguagesMap; + tokenTypes: IValidTokenTypeMap; + injectTo?: string[]; +} + +export interface IValidTokenTypeMap { + [selector: string]: StandardTokenType; +} + +export interface IValidEmbeddedLanguagesMap { + [scopeName: string]: LanguageId; +} + +export class TMScopeRegistry extends Disposable { + + private _scopeNameToLanguageRegistration: { [scopeName: string]: IValidGrammarDefinition; }; + + constructor() { + super(); + this.reset(); + } + + public reset(): void { + this._scopeNameToLanguageRegistration = Object.create(null); + } + + public register(def: IValidGrammarDefinition): void { + if (this._scopeNameToLanguageRegistration[def.scopeName]) { + const existingRegistration = this._scopeNameToLanguageRegistration[def.scopeName]; + if (!resources.isEqual(existingRegistration.location, def.location)) { + console.warn( + `Overwriting grammar scope name to file mapping for scope ${def.scopeName}.\n` + + `Old grammar file: ${existingRegistration.location.toString()}.\n` + + `New grammar file: ${def.location.toString()}` + ); + } + } + this._scopeNameToLanguageRegistration[def.scopeName] = def; + } + + public getGrammarDefinition(scopeName: string): IValidGrammarDefinition | null { + return this._scopeNameToLanguageRegistration[scopeName] || null; + } +} diff --git a/src/vs/workbench/services/textMate/electron-browser/cgmanifest.json b/src/vs/workbench/services/textMate/common/cgmanifest.json similarity index 100% rename from src/vs/workbench/services/textMate/electron-browser/cgmanifest.json rename to src/vs/workbench/services/textMate/common/cgmanifest.json diff --git a/src/vs/workbench/services/textMate/electron-browser/textMateService.ts b/src/vs/workbench/services/textMate/electron-browser/textMateService.ts index 94e175490..dc35917e9 100644 --- a/src/vs/workbench/services/textMate/electron-browser/textMateService.ts +++ b/src/vs/workbench/services/textMate/electron-browser/textMateService.ts @@ -3,513 +3,249 @@ * 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 { Color } from 'vs/base/common/color'; -import { onUnexpectedError } from 'vs/base/common/errors'; -import { Emitter, Event } from 'vs/base/common/event'; -import * as resources from 'vs/base/common/resources'; -import * as types from 'vs/base/common/types'; -import { URI } from 'vs/base/common/uri'; -import { TokenizationResult, TokenizationResult2 } from 'vs/editor/common/core/token'; -import { IState, ITokenizationSupport, LanguageId, TokenMetadata, TokenizationRegistry } from 'vs/editor/common/modes'; -import { nullTokenize2 } from 'vs/editor/common/modes/nullMode'; -import { generateTokensCSSForColorMap } from 'vs/editor/common/modes/supports/tokenization'; +import { ITextMateService } from 'vs/workbench/services/textMate/common/textMateService'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { AbstractTextMateService } from 'vs/workbench/services/textMate/browser/abstractTextMateService'; import { IModeService } from 'vs/editor/common/services/modeService'; +import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { IFileService } from 'vs/platform/files/common/files'; -import { ILogService } from 'vs/platform/log/common/log'; import { INotificationService } from 'vs/platform/notification/common/notification'; -import { ExtensionMessageCollector } from 'vs/workbench/services/extensions/common/extensionsRegistry'; -import { IEmbeddedLanguagesMap, ITMSyntaxExtensionPoint, TokenTypesContribution, grammarsExtPoint } from 'vs/workbench/services/textMate/common/TMGrammars'; -import { ITextMateService } from 'vs/workbench/services/textMate/common/textMateService'; -import { ITokenColorizationRule, IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; -import { IEmbeddedLanguagesMap as IEmbeddedLanguagesMap2, IGrammar, ITokenTypeMap, Registry, StackElement, StandardTokenType } from 'vscode-textmate'; -import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { ILogService } from 'vs/platform/log/common/log'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; - -export class TMScopeRegistry { - - private _scopeNameToLanguageRegistration: { [scopeName: string]: TMLanguageRegistration; }; - private _encounteredLanguages: boolean[]; +import { createWebWorker, MonacoWebWorker } from 'vs/editor/common/services/webWorker'; +import { IModelService } from 'vs/editor/common/services/modelService'; +import { IOnigLib, IRawTheme } from 'vscode-textmate'; +import { IValidGrammarDefinition } from 'vs/workbench/services/textMate/common/TMScopeRegistry'; +import { TextMateWorker } from 'vs/workbench/services/textMate/electron-browser/textMateWorker'; +import { ITextModel } from 'vs/editor/common/model'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { UriComponents, URI } from 'vs/base/common/uri'; +import { MultilineTokensBuilder } from 'vs/editor/common/model/tokensStore'; +import { TMGrammarFactory } from 'vs/workbench/services/textMate/common/TMGrammarFactory'; +import { IModelContentChangedEvent } from 'vs/editor/common/model/textModelEvents'; +import { IStorageService } from 'vs/platform/storage/common/storage'; + +const RUN_TEXTMATE_IN_WORKER = false; + +class ModelWorkerTextMateTokenizer extends Disposable { + + private readonly _worker: TextMateWorker; + private readonly _model: ITextModel; + private _isSynced: boolean; + private _pendingChanges: IModelContentChangedEvent[] = []; + + constructor(worker: TextMateWorker, model: ITextModel) { + super(); + this._worker = worker; + this._model = model; + this._isSynced = false; - private readonly _onDidEncounterLanguage = new Emitter<LanguageId>(); - public readonly onDidEncounterLanguage: Event<LanguageId> = this._onDidEncounterLanguage.event; + this._register(this._model.onDidChangeAttached(() => this._onDidChangeAttached())); + this._onDidChangeAttached(); - constructor() { - this.reset(); - } + this._register(this._model.onDidChangeContent((e) => { + if (this._isSynced) { + this._worker.acceptModelChanged(this._model.uri.toString(), e); + this._pendingChanges.push(e); + } + })); - public reset(): void { - this._scopeNameToLanguageRegistration = Object.create(null); - this._encounteredLanguages = []; + this._register(this._model.onDidChangeLanguage((e) => { + if (this._isSynced) { + this._worker.acceptModelLanguageChanged(this._model.uri.toString(), this._model.getLanguageIdentifier().id); + } + })); } - public register(scopeName: string, grammarLocation: URI, embeddedLanguages?: IEmbeddedLanguagesMap, tokenTypes?: TokenTypesContribution): void { - if (this._scopeNameToLanguageRegistration[scopeName]) { - const existingRegistration = this._scopeNameToLanguageRegistration[scopeName]; - if (!resources.isEqual(existingRegistration.grammarLocation, grammarLocation)) { - console.warn( - `Overwriting grammar scope name to file mapping for scope ${scopeName}.\n` + - `Old grammar file: ${existingRegistration.grammarLocation.toString()}.\n` + - `New grammar file: ${grammarLocation.toString()}` - ); + private _onDidChangeAttached(): void { + if (this._model.isAttachedToEditor()) { + if (!this._isSynced) { + this._beginSync(); + } + } else { + if (this._isSynced) { + this._endSync(); } } - this._scopeNameToLanguageRegistration[scopeName] = new TMLanguageRegistration(scopeName, grammarLocation, embeddedLanguages, tokenTypes); } - public getLanguageRegistration(scopeName: string): TMLanguageRegistration { - return this._scopeNameToLanguageRegistration[scopeName] || null; + private _beginSync(): void { + this._isSynced = true; + this._worker.acceptNewModel({ + uri: this._model.uri, + versionId: this._model.getVersionId(), + lines: this._model.getLinesContent(), + EOL: this._model.getEOL(), + languageId: this._model.getLanguageIdentifier().id, + }); } - public getGrammarLocation(scopeName: string): URI | null { - let data = this.getLanguageRegistration(scopeName); - return data ? data.grammarLocation : null; + private _endSync(): void { + this._isSynced = false; + this._worker.acceptRemovedModel(this._model.uri.toString()); } - /** - * To be called when tokenization found/hit an embedded language. - */ - public onEncounteredLanguage(languageId: LanguageId): void { - if (!this._encounteredLanguages[languageId]) { - this._encounteredLanguages[languageId] = true; - this._onDidEncounterLanguage.fire(languageId); - } + public dispose() { + super.dispose(); + this._endSync(); } -} -export class TMLanguageRegistration { - _topLevelScopeNameDataBrand: void; - - readonly scopeName: string; - readonly grammarLocation: URI; - readonly embeddedLanguages: IEmbeddedLanguagesMap; - readonly tokenTypes: ITokenTypeMap; - - constructor(scopeName: string, grammarLocation: URI, embeddedLanguages: IEmbeddedLanguagesMap | undefined, tokenTypes: TokenTypesContribution | undefined) { - this.scopeName = scopeName; - this.grammarLocation = grammarLocation; - - // embeddedLanguages handling - this.embeddedLanguages = Object.create(null); - - if (embeddedLanguages) { - // If embeddedLanguages are configured, fill in `this._embeddedLanguages` - let scopes = Object.keys(embeddedLanguages); - for (let i = 0, len = scopes.length; i < len; i++) { - let scope = scopes[i]; - let language = embeddedLanguages[scope]; - if (typeof language !== 'string') { - // never hurts to be too careful - continue; - } - this.embeddedLanguages[scope] = language; - } + private _confirm(versionId: number): void { + while (this._pendingChanges.length > 0 && this._pendingChanges[0].versionId <= versionId) { + this._pendingChanges.shift(); } + } + + public setTokens(versionId: number, rawTokens: ArrayBuffer): void { + this._confirm(versionId); + const tokens = MultilineTokensBuilder.deserialize(new Uint8Array(rawTokens)); - this.tokenTypes = Object.create(null); - if (tokenTypes) { - // If tokenTypes is configured, fill in `this._tokenTypes` - const scopes = Object.keys(tokenTypes); - for (const scope of scopes) { - const tokenType = tokenTypes[scope]; - switch (tokenType) { - case 'string': - this.tokenTypes[scope] = StandardTokenType.String; - break; - case 'other': - this.tokenTypes[scope] = StandardTokenType.Other; - break; - case 'comment': - this.tokenTypes[scope] = StandardTokenType.Comment; - break; + for (let i = 0; i < this._pendingChanges.length; i++) { + const change = this._pendingChanges[i]; + for (let j = 0; j < tokens.length; j++) { + for (let k = 0; k < change.changes.length; k++) { + tokens[j].applyEdit(change.changes[k].range, change.changes[k].text); } } } - } -} -interface ICreateGrammarResult { - languageId: LanguageId; - grammar: IGrammar; - initialState: StackElement; - containsEmbeddedLanguages: boolean; + this._model.setTokens(tokens); + } } -export class TextMateService extends Disposable implements ITextMateService { - public _serviceBrand: any; - - private readonly _onDidEncounterLanguage: Emitter<LanguageId> = this._register(new Emitter<LanguageId>()); - public readonly onDidEncounterLanguage: Event<LanguageId> = this._onDidEncounterLanguage.event; - - private readonly _styleElement: HTMLStyleElement; - private readonly _createdModes: string[]; - - private _scopeRegistry: TMScopeRegistry; - private _injections: { [scopeName: string]: string[]; }; - private _injectedEmbeddedLanguages: { [scopeName: string]: IEmbeddedLanguagesMap[]; }; - private _languageToScope: Map<string, string>; - private _grammarRegistry: Promise<[Registry, StackElement]> | null; - private _tokenizersRegistrations: IDisposable[]; - private _currentTokenColors: ITokenColorizationRule[] | null; - private _themeListener: IDisposable | null; +export class TextMateWorkerHost { constructor( - @IModeService private readonly _modeService: IModeService, - @IWorkbenchThemeService private readonly _themeService: IWorkbenchThemeService, - @IFileService private readonly _fileService: IFileService, - @INotificationService private readonly _notificationService: INotificationService, - @ILogService private readonly _logService: ILogService, - @IConfigurationService private readonly _configurationService: IConfigurationService + private readonly textMateService: TextMateService, + @IFileService private readonly _fileService: IFileService ) { - super(); - this._styleElement = dom.createStyleSheet(); - this._styleElement.className = 'vscode-tokens-styles'; - this._createdModes = []; - this._scopeRegistry = new TMScopeRegistry(); - this._scopeRegistry.onDidEncounterLanguage((language) => this._onDidEncounterLanguage.fire(language)); - this._injections = {}; - this._injectedEmbeddedLanguages = {}; - this._languageToScope = new Map<string, string>(); - this._grammarRegistry = null; - this._tokenizersRegistrations = []; - this._currentTokenColors = null; - this._themeListener = null; - - grammarsExtPoint.setHandler((extensions) => { - this._scopeRegistry.reset(); - this._injections = {}; - this._injectedEmbeddedLanguages = {}; - this._languageToScope = new Map<string, string>(); - this._grammarRegistry = null; - this._tokenizersRegistrations = dispose(this._tokenizersRegistrations); - this._currentTokenColors = null; - if (this._themeListener) { - this._themeListener.dispose(); - this._themeListener = null; - } - - for (const extension of extensions) { - let grammars = extension.value; - for (const grammar of grammars) { - this._handleGrammarExtensionPointUser(extension.description.extensionLocation, grammar, extension.collector); - } - } - - for (const createMode of this._createdModes) { - this._registerDefinitionIfAvailable(createMode); - } - }); - - // Generate some color map until the grammar registry is loaded - let colorTheme = this._themeService.getColorTheme(); - let defaultForeground: Color = Color.transparent; - let defaultBackground: Color = Color.transparent; - for (let i = 0, len = colorTheme.tokenColors.length; i < len; i++) { - let rule = colorTheme.tokenColors[i]; - if (!rule.scope && rule.settings) { - if (rule.settings.foreground) { - defaultForeground = Color.fromHex(rule.settings.foreground); - } - if (rule.settings.background) { - defaultBackground = Color.fromHex(rule.settings.background); - } - } - } - TokenizationRegistry.setColorMap([null!, defaultForeground, defaultBackground]); - - this._modeService.onDidCreateMode((mode) => { - let modeId = mode.getId(); - this._createdModes.push(modeId); - this._registerDefinitionIfAvailable(modeId); - }); } - private _registerDefinitionIfAvailable(modeId: string): void { - if (this._languageToScope.has(modeId)) { - const promise = this._createGrammar(modeId).then((r) => { - return new TMTokenization(this._scopeRegistry, r.languageId, r.grammar, r.initialState, r.containsEmbeddedLanguages, this._notificationService, this._configurationService); - }, e => { - onUnexpectedError(e); - return null; - }); - this._tokenizersRegistrations.push(TokenizationRegistry.registerPromise(modeId, promise)); - } + async readFile(_resource: UriComponents): Promise<string> { + const resource = URI.revive(_resource); + const content = await this._fileService.readFile(resource); + return content.value.toString(); } - private async _createGrammarRegistry(): Promise<[Registry, StackElement]> { - const { Registry, INITIAL, parseRawGrammar } = await import('vscode-textmate'); - const grammarRegistry = new Registry({ - loadGrammar: async (scopeName: string) => { - const location = this._scopeRegistry.getGrammarLocation(scopeName); - if (!location) { - this._logService.trace(`No grammar found for scope ${scopeName}`); - return null; - } - try { - const content = await this._fileService.readFile(location); - return parseRawGrammar(content.value.toString(), location.path); - } catch (e) { - this._logService.error(`Unable to load and parse grammar for scope ${scopeName} from ${location}`, e); - return null; - } - }, - getInjections: (scopeName: string) => { - const scopeParts = scopeName.split('.'); - let injections: string[] = []; - for (let i = 1; i <= scopeParts.length; i++) { - const subScopeName = scopeParts.slice(0, i).join('.'); - injections = [...injections, ...(this._injections[subScopeName] || [])]; - } - return injections; - } - }); - this._updateTheme(grammarRegistry); - this._themeListener = this._themeService.onDidColorThemeChange((e) => this._updateTheme(grammarRegistry)); - return <[Registry, StackElement]>[grammarRegistry, INITIAL]; + async setTokens(_resource: UriComponents, versionId: number, tokens: Uint8Array): Promise<void> { + const resource = URI.revive(_resource); + this.textMateService.setTokens(resource, versionId, tokens); } +} - private _getOrCreateGrammarRegistry(): Promise<[Registry, StackElement]> { - if (!this._grammarRegistry) { - this._grammarRegistry = this._createGrammarRegistry(); - } - return this._grammarRegistry; - } +export class TextMateService extends AbstractTextMateService { - private static _toColorMap(colorMap: string[]): Color[] { - let result: Color[] = [null!]; - for (let i = 1, len = colorMap.length; i < len; i++) { - result[i] = Color.fromHex(colorMap[i]); - } - return result; - } + private _worker: MonacoWebWorker<TextMateWorker> | null; + private _workerProxy: TextMateWorker | null; + private _tokenizers: { [uri: string]: ModelWorkerTextMateTokenizer; }; - private _updateTheme(grammarRegistry: Registry): void { - let colorTheme = this._themeService.getColorTheme(); - if (!this.compareTokenRules(colorTheme.tokenColors)) { - return; - } - grammarRegistry.setTheme({ name: colorTheme.label, settings: colorTheme.tokenColors }); - let colorMap = TextMateService._toColorMap(grammarRegistry.getColorMap()); - let cssRules = generateTokensCSSForColorMap(colorMap); - this._styleElement.innerHTML = cssRules; - TokenizationRegistry.setColorMap(colorMap); - } - - private compareTokenRules(newRules: ITokenColorizationRule[]): boolean { - let currRules = this._currentTokenColors; - this._currentTokenColors = newRules; - if (!newRules || !currRules || newRules.length !== currRules.length) { - return true; - } - for (let i = newRules.length - 1; i >= 0; i--) { - let r1 = newRules[i]; - let r2 = currRules[i]; - if (r1.scope !== r2.scope) { - return true; - } - let s1 = r1.settings; - let s2 = r2.settings; - if (s1 && s2) { - if (s1.fontStyle !== s2.fontStyle || s1.foreground !== s2.foreground || s1.background !== s2.background) { - return true; - } - } else if (!s1 || !s2) { - return true; - } - } - return false; + constructor( + @IModeService modeService: IModeService, + @IWorkbenchThemeService themeService: IWorkbenchThemeService, + @IFileService fileService: IFileService, + @INotificationService notificationService: INotificationService, + @ILogService logService: ILogService, + @IConfigurationService configurationService: IConfigurationService, + @IStorageService storageService: IStorageService, + @IModelService private readonly _modelService: IModelService, + ) { + super(modeService, themeService, fileService, notificationService, logService, configurationService, storageService); + this._worker = null; + this._workerProxy = null; + this._tokenizers = Object.create(null); + this._register(this._modelService.onModelAdded(model => this._onModelAdded(model))); + this._register(this._modelService.onModelRemoved(model => this._onModelRemoved(model))); + this._modelService.getModels().forEach((model) => this._onModelAdded(model)); } - private _handleGrammarExtensionPointUser(extensionLocation: URI, syntax: ITMSyntaxExtensionPoint, collector: ExtensionMessageCollector): void { - if (syntax.language && ((typeof syntax.language !== 'string') || !this._modeService.isRegisteredMode(syntax.language))) { - collector.error(nls.localize('invalid.language', "Unknown language in `contributes.{0}.language`. Provided value: {1}", grammarsExtPoint.name, String(syntax.language))); - return; - } - if (!syntax.scopeName || (typeof syntax.scopeName !== 'string')) { - collector.error(nls.localize('invalid.scopeName', "Expected string in `contributes.{0}.scopeName`. Provided value: {1}", grammarsExtPoint.name, String(syntax.scopeName))); - return; - } - if (!syntax.path || (typeof syntax.path !== 'string')) { - collector.error(nls.localize('invalid.path.0', "Expected string in `contributes.{0}.path`. Provided value: {1}", grammarsExtPoint.name, String(syntax.path))); - return; - } - if (syntax.injectTo && (!Array.isArray(syntax.injectTo) || syntax.injectTo.some(scope => typeof scope !== 'string'))) { - collector.error(nls.localize('invalid.injectTo', "Invalid value in `contributes.{0}.injectTo`. Must be an array of language scope names. Provided value: {1}", grammarsExtPoint.name, JSON.stringify(syntax.injectTo))); + private _onModelAdded(model: ITextModel): void { + if (!this._workerProxy) { return; } - if (syntax.embeddedLanguages && !types.isObject(syntax.embeddedLanguages)) { - collector.error(nls.localize('invalid.embeddedLanguages', "Invalid value in `contributes.{0}.embeddedLanguages`. Must be an object map from scope name to language. Provided value: {1}", grammarsExtPoint.name, JSON.stringify(syntax.embeddedLanguages))); + if (model.isTooLargeForSyncing()) { return; } + const key = model.uri.toString(); + const tokenizer = new ModelWorkerTextMateTokenizer(this._workerProxy, model); + this._tokenizers[key] = tokenizer; + } - if (syntax.tokenTypes && !types.isObject(syntax.tokenTypes)) { - collector.error(nls.localize('invalid.tokenTypes', "Invalid value in `contributes.{0}.tokenTypes`. Must be an object map from scope name to token type. Provided value: {1}", grammarsExtPoint.name, JSON.stringify(syntax.tokenTypes))); - return; - } - - const grammarLocation = resources.joinPath(extensionLocation, syntax.path); - if (!resources.isEqualOrParent(grammarLocation, extensionLocation)) { - 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.", grammarsExtPoint.name, grammarLocation.path, extensionLocation.path)); - } - - this._scopeRegistry.register(syntax.scopeName, grammarLocation, syntax.embeddedLanguages, syntax.tokenTypes); - - if (syntax.injectTo) { - for (let injectScope of syntax.injectTo) { - let injections = this._injections[injectScope]; - if (!injections) { - this._injections[injectScope] = injections = []; - } - 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; - if (modeId) { - this._languageToScope.set(modeId, syntax.scopeName); + private _onModelRemoved(model: ITextModel): void { + const key = model.uri.toString(); + if (this._tokenizers[key]) { + this._tokenizers[key].dispose(); + delete this._tokenizers[key]; } } - private _resolveEmbeddedLanguages(embeddedLanguages: IEmbeddedLanguagesMap): IEmbeddedLanguagesMap2 { - let scopes = Object.keys(embeddedLanguages); - let result: IEmbeddedLanguagesMap2 = Object.create(null); - for (let i = 0, len = scopes.length; i < len; i++) { - let scope = scopes[i]; - let language = embeddedLanguages[scope]; - let languageIdentifier = this._modeService.getLanguageIdentifier(language); - if (languageIdentifier) { - result[scope] = languageIdentifier.id; - } - } - return result; + protected _loadVSCodeTextmate(): Promise<typeof import('vscode-textmate')> { + return import('vscode-textmate'); } - public async createGrammar(modeId: string): Promise<IGrammar> { - const { grammar } = await this._createGrammar(modeId); - return grammar; + protected _loadOnigLib(): Promise<IOnigLib> | undefined { + return undefined; } - private async _createGrammar(modeId: string): Promise<ICreateGrammarResult> { - const scopeName = this._languageToScope.get(modeId); - if (typeof scopeName !== 'string') { - // No TM grammar defined - return Promise.reject(new Error(nls.localize('no-tm-grammar', "No TM Grammar registered for this language."))); - } - const languageRegistration = this._scopeRegistry.getLanguageRegistration(scopeName); - if (!languageRegistration) { - // No TM grammar defined - return Promise.reject(new Error(nls.localize('no-tm-grammar', "No TM Grammar registered for this language."))); - } - let embeddedLanguages = this._resolveEmbeddedLanguages(languageRegistration.embeddedLanguages); - let rawInjectedEmbeddedLanguages = this._injectedEmbeddedLanguages[scopeName]; - if (rawInjectedEmbeddedLanguages) { - let injectedEmbeddedLanguages: IEmbeddedLanguagesMap2[] = rawInjectedEmbeddedLanguages.map(this._resolveEmbeddedLanguages.bind(this)); - for (const injected of injectedEmbeddedLanguages) { - for (const scope of Object.keys(injected)) { - embeddedLanguages[scope] = injected[scope]; - } - } - } + protected _onDidCreateGrammarFactory(grammarDefinitions: IValidGrammarDefinition[]): void { + this._killWorker(); - let languageId = this._modeService.getLanguageIdentifier(modeId)!.id; - let containsEmbeddedLanguages = (Object.keys(embeddedLanguages).length > 0); - - const [grammarRegistry, initialState] = await this._getOrCreateGrammarRegistry(); - const grammar = await grammarRegistry.loadGrammarWithConfiguration(scopeName, languageId, { embeddedLanguages, tokenTypes: languageRegistration.tokenTypes }); - return { - languageId: languageId, - grammar: grammar, - initialState: initialState, - containsEmbeddedLanguages: containsEmbeddedLanguages - }; - } -} + if (RUN_TEXTMATE_IN_WORKER) { + const workerHost = new TextMateWorkerHost(this, this._fileService); + const worker = createWebWorker<TextMateWorker>(this._modelService, { + createData: { + grammarDefinitions + }, + label: 'textMateWorker', + moduleId: 'vs/workbench/services/textMate/electron-browser/textMateWorker', + host: workerHost + }); -class TMTokenization implements ITokenizationSupport { - - private readonly _scopeRegistry: TMScopeRegistry; - private readonly _languageId: LanguageId; - private readonly _grammar: IGrammar; - private readonly _containsEmbeddedLanguages: boolean; - private readonly _seenLanguages: boolean[]; - private readonly _initialState: StackElement; - private _maxTokenizationLineLength: number; - private _tokenizationWarningAlreadyShown: boolean; - - constructor(scopeRegistry: TMScopeRegistry, languageId: LanguageId, grammar: IGrammar, initialState: StackElement, containsEmbeddedLanguages: boolean, @INotificationService private readonly notificationService: INotificationService, @IConfigurationService readonly configurationService: IConfigurationService) { - this._scopeRegistry = scopeRegistry; - this._languageId = languageId; - this._grammar = grammar; - this._initialState = initialState; - this._containsEmbeddedLanguages = containsEmbeddedLanguages; - this._seenLanguages = []; - this._maxTokenizationLineLength = configurationService.getValue<number>('editor.maxTokenizationLineLength'); + this._worker = worker; + worker.getProxy().then((proxy) => { + if (this._worker !== worker) { + // disposed in the meantime + return; + } + this._workerProxy = proxy; + if (this._currentTheme) { + this._workerProxy.acceptTheme(this._currentTheme); + } + this._modelService.getModels().forEach((model) => this._onModelAdded(model)); + }); + } } - public getInitialState(): IState { - return this._initialState; + protected _doUpdateTheme(grammarFactory: TMGrammarFactory, theme: IRawTheme): void { + super._doUpdateTheme(grammarFactory, theme); + if (this._currentTheme && this._workerProxy) { + this._workerProxy.acceptTheme(this._currentTheme); + } } - public tokenize(line: string, state: IState, offsetDelta: number): TokenizationResult { - throw new Error('Not supported!'); + protected _onDidDisposeGrammarFactory(): void { + this._killWorker(); } - public tokenize2(line: string, state: StackElement, offsetDelta: number): TokenizationResult2 { - if (offsetDelta !== 0) { - throw new Error('Unexpected: offsetDelta should be 0.'); - } - - // Do not attempt to tokenize if a line is too long - if (line.length >= this._maxTokenizationLineLength) { - if (!this._tokenizationWarningAlreadyShown) { - this._tokenizationWarningAlreadyShown = true; - this.notificationService.warn(nls.localize('too many characters', "Tokenization is skipped for long lines for performance reasons. The length of a long line can be configured via `editor.maxTokenizationLineLength`.")); - } - console.log(`Line (${line.substr(0, 15)}...): longer than ${this._maxTokenizationLineLength} characters, tokenization skipped.`); - return nullTokenize2(this._languageId, line, state, offsetDelta); + private _killWorker(): void { + for (let key of Object.keys(this._tokenizers)) { + this._tokenizers[key].dispose(); } + this._tokenizers = Object.create(null); - let textMateResult = this._grammar.tokenizeLine2(line, state); - - if (this._containsEmbeddedLanguages) { - let seenLanguages = this._seenLanguages; - let tokens = textMateResult.tokens; - - // Must check if any of the embedded languages was hit - for (let i = 0, len = (tokens.length >>> 1); i < len; i++) { - let metadata = tokens[(i << 1) + 1]; - let languageId = TokenMetadata.getLanguageId(metadata); - - if (!seenLanguages[languageId]) { - seenLanguages[languageId] = true; - this._scopeRegistry.onEncounteredLanguage(languageId); - } - } + if (this._worker) { + this._worker.dispose(); + this._worker = null; } + this._workerProxy = null; + } - let endState: StackElement; - // try to save an object if possible - if (state.equals(textMateResult.ruleStack)) { - endState = state; - } else { - endState = textMateResult.ruleStack; - + setTokens(resource: URI, versionId: number, tokens: ArrayBuffer): void { + const key = resource.toString(); + if (!this._tokenizers[key]) { + return; } - - return new TokenizationResult2(textMateResult.tokens, endState); + this._tokenizers[key].setTokens(versionId, tokens); } } -registerSingleton(ITextMateService, TextMateService); \ No newline at end of file +registerSingleton(ITextMateService, TextMateService); diff --git a/src/vs/workbench/services/textMate/electron-browser/textMateWorker.ts b/src/vs/workbench/services/textMate/electron-browser/textMateWorker.ts new file mode 100644 index 000000000..a5c24f1d7 --- /dev/null +++ b/src/vs/workbench/services/textMate/electron-browser/textMateWorker.ts @@ -0,0 +1,196 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IWorkerContext } from 'vs/editor/common/services/editorSimpleWorker'; +import { UriComponents, URI } from 'vs/base/common/uri'; +import { LanguageId } from 'vs/editor/common/modes'; +import { IValidEmbeddedLanguagesMap, IValidTokenTypeMap, IValidGrammarDefinition } from 'vs/workbench/services/textMate/common/TMScopeRegistry'; +import { TMGrammarFactory, ICreateGrammarResult } from 'vs/workbench/services/textMate/common/TMGrammarFactory'; +import { IModelChangedEvent, MirrorTextModel } from 'vs/editor/common/model/mirrorTextModel'; +import { TextMateWorkerHost } from 'vs/workbench/services/textMate/electron-browser/textMateService'; +import { TokenizationStateStore } from 'vs/editor/common/model/textModelTokens'; +import { IGrammar, StackElement, IRawTheme } from 'vscode-textmate'; +import { MultilineTokensBuilder, countEOL } from 'vs/editor/common/model/tokensStore'; +import { LineTokens } from 'vs/editor/common/core/lineTokens'; + +export interface IValidGrammarDefinitionDTO { + location: UriComponents; + language?: LanguageId; + scopeName: string; + embeddedLanguages: IValidEmbeddedLanguagesMap; + tokenTypes: IValidTokenTypeMap; + injectTo?: string[]; +} + +export interface ICreateData { + grammarDefinitions: IValidGrammarDefinitionDTO[]; +} + +export interface IRawModelData { + uri: UriComponents; + versionId: number; + lines: string[]; + EOL: string; + languageId: LanguageId; +} + +class TextMateWorkerModel extends MirrorTextModel { + + private readonly _tokenizationStateStore: TokenizationStateStore; + private readonly _worker: TextMateWorker; + private _languageId: LanguageId; + private _grammar: IGrammar | null; + private _isDisposed: boolean; + + constructor(uri: URI, lines: string[], eol: string, versionId: number, worker: TextMateWorker, languageId: LanguageId) { + super(uri, lines, eol, versionId); + this._tokenizationStateStore = new TokenizationStateStore(); + this._worker = worker; + this._languageId = languageId; + this._isDisposed = false; + this._grammar = null; + this._resetTokenization(); + } + + public dispose(): void { + this._isDisposed = true; + super.dispose(); + } + + public onLanguageId(languageId: LanguageId): void { + this._languageId = languageId; + this._resetTokenization(); + } + + onEvents(e: IModelChangedEvent): void { + super.onEvents(e); + for (let i = 0; i < e.changes.length; i++) { + const change = e.changes[i]; + const [eolCount] = countEOL(change.text); + this._tokenizationStateStore.applyEdits(change.range, eolCount); + } + this._ensureTokens(); + } + + private _resetTokenization(): void { + this._grammar = null; + this._tokenizationStateStore.flush(null); + + const languageId = this._languageId; + this._worker.getOrCreateGrammar(languageId).then((r) => { + if (this._isDisposed || languageId !== this._languageId) { + return; + } + + this._grammar = r.grammar; + this._tokenizationStateStore.flush(r.initialState); + this._ensureTokens(); + }); + } + + private _ensureTokens(): void { + if (!this._grammar) { + return; + } + const builder = new MultilineTokensBuilder(); + const lineCount = this._lines.length; + + // Validate all states up to and including endLineIndex + for (let lineIndex = this._tokenizationStateStore.invalidLineStartIndex; lineIndex < lineCount; lineIndex++) { + const text = this._lines[lineIndex]; + const lineStartState = this._tokenizationStateStore.getBeginState(lineIndex); + + const r = this._grammar.tokenizeLine2(text, <StackElement>lineStartState!); + LineTokens.convertToEndOffset(r.tokens, text.length); + builder.add(lineIndex + 1, r.tokens); + this._tokenizationStateStore.setEndState(lineCount, lineIndex, r.ruleStack); + lineIndex = this._tokenizationStateStore.invalidLineStartIndex - 1; // -1 because the outer loop increments it + } + + this._worker._setTokens(this._uri, this._versionId, builder.serialize()); + } +} + +export class TextMateWorker { + + private readonly _host: TextMateWorkerHost; + private readonly _models: { [uri: string]: TextMateWorkerModel; }; + private readonly _grammarCache: Promise<ICreateGrammarResult>[]; + private readonly _grammarFactory: TMGrammarFactory; + + constructor(ctx: IWorkerContext<TextMateWorkerHost>, createData: ICreateData) { + this._host = ctx.host; + this._models = Object.create(null); + this._grammarCache = []; + const grammarDefinitions = createData.grammarDefinitions.map<IValidGrammarDefinition>((def) => { + return { + location: URI.revive(def.location), + language: def.language, + scopeName: def.scopeName, + embeddedLanguages: def.embeddedLanguages, + tokenTypes: def.tokenTypes, + injectTo: def.injectTo, + }; + }); + + let vscodeTextmate: typeof import('vscode-textmate'); + const globalDefine = (<any>self).define; + try { + (<any>self).define.amd = undefined; + vscodeTextmate = require.__$__nodeRequire('vscode-textmate'); + } catch (err) { + console.error(err); + return; + } finally { + (<any>self).define = globalDefine; + } + + this._grammarFactory = new TMGrammarFactory({ + logTrace: (msg: string) => {/* console.log(msg) */ }, + logError: (msg: string, err: any) => console.error(msg, err), + readFile: (resource: URI) => this._host.readFile(resource) + }, grammarDefinitions, vscodeTextmate, undefined); + } + + public acceptNewModel(data: IRawModelData): void { + const uri = URI.revive(data.uri); + const key = uri.toString(); + this._models[key] = new TextMateWorkerModel(uri, data.lines, data.EOL, data.versionId, this, data.languageId); + } + + public acceptModelChanged(strURL: string, e: IModelChangedEvent): void { + this._models[strURL].onEvents(e); + } + + public acceptModelLanguageChanged(strURL: string, newLanguageId: LanguageId): void { + this._models[strURL].onLanguageId(newLanguageId); + } + + public acceptRemovedModel(strURL: string): void { + if (this._models[strURL]) { + this._models[strURL].dispose(); + delete this._models[strURL]; + } + } + + public getOrCreateGrammar(languageId: LanguageId): Promise<ICreateGrammarResult> { + if (!this._grammarCache[languageId]) { + this._grammarCache[languageId] = this._grammarFactory.createGrammar(languageId); + } + return this._grammarCache[languageId]; + } + + public acceptTheme(theme: IRawTheme): void { + this._grammarFactory.setTheme(theme); + } + + public _setTokens(resource: URI, versionId: number, tokens: Uint8Array): void { + this._host.setTokens(resource, versionId, tokens); + } +} + +export function create(ctx: IWorkerContext<TextMateWorkerHost>, createData: ICreateData): TextMateWorker { + return new TextMateWorker(ctx, createData); +} diff --git a/src/vs/workbench/services/textfile/browser/textFileService.ts b/src/vs/workbench/services/textfile/browser/textFileService.ts index d15549e21..9f0660e40 100644 --- a/src/vs/workbench/services/textfile/browser/textFileService.ts +++ b/src/vs/workbench/services/textfile/browser/textFileService.ts @@ -6,6 +6,8 @@ import { TextFileService } from 'vs/workbench/services/textfile/common/textFileService'; import { ITextFileService, IResourceEncodings, IResourceEncoding } from 'vs/workbench/services/textfile/common/textfiles'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle'; +import { Schemas } from 'vs/base/common/network'; export class BrowserTextFileService extends TextFileService { @@ -14,6 +16,42 @@ export class BrowserTextFileService extends TextFileService { return { encoding: 'utf8', hasBOM: false }; } }; + + protected beforeShutdown(reason: ShutdownReason): boolean { + // Web: we cannot perform long running in the shutdown phase + // As such we need to check sync if there are any dirty files + // that have not been backed up yet and then prevent the shutdown + // if that is the case. + return this.doBeforeShutdownSync(reason); + } + + private doBeforeShutdownSync(reason: ShutdownReason): boolean { + const dirtyResources = this.getDirty(); + if (!dirtyResources.length) { + return false; // no dirty: no veto + } + + if (!this.isHotExitEnabled) { + return true; // dirty without backup: veto + } + + for (const dirtyResource of dirtyResources) { + let hasBackup = false; + + if (this.fileService.canHandleResource(dirtyResource)) { + const model = this.models.get(dirtyResource); + hasBackup = !!(model && model.hasBackup()); + } else if (dirtyResource.scheme === Schemas.untitled) { + hasBackup = this.untitledEditorService.hasBackup(dirtyResource); + } + + if (!hasBackup) { + return true; // dirty without backup: veto + } + } + + return false; // dirty with backups: no veto + } } registerSingleton(ITextFileService, BrowserTextFileService); \ No newline at end of file diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index ecb2e2bab..819e2a1fc 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -3,13 +3,12 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { join } from 'vs/base/common/path'; import * as nls from 'vs/nls'; import { Event, Emitter } from 'vs/base/common/event'; import { guessMimeTypes } from 'vs/base/common/mime'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import { URI } from 'vs/base/common/uri'; -import { isUndefinedOrNull, withUndefinedAsNull } from 'vs/base/common/types'; +import { isUndefinedOrNull } from 'vs/base/common/types'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ITextFileService, IAutoSaveConfiguration, ModelState, ITextFileEditorModel, ISaveOptions, ISaveErrorHandler, ISaveParticipant, StateChange, SaveReason, ITextFileStreamContent, ILoadOptions, LoadReason, IResolvedTextFileEditorModel } from 'vs/workbench/services/textfile/common/textfiles'; @@ -18,21 +17,42 @@ import { BaseTextEditorModel } from 'vs/workbench/common/editor/textEditorModel' import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { IFileService, FileOperationError, FileOperationResult, CONTENT_CHANGE_EVENT_BUFFER_DELAY, FileChangesEvent, FileChangeType, IFileStatWithMetadata, ETAG_DISABLED } from 'vs/platform/files/common/files'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IModeService, ILanguageSelection } from 'vs/editor/common/services/modeService'; +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 { RunOnceScheduler, timeout } from 'vs/base/common/async'; import { ITextBufferFactory } from 'vs/editor/common/model'; import { hash } from 'vs/base/common/hash'; -import { createTextBufferFactory } from 'vs/editor/common/model/textModel'; import { INotificationService } from 'vs/platform/notification/common/notification'; -import { isLinux } from 'vs/base/common/platform'; -import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { toDisposable, MutableDisposable } from 'vs/base/common/lifecycle'; import { ILogService } from 'vs/platform/log/common/log'; -import { isEqual, isEqualOrParent, extname, basename } from 'vs/base/common/resources'; +import { isEqual, isEqualOrParent, extname, basename, joinPath } from 'vs/base/common/resources'; import { onUnexpectedError } from 'vs/base/common/errors'; import { Schemas } from 'vs/base/common/network'; +export interface IBackupMetaData { + mtime: number; + size: number; + etag: string; + orphaned: boolean; +} + +type FileTelemetryDataFragment = { + mimeType: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + ext: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + path: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + reason?: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + whitelistedjson?: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; +}; + +type TelemetryData = { + mimeType: string; + ext: string; + path: number; + reason?: number; + whitelistedjson?: string; +}; + /** * 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. */ @@ -50,27 +70,27 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil static setSaveParticipant(handler: ISaveParticipant | null): void { TextFileEditorModel.saveParticipant = handler; } private readonly _onDidContentChange: Emitter<StateChange> = this._register(new Emitter<StateChange>()); - get onDidContentChange(): Event<StateChange> { return this._onDidContentChange.event; } + readonly onDidContentChange: Event<StateChange> = this._onDidContentChange.event; private readonly _onDidStateChange: Emitter<StateChange> = this._register(new Emitter<StateChange>()); - get onDidStateChange(): Event<StateChange> { return this._onDidStateChange.event; } + readonly onDidStateChange: Event<StateChange> = this._onDidStateChange.event; private resource: URI; - private contentEncoding: string; // encoding as reported from disk - private preferredEncoding: string; // encoding as chosen by the user + private contentEncoding: string; // encoding as reported from disk + private preferredEncoding: string; // encoding as chosen by the user + + private preferredMode: string; // mode as chosen by the user private versionId: number; private bufferSavedVersionId: number; private blockModelContentChange: boolean; - private createTextEditorModelPromise: Promise<TextFileEditorModel> | null; - - private lastResolvedDiskStat: IFileStatWithMetadata; + private lastResolvedFileStat: IFileStatWithMetadata; private autoSaveAfterMillies?: number; private autoSaveAfterMilliesEnabled: boolean; - private autoSaveDisposable?: IDisposable; + private readonly autoSaveDisposable = this._register(new MutableDisposable()); private saveSequentializer: SaveSequentializer; private lastSaveAttemptTime: number; @@ -88,6 +108,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil constructor( resource: URI, preferredEncoding: string, + preferredMode: string, @INotificationService private readonly notificationService: INotificationService, @IModeService modeService: IModeService, @IModelService modelService: IModelService, @@ -104,6 +125,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil this.resource = resource; this.preferredEncoding = preferredEncoding; + this.preferredMode = preferredMode; this.inOrphanMode = false; this.dirty = false; this.versionId = 0; @@ -136,7 +158,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } } - private onFileChanges(e: FileChangesEvent): void { + private async onFileChanges(e: FileChangesEvent): Promise<void> { let fileEventImpactsModel = false; let newInOrphanModeGuess: boolean | undefined; @@ -159,28 +181,25 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } if (fileEventImpactsModel && this.inOrphanMode !== newInOrphanModeGuess) { - let checkOrphanedPromise: Promise<boolean>; + let newInOrphanModeValidated: boolean = false; if (newInOrphanModeGuess) { // We have received reports of users seeing delete events even though the file still // exists (network shares issue: https://github.com/Microsoft/vscode/issues/13665). // Since we do not want to mark the model as orphaned, we have to check if the // file is really gone and not just a faulty file event. - checkOrphanedPromise = timeout(100).then(() => { - if (this.disposed) { - return true; - } + await timeout(100); - return this.fileService.exists(this.resource).then(exists => !exists); - }); - } else { - checkOrphanedPromise = Promise.resolve(false); + if (this.disposed) { + newInOrphanModeValidated = true; + } else { + const exists = await this.fileService.exists(this.resource); + newInOrphanModeValidated = !exists; + } } - checkOrphanedPromise.then(newInOrphanModeValidated => { - if (this.inOrphanMode !== newInOrphanModeValidated && !this.disposed) { - this.setOrphaned(newInOrphanModeValidated); - } - }); + if (this.inOrphanMode !== newInOrphanModeValidated && !this.disposed) { + this.setOrphaned(newInOrphanModeValidated); + } } } @@ -199,53 +218,73 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } private onFilesAssociationChange(): void { - if (!this.textEditorModel) { + if (!this.isResolved()) { return; } const firstLineText = this.getFirstLineText(this.textEditorModel); - const languageSelection = this.getOrCreateMode(this.modeService, undefined, firstLineText); + const languageSelection = this.getOrCreateMode(this.resource, this.modeService, this.preferredMode, firstLineText); this.modelService.setMode(this.textEditorModel, languageSelection); } - getVersionId(): number { - return this.versionId; + setMode(mode: string): void { + super.setMode(mode); + + this.preferredMode = mode; + } + + async backup(target = this.resource): Promise<void> { + if (this.isResolved()) { + + // Only fill in model metadata if resource matches + let meta: IBackupMetaData | undefined = undefined; + if (isEqual(target, this.resource) && this.lastResolvedFileStat) { + meta = { + mtime: this.lastResolvedFileStat.mtime, + size: this.lastResolvedFileStat.size, + etag: this.lastResolvedFileStat.etag, + orphaned: this.inOrphanMode + }; + } + + return this.backupFileService.backupResource<IBackupMetaData>(target, this.createSnapshot(), this.versionId, meta); + } + } + + hasBackup(): boolean { + return this.backupFileService.hasBackupSync(this.resource, this.versionId); } async revert(soft?: boolean): Promise<void> { if (!this.isResolved()) { - return Promise.resolve(undefined); + return; } // Cancel any running auto-save - this.cancelPendingAutoSave(); + this.autoSaveDisposable.clear(); // Unset flags const undo = this.setDirty(false); - let loadPromise: Promise<unknown>; - if (soft) { - loadPromise = Promise.resolve(); - } else { - loadPromise = this.load({ forceReadFromDisk: true }); - } + // Force read from disk unless reverting soft + if (!soft) { + try { + await this.load({ forceReadFromDisk: true }); + } catch (error) { - try { - await loadPromise; - - // Emit file change event - this._onDidStateChange.fire(StateChange.REVERTED); - } catch (error) { - - // Set flags back to previous values, we are still dirty if revert failed - undo(); + // Set flags back to previous values, we are still dirty if revert failed + undo(); - return Promise.reject(error); + throw error; + } } + + // Emit file change event + this._onDidStateChange.fire(StateChange.REVERTED); } - load(options?: ILoadOptions): Promise<ITextFileEditorModel> { + async load(options?: ILoadOptions): Promise<ITextFileEditorModel> { this.logService.trace('load() - enter', this.resource); // It is very important to not reload the model when the model is dirty. @@ -254,44 +293,57 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil if (this.dirty || this.saveSequentializer.hasPendingSave()) { this.logService.trace('load() - exit - without loading because model is dirty or being saved', this.resource); - return Promise.resolve(this); + return this; } // Only for new models we support to load from backup - if (!this.textEditorModel && !this.createTextEditorModelPromise) { - return this.loadFromBackup(options); + if (!this.isResolved()) { + const backup = await this.backupFileService.loadBackupResource(this.resource); + + if (this.isResolved()) { + return this; // Make sure meanwhile someone else did not suceed in loading + } + + if (backup) { + try { + return await this.loadFromBackup(backup, options); + } catch (error) { + // ignore error and continue to load as file below + } + } } // Otherwise load from file resource return this.loadFromFile(options); } - private async loadFromBackup(options?: ILoadOptions): Promise<TextFileEditorModel> { - const backup = await this.backupFileService.loadBackupResource(this.resource); + private async loadFromBackup(backup: URI, options?: ILoadOptions): Promise<TextFileEditorModel> { - // Make sure meanwhile someone else did not suceed or start loading - if (this.createTextEditorModelPromise || this.textEditorModel) { - return this.createTextEditorModelPromise || this; - } + // Resolve actual backup contents + const resolvedBackup = await this.backupFileService.resolveBackupContent<IBackupMetaData>(backup); - // If we have a backup, continue loading with it - if (!!backup) { - const content: ITextFileStreamContent = { - resource: this.resource, - name: basename(this.resource), - mtime: Date.now(), - size: 0, - etag: ETAG_DISABLED, // always allow to save content restored from a backup (see https://github.com/Microsoft/vscode/issues/72343) - value: createTextBufferFactory(''), // will be filled later from backup - encoding: this.textFileService.encoding.getPreferredWriteEncoding(this.resource, this.preferredEncoding).encoding, - isReadonly: false - }; + if (this.isResolved()) { + return this; // Make sure meanwhile someone else did not suceed in loading + } - return this.loadWithContent(content, options, backup); + // Load with backup + this.loadFromContent({ + resource: this.resource, + name: basename(this.resource), + mtime: resolvedBackup.meta ? resolvedBackup.meta.mtime : Date.now(), + size: resolvedBackup.meta ? resolvedBackup.meta.size : 0, + etag: resolvedBackup.meta ? resolvedBackup.meta.etag : ETAG_DISABLED, // etag disabled if unknown! + value: resolvedBackup.value, + encoding: this.textFileService.encoding.getPreferredWriteEncoding(this.resource, this.preferredEncoding).encoding, + isReadonly: false + }, options, true /* from backup */); + + // Restore orphaned flag based on state + if (resolvedBackup.meta && resolvedBackup.meta.orphaned) { + this.setOrphaned(true); } - // Otherwise load from file - return this.loadFromFile(options); + return this; } private async loadFromFile(options?: ILoadOptions): Promise<TextFileEditorModel> { @@ -302,8 +354,8 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil let etag: string | undefined; if (forceReadFromDisk) { etag = ETAG_DISABLED; // disable ETag if we enforce to read from disk - } else if (this.lastResolvedDiskStat) { - etag = this.lastResolvedDiskStat.etag; // otherwise respect etag to support caching + } else if (this.lastResolvedFileStat) { + etag = this.lastResolvedFileStat.etag; // otherwise respect etag to support caching } // Ensure to track the versionId before doing a long running operation @@ -321,12 +373,11 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // Clear orphaned state when loading was successful this.setOrphaned(false); - // Guard against the model having changed in the meantime - if (currentVersionId === this.versionId) { - return this.loadWithContent(content, options); + if (currentVersionId !== this.versionId) { + return this; // Make sure meanwhile someone else did not suceed loading } - return this; + return this.loadFromContent(content, options); } catch (error) { const result = error.fileOperationResult; @@ -356,37 +407,11 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } } - private async loadWithContent(content: ITextFileStreamContent, options?: ILoadOptions, backup?: URI): Promise<TextFileEditorModel> { - const model = await this.doLoadWithContent(content, backup); - - // Telemetry: We log the fileGet telemetry event after the model has been loaded to ensure a good mimetype - const settingsType = this.getTypeIfSettings(); - if (settingsType) { - /* __GDPR__ - "settingsRead" : { - "settingsType": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } - } - */ - this.telemetryService.publicLog('settingsRead', { settingsType }); // 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" : { - "${include}": [ - "${FileTelemetryData}" - ] - } - */ - this.telemetryService.publicLog('fileGet', this.getTelemetryData(options && options.reason ? options.reason : LoadReason.OTHER)); - } - - return model; - } - - private doLoadWithContent(content: ITextFileStreamContent, backup?: URI): Promise<TextFileEditorModel> { + private loadFromContent(content: ITextFileStreamContent, options?: ILoadOptions, fromBackup?: boolean): TextFileEditorModel { this.logService.trace('load() - resolved content', this.resource); // Update our resolved disk stat model - this.updateLastResolvedDiskStat({ + this.updateLastResolvedFileStat({ resource: this.resource, name: content.name, mtime: content.mtime, @@ -409,21 +434,55 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } // Update Existing Model - if (this.textEditorModel) { + if (this.isResolved()) { this.doUpdateTextModel(content.value); + } + + // Create New Model + else { + this.doCreateTextModel(content.resource, content.value, !!fromBackup); + } + + // Telemetry: We log the fileGet telemetry event after the model has been loaded to ensure a good mimetype + const settingsType = this.getTypeIfSettings(); + if (settingsType) { + type SettingsReadClassification = { + settingsType: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + }; + + this.telemetryService.publicLog2<{ settingsType: string }, SettingsReadClassification>('settingsRead', { settingsType }); // Do not log read to user settings.json and .vscode folder as a fileGet event as it ruins our JSON usage data + } else { + type FileGetClassification = {} & FileTelemetryDataFragment; - return Promise.resolve(this); + this.telemetryService.publicLog2<TelemetryData, FileGetClassification>('fileGet', this.getTelemetryData(options && options.reason ? options.reason : LoadReason.OTHER)); } - // Join an existing request to create the editor model to avoid race conditions - else if (this.createTextEditorModelPromise) { - this.logService.trace('load() - join existing text editor model promise', this.resource); + return this; + } + + private doCreateTextModel(resource: URI, value: ITextBufferFactory, fromBackup: boolean): void { + this.logService.trace('load() - created text editor model', this.resource); - return this.createTextEditorModelPromise; + // Create model + this.createTextEditorModel(value, resource, this.preferredMode); + + // We restored a backup so we have to set the model as being dirty + // We also want to trigger auto save if it is enabled to simulate the exact same behaviour + // you would get if manually making the model dirty (fixes https://github.com/Microsoft/vscode/issues/16977) + if (fromBackup) { + this.makeDirty(); + if (this.autoSaveAfterMilliesEnabled) { + this.doAutoSave(this.versionId); + } } - // Create New Model - return this.doCreateTextModel(content.resource, content.value, backup); + // Ensure we are not tracking a stale state + else { + this.setDirty(false); + } + + // Model Listeners + this.installModelListeners(); } private doUpdateTextModel(value: ITextBufferFactory): void { @@ -435,7 +494,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // Update model value in a block that ignores model content change events this.blockModelContentChange = true; try { - this.updateTextEditorModel(value); + this.updateTextEditorModel(value, this.preferredMode); } finally { this.blockModelContentChange = false; } @@ -444,44 +503,6 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil this.updateSavedVersionId(); } - private doCreateTextModel(resource: URI, value: ITextBufferFactory, backup: URI | undefined): Promise<TextFileEditorModel> { - this.logService.trace('load() - created text editor model', this.resource); - - this.createTextEditorModelPromise = this.doLoadBackup(backup).then(backupContent => { - this.createTextEditorModelPromise = null; - - // Create model - const hasBackupContent = !!backupContent; - this.createTextEditorModel(backupContent ? backupContent : value, resource); - - // We restored a backup so we have to set the model as being dirty - // We also want to trigger auto save if it is enabled to simulate the exact same behaviour - // you would get if manually making the model dirty (fixes https://github.com/Microsoft/vscode/issues/16977) - if (hasBackupContent) { - this.makeDirty(); - if (this.autoSaveAfterMilliesEnabled) { - this.doAutoSave(this.versionId); - } - } - - // Ensure we are not tracking a stale state - else { - this.setDirty(false); - } - - // Model Listeners - this.installModelListeners(); - - return this; - }, error => { - this.createTextEditorModelPromise = null; - - return Promise.reject<TextFileEditorModel>(error); - }); - - return this.createTextEditorModelPromise; - } - private installModelListeners(): void { // See https://github.com/Microsoft/vscode/issues/30189 @@ -489,27 +510,11 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // where `value` was captured in the content change listener closure scope. // Content Change - if (this.textEditorModel) { + if (this.isResolved()) { this._register(this.textEditorModel.onDidChangeContent(() => this.onModelContentChanged())); } } - private async doLoadBackup(backup: URI | undefined): Promise<ITextBufferFactory | null> { - if (!backup) { - return null; - } - - try { - return withUndefinedAsNull(await this.backupFileService.resolveBackupContent(backup)); - } catch (error) { - return null; // ignore errors - } - } - - protected getOrCreateMode(modeService: IModeService, preferredModeIds: string | undefined, firstLineText?: string): ILanguageSelection { - return modeService.createByFilepathOrFirstLine(this.resource.fsPath, firstLineText); - } - private onModelContentChanged(): void { this.logService.trace(`onModelContentChanged() - enter`, this.resource); @@ -526,7 +531,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // In this case we clear the dirty flag and emit a SAVED event to indicate this state. // Note: we currently only do this check when auto-save is turned off because there you see // a dirty indicator that you want to get rid of when undoing to the saved version. - if (!this.autoSaveAfterMilliesEnabled && this.textEditorModel && this.textEditorModel.getAlternativeVersionId() === this.bufferSavedVersionId) { + if (!this.autoSaveAfterMilliesEnabled && this.isResolved() && this.textEditorModel.getAlternativeVersionId() === this.bufferSavedVersionId) { this.logService.trace('onModelContentChanged() - model content changed back to last saved version', this.resource); // Clear flags @@ -575,7 +580,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil this.logService.trace(`doAutoSave() - enter for versionId ${versionId}`, this.resource); // Cancel any currently running auto saves to make this the one that succeeds - this.cancelPendingAutoSave(); + this.autoSaveDisposable.clear(); // Create new save timer and store it for disposal as needed const handle = setTimeout(() => { @@ -586,25 +591,18 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } }, this.autoSaveAfterMillies); - this.autoSaveDisposable = toDisposable(() => clearTimeout(handle)); - } - - private cancelPendingAutoSave(): void { - if (this.autoSaveDisposable) { - this.autoSaveDisposable.dispose(); - this.autoSaveDisposable = undefined; - } + this.autoSaveDisposable.value = toDisposable(() => clearTimeout(handle)); } - save(options: ISaveOptions = Object.create(null)): Promise<void> { + async save(options: ISaveOptions = Object.create(null)): Promise<void> { if (!this.isResolved()) { - return Promise.resolve(undefined); + return; } this.logService.trace('save() - enter', this.resource); // Cancel any currently running auto saves to make this the one that succeeds - this.cancelPendingAutoSave(); + this.autoSaveDisposable.clear(); return this.doSave(this.versionId, options); } @@ -624,7 +622,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil if (this.saveSequentializer.hasPendingSave(versionId)) { this.logService.trace(`doSave(${versionId}) - exit - found a pending save for versionId ${versionId}`, this.resource); - return this.saveSequentializer.pendingSave || Promise.resolve(undefined); + return this.saveSequentializer.pendingSave || Promise.resolve(); } // Return early if not dirty (unless forced) or version changed meanwhile @@ -637,7 +635,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil if ((!options.force && !this.dirty) || versionId !== this.versionId) { this.logService.trace(`doSave(${versionId}) - exit - because not dirty and/or versionId is different (this.isDirty: ${this.dirty}, this.versionId: ${this.versionId})`, this.resource); - return Promise.resolve(undefined); + return Promise.resolve(); } // Return if currently saving by storing this save request as the next save that should happen. @@ -657,7 +655,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // Push all edit operations to the undo stack so that the user has a chance to // Ctrl+Z back to the saved version. We only do this when auto-save is turned off - if (!this.autoSaveAfterMilliesEnabled && this.textEditorModel) { + if (!this.autoSaveAfterMilliesEnabled && this.isResolved()) { this.textEditorModel.pushStackElement(); } @@ -687,7 +685,12 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // saving contents to disk that are stale (see https://github.com/Microsoft/vscode/issues/50942). // To fix this issue, we will not store the contents to disk when we got disposed. if (this.disposed) { - return undefined; + return; + } + + // We require a resolved model from this point on, since we are about to write data to disk. + if (!this.isResolved()) { + return; } // Under certain conditions we do a short-cut of flushing contents to disk when we can assume that @@ -713,16 +716,12 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // Save to Disk // mark the save operation as currently pending with the versionId (it might have changed from a save participant triggering) this.logService.trace(`doSave(${versionId}) - before write()`, this.resource); - const snapshot = this.createSnapshot(); - if (!snapshot) { - throw new Error('Invalid snapshot'); - } - return this.saveSequentializer.setPending(newVersionId, this.textFileService.write(this.lastResolvedDiskStat.resource, snapshot, { + return this.saveSequentializer.setPending(newVersionId, this.textFileService.write(this.lastResolvedFileStat.resource, this.createSnapshot(), { overwriteReadonly: options.overwriteReadonly, overwriteEncoding: options.overwriteEncoding, - mtime: this.lastResolvedDiskStat.mtime, + mtime: this.lastResolvedFileStat.mtime, encoding: this.getEncoding(), - etag: this.lastResolvedDiskStat.etag, + etag: this.lastResolvedFileStat.etag, writeElevated: options.writeElevated }).then(stat => { this.logService.trace(`doSave(${versionId}) - after write()`, this.resource); @@ -736,7 +735,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } // Updated resolved stat with updated stat - this.updateLastResolvedDiskStat(stat); + this.updateLastResolvedFileStat(stat); // Cancel any content change event promises as they are no longer valid this.contentChangeEventScheduler.cancel(); @@ -747,21 +746,13 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // Telemetry const settingsType = this.getTypeIfSettings(); if (settingsType) { - /* __GDPR__ - "settingsWritten" : { - "settingsType": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } - } - */ - this.telemetryService.publicLog('settingsWritten', { settingsType }); // Do not log write to user settings.json and .vscode folder as a filePUT event as it ruins our JSON usage data + type SettingsWrittenClassification = { + settingsType: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + }; + this.telemetryService.publicLog2<{ settingsType: string }, SettingsWrittenClassification>('settingsWritten', { settingsType }); // 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" : { - "${include}": [ - "${FileTelemetryData}" - ] - } - */ - this.telemetryService.publicLog('filePUT', this.getTelemetryData(options.reason)); + type FilePutClassfication = {} & FileTelemetryDataFragment; + this.telemetryService.publicLog2<TelemetryData, FilePutClassfication>('filePUT', this.getTelemetryData(options.reason)); } }, error => { this.logService.error(`doSave(${versionId}) - exit - resulted in a save error: ${error.toString()}`, this.resource); @@ -789,22 +780,22 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } // Check for global settings file - if (isEqual(this.resource, URI.file(this.environmentService.appSettingsPath), !isLinux)) { + if (isEqual(this.resource, this.environmentService.settingsResource)) { return 'global-settings'; } // Check for keybindings file - if (isEqual(this.resource, URI.file(this.environmentService.appKeybindingsPath), !isLinux)) { + if (isEqual(this.resource, this.environmentService.keybindingsResource)) { return 'keybindings'; } // Check for locale file - if (isEqual(this.resource, URI.file(join(this.environmentService.appSettingsHome, 'locale.json')), !isLinux)) { + if (isEqual(this.resource, joinPath(this.environmentService.userRoamingDataHome, 'locale.json'))) { return 'locale'; } // Check for snippets - if (isEqualOrParent(this.resource, URI.file(join(this.environmentService.appSettingsHome, 'snippets')))) { + if (isEqualOrParent(this.resource, joinPath(this.environmentService.userRoamingDataHome, 'snippets'))) { return 'snippets'; } @@ -822,47 +813,42 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil return ''; } - private getTelemetryData(reason: number | undefined): object { + private getTelemetryData(reason: number | undefined): TelemetryData { const ext = extname(this.resource); const fileName = basename(this.resource); const path = this.resource.scheme === Schemas.file ? this.resource.fsPath : this.resource.path; const telemetryData = { - mimeType: guessMimeTypes(path).join(', '), + mimeType: guessMimeTypes(this.resource).join(', '), ext, path: hash(path), - reason + reason, + whitelistedjson: undefined as string | undefined }; if (ext === '.json' && TextFileEditorModel.WHITELIST_JSON.indexOf(fileName) > -1) { telemetryData['whitelistedjson'] = fileName; } - /* __GDPR__FRAGMENT__ - "FileTelemetryData" : { - "mimeType" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "ext": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "path": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "reason": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "whitelistedjson": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } - } - */ return telemetryData; } private doTouch(versionId: number): Promise<void> { - const snapshot = this.createSnapshot(); - if (!snapshot) { - throw new Error('invalid snapshot'); + if (!this.isResolved()) { + return Promise.resolve(); } - return this.saveSequentializer.setPending(versionId, this.textFileService.write(this.lastResolvedDiskStat.resource, snapshot, { - mtime: this.lastResolvedDiskStat.mtime, + return this.saveSequentializer.setPending(versionId, this.textFileService.write(this.lastResolvedFileStat.resource, this.createSnapshot(), { + mtime: this.lastResolvedFileStat.mtime, encoding: this.getEncoding(), - etag: this.lastResolvedDiskStat.etag + etag: this.lastResolvedFileStat.etag }).then(stat => { // Updated resolved stat with updated stat since touching it might have changed mtime - this.updateLastResolvedDiskStat(stat); + this.updateLastResolvedFileStat(stat); + + // Emit File Saved Event + this._onDidStateChange.fire(StateChange.SAVED); + }, error => onUnexpectedError(error) /* just log any error but do not notify the user since the file was not dirty */)); } @@ -896,23 +882,23 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // in order to find out if the model changed back to a saved version (e.g. // when undoing long enough to reach to a version that is saved and then to // clear the dirty flag) - if (this.textEditorModel) { + if (this.isResolved()) { this.bufferSavedVersionId = this.textEditorModel.getAlternativeVersionId(); } } - private updateLastResolvedDiskStat(newVersionOnDiskStat: IFileStatWithMetadata): void { + private updateLastResolvedFileStat(newFileStat: IFileStatWithMetadata): void { // First resolve - just take - if (!this.lastResolvedDiskStat) { - this.lastResolvedDiskStat = newVersionOnDiskStat; + if (!this.lastResolvedFileStat) { + this.lastResolvedFileStat = newFileStat; } // Subsequent resolve - make sure that we only assign it if the mtime is equal or has advanced. // This prevents race conditions from loading and saving. If a save comes in late after a revert // was called, the mtime could be out of sync. - else if (this.lastResolvedDiskStat.mtime <= newVersionOnDiskStat.mtime) { - this.lastResolvedDiskStat = newVersionOnDiskStat; + else if (this.lastResolvedFileStat.mtime <= newFileStat.mtime) { + this.lastResolvedFileStat = newFileStat; } } @@ -935,10 +921,6 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil return this.lastSaveAttemptTime; } - getETag(): string | null { - return this.lastResolvedDiskStat ? this.lastResolvedDiskStat.etag || null : null; - } - hasState(state: ModelState): boolean { switch (state) { case ModelState.CONFLICT: @@ -1020,12 +1002,12 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil return true; } - isResolved(): boolean { - return !isUndefinedOrNull(this.lastResolvedDiskStat); + isResolved(): this is IResolvedTextFileEditorModel { + return !!this.textEditorModel; } isReadonly(): boolean { - return !!(this.lastResolvedDiskStat && this.lastResolvedDiskStat.isReadonly); + return !!(this.lastResolvedFileStat && this.lastResolvedFileStat.isReadonly); } isDisposed(): boolean { @@ -1037,7 +1019,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } getStat(): IFileStatWithMetadata { - return this.lastResolvedDiskStat; + return this.lastResolvedFileStat; } dispose(): void { @@ -1046,10 +1028,6 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil this.inOrphanMode = false; this.inErrorMode = false; - this.createTextEditorModelPromise = null; - - this.cancelPendingAutoSave(); - super.dispose(); } } diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts b/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts index 1baca9352..8afe2d467 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModelManager.ts @@ -15,28 +15,28 @@ import { ResourceMap } from 'vs/base/common/map'; export class TextFileEditorModelManager extends Disposable implements ITextFileEditorModelManager { private readonly _onModelDisposed: Emitter<URI> = this._register(new Emitter<URI>()); - get onModelDisposed(): Event<URI> { return this._onModelDisposed.event; } + readonly onModelDisposed: Event<URI> = this._onModelDisposed.event; private readonly _onModelContentChanged: Emitter<TextFileModelChangeEvent> = this._register(new Emitter<TextFileModelChangeEvent>()); - get onModelContentChanged(): Event<TextFileModelChangeEvent> { return this._onModelContentChanged.event; } + readonly onModelContentChanged: Event<TextFileModelChangeEvent> = this._onModelContentChanged.event; private readonly _onModelDirty: Emitter<TextFileModelChangeEvent> = this._register(new Emitter<TextFileModelChangeEvent>()); - get onModelDirty(): Event<TextFileModelChangeEvent> { return this._onModelDirty.event; } + readonly onModelDirty: Event<TextFileModelChangeEvent> = this._onModelDirty.event; private readonly _onModelSaveError: Emitter<TextFileModelChangeEvent> = this._register(new Emitter<TextFileModelChangeEvent>()); - get onModelSaveError(): Event<TextFileModelChangeEvent> { return this._onModelSaveError.event; } + readonly onModelSaveError: Event<TextFileModelChangeEvent> = this._onModelSaveError.event; private readonly _onModelSaved: Emitter<TextFileModelChangeEvent> = this._register(new Emitter<TextFileModelChangeEvent>()); - get onModelSaved(): Event<TextFileModelChangeEvent> { return this._onModelSaved.event; } + readonly onModelSaved: Event<TextFileModelChangeEvent> = this._onModelSaved.event; private readonly _onModelReverted: Emitter<TextFileModelChangeEvent> = this._register(new Emitter<TextFileModelChangeEvent>()); - get onModelReverted(): Event<TextFileModelChangeEvent> { return this._onModelReverted.event; } + readonly onModelReverted: Event<TextFileModelChangeEvent> = this._onModelReverted.event; private readonly _onModelEncodingChanged: Emitter<TextFileModelChangeEvent> = this._register(new Emitter<TextFileModelChangeEvent>()); - get onModelEncodingChanged(): Event<TextFileModelChangeEvent> { return this._onModelEncodingChanged.event; } + readonly onModelEncodingChanged: Event<TextFileModelChangeEvent> = this._onModelEncodingChanged.event; private readonly _onModelOrphanedChanged: Emitter<TextFileModelChangeEvent> = this._register(new Emitter<TextFileModelChangeEvent>()); - get onModelOrphanedChanged(): Event<TextFileModelChangeEvent> { return this._onModelOrphanedChanged.event; } + readonly onModelOrphanedChanged: Event<TextFileModelChangeEvent> = this._onModelOrphanedChanged.event; private _onModelsDirtyEvent: Event<TextFileModelChangeEvent[]>; private _onModelsSaveError: Event<TextFileModelChangeEvent[]>; @@ -153,7 +153,7 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE // Model does not exist else { - const newModel = model = this.instantiationService.createInstance(TextFileEditorModel, resource, options ? options.encoding : undefined); + const newModel = model = this.instantiationService.createInstance(TextFileEditorModel, resource, options ? options.encoding : undefined, options ? options.mode : undefined); modelPromise = model.load(options); // Install state change listener @@ -204,6 +204,11 @@ export class TextFileEditorModelManager extends Disposable implements ITextFileE // Remove from pending loads this.mapResourceToPendingModelLoaders.delete(resource); + // Apply mode if provided + if (options && options.mode) { + resolvedModel.setMode(options.mode); + } + return resolvedModel; } catch (error) { diff --git a/src/vs/workbench/services/textfile/common/textFileService.ts b/src/vs/workbench/services/textfile/common/textFileService.ts index 1c513e1bc..33870009b 100644 --- a/src/vs/workbench/services/textfile/common/textFileService.ts +++ b/src/vs/workbench/services/textfile/common/textFileService.ts @@ -31,7 +31,6 @@ import { createTextBufferFactoryFromSnapshot, createTextBufferFactoryFromStream import { IModelService } from 'vs/editor/common/services/modelService'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { isEqualOrParent, isEqual, joinPath, dirname, extname, basename, toLocalResource } from 'vs/base/common/resources'; -import { posix } from 'vs/base/common/path'; import { getConfirmMessage, IDialogService, IFileDialogService, ISaveDialogOptions, IConfirmation } from 'vs/platform/dialogs/common/dialogs'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -40,6 +39,7 @@ import { trim } from 'vs/base/common/strings'; import { VSBuffer } from 'vs/base/common/buffer'; import { ITextSnapshot } from 'vs/editor/common/model'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; +import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; /** * The workbench file service implementation implements the raw file service spec and adds additional methods on top. @@ -49,13 +49,13 @@ export abstract class TextFileService extends Disposable implements ITextFileSer _serviceBrand: ServiceIdentifier<any>; private readonly _onAutoSaveConfigurationChange: Emitter<IAutoSaveConfiguration> = this._register(new Emitter<IAutoSaveConfiguration>()); - get onAutoSaveConfigurationChange(): Event<IAutoSaveConfiguration> { return this._onAutoSaveConfigurationChange.event; } + readonly onAutoSaveConfigurationChange: Event<IAutoSaveConfiguration> = this._onAutoSaveConfigurationChange.event; private readonly _onFilesAssociationChange: Emitter<void> = this._register(new Emitter<void>()); - get onFilesAssociationChange(): Event<void> { return this._onFilesAssociationChange.event; } + readonly onFilesAssociationChange: Event<void> = this._onFilesAssociationChange.event; private readonly _onWillMove = this._register(new Emitter<IWillMoveEvent>()); - get onWillMove(): Event<IWillMoveEvent> { return this._onWillMove.event; } + readonly onWillMove: Event<IWillMoveEvent> = this._onWillMove.event; private _models: TextFileEditorModelManager; get models(): ITextFileEditorModelManager { return this._models; } @@ -72,7 +72,7 @@ export abstract class TextFileService extends Disposable implements ITextFileSer constructor( @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @IFileService protected readonly fileService: IFileService, - @IUntitledEditorService private readonly untitledEditorService: IUntitledEditorService, + @IUntitledEditorService protected readonly untitledEditorService: IUntitledEditorService, @ILifecycleService private readonly lifecycleService: ILifecycleService, @IInstantiationService protected instantiationService: IInstantiationService, @IConfigurationService private readonly configurationService: IConfigurationService, @@ -118,7 +118,7 @@ export abstract class TextFileService extends Disposable implements ITextFileSer })); } - private beforeShutdown(reason: ShutdownReason): boolean | Promise<boolean> { + protected beforeShutdown(reason: ShutdownReason): boolean | Promise<boolean> { // Dirty files need treatment on shutdown const dirty = this.getDirty(); @@ -151,7 +151,7 @@ export abstract class TextFileService extends Disposable implements ITextFileSer // If hot exit is enabled, backup dirty files and allow to exit without confirmation if (this.isHotExitEnabled) { - return this.backupBeforeShutdown(dirty, this.models, reason).then(didBackup => { + return this.backupBeforeShutdown(dirty, reason).then(didBackup => { if (didBackup) { return this.noVeto({ cleanUpBackups: false }); // no veto and no backup cleanup (since backup was successful) } @@ -170,7 +170,7 @@ export abstract class TextFileService extends Disposable implements ITextFileSer return this.confirmBeforeShutdown(); } - private async backupBeforeShutdown(dirtyToBackup: URI[], textFileEditorModelManager: ITextFileEditorModelManager, reason: ShutdownReason): Promise<boolean> { + private async backupBeforeShutdown(dirtyToBackup: URI[], reason: ShutdownReason): Promise<boolean> { const windowCount = await this.windowsService.getWindowCount(); // When quit is requested skip the confirm callback and attempt to backup all workspaces. @@ -211,24 +211,24 @@ export abstract class TextFileService extends Disposable implements ITextFileSer return false; } - await this.backupAll(dirtyToBackup, textFileEditorModelManager); + await this.backupAll(dirtyToBackup); return true; } - private backupAll(dirtyToBackup: URI[], textFileEditorModelManager: ITextFileEditorModelManager): Promise<void> { + private backupAll(dirtyToBackup: URI[]): Promise<void> { // split up between files and untitled const filesToBackup: ITextFileEditorModel[] = []; const untitledToBackup: URI[] = []; - dirtyToBackup.forEach(s => { - if (this.fileService.canHandleResource(s)) { - const model = textFileEditorModelManager.get(s); + dirtyToBackup.forEach(dirty => { + if (this.fileService.canHandleResource(dirty)) { + const model = this.models.get(dirty); if (model) { filesToBackup.push(model); } - } else if (s.scheme === Schemas.untitled) { - untitledToBackup.push(s); + } else if (dirty.scheme === Schemas.untitled) { + untitledToBackup.push(dirty); } }); @@ -238,59 +238,44 @@ export abstract class TextFileService extends Disposable implements ITextFileSer private async doBackupAll(dirtyFileModels: ITextFileEditorModel[], untitledResources: URI[]): Promise<void> { // Handle file resources first - await Promise.all(dirtyFileModels.map(async model => { - const snapshot = model.createSnapshot(); - if (snapshot) { - await this.backupFileService.backupResource(model.getResource(), snapshot, model.getVersionId()); - } - })); + await Promise.all(dirtyFileModels.map(model => model.backup())); // Handle untitled resources - const untitledModelPromises = untitledResources + await Promise.all(untitledResources .filter(untitled => this.untitledEditorService.exists(untitled)) - .map(untitled => this.untitledEditorService.loadOrCreate({ resource: untitled })); - - const untitledModels = await Promise.all(untitledModelPromises); - - await Promise.all(untitledModels.map(async model => { - const snapshot = model.createSnapshot(); - if (snapshot) { - await this.backupFileService.backupResource(model.getResource(), snapshot, model.getVersionId()); - } - })); + .map(async untitled => (await this.untitledEditorService.loadOrCreate({ resource: untitled })).backup())); } - private confirmBeforeShutdown(): boolean | Promise<boolean> { - return this.confirmSave().then(confirm => { + private async confirmBeforeShutdown(): Promise<boolean> { + const confirm = await this.confirmSave(); - // Save - if (confirm === ConfirmResult.SAVE) { - return this.saveAll(true /* includeUntitled */, { skipSaveParticipants: true }).then(result => { - if (result.results.some(r => !r.success)) { - return true; // veto if some saves failed - } + // Save + if (confirm === ConfirmResult.SAVE) { + const result = await this.saveAll(true /* includeUntitled */, { skipSaveParticipants: true }); - return this.noVeto({ cleanUpBackups: true }); - }); + if (result.results.some(r => !r.success)) { + return true; // veto if some saves failed } - // Don't Save - else if (confirm === ConfirmResult.DONT_SAVE) { + return this.noVeto({ cleanUpBackups: true }); + } - // Make sure to revert untitled so that they do not restore - // see https://github.com/Microsoft/vscode/issues/29572 - this.untitledEditorService.revertAll(); + // Don't Save + else if (confirm === ConfirmResult.DONT_SAVE) { - return this.noVeto({ cleanUpBackups: true }); - } + // Make sure to revert untitled so that they do not restore + // see https://github.com/Microsoft/vscode/issues/29572 + this.untitledEditorService.revertAll(); - // Cancel - else if (confirm === ConfirmResult.CANCEL) { - return true; // veto - } + return this.noVeto({ cleanUpBackups: true }); + } - return false; - }); + // Cancel + else if (confirm === ConfirmResult.CANCEL) { + return true; // veto + } + + return false; } private noVeto(options: { cleanUpBackups: boolean }): boolean | Promise<boolean> { @@ -450,14 +435,14 @@ export abstract class TextFileService extends Disposable implements ITextFileSer } async delete(resource: URI, options?: { useTrash?: boolean, recursive?: boolean }): Promise<void> { - const dirtyFiles = this.getDirty().filter(dirty => isEqualOrParent(dirty, resource, !platform.isLinux /* ignorecase */)); + const dirtyFiles = this.getDirty().filter(dirty => isEqualOrParent(dirty, resource)); await this.revertAll(dirtyFiles, { soft: true }); return this.fileService.del(resource, options); } - async move(source: URI, target: URI, overwrite?: boolean): Promise<void> { + async move(source: URI, target: URI, overwrite?: boolean): Promise<IFileStatWithMetadata> { const waitForPromises: Promise<unknown>[] = []; // Event @@ -481,7 +466,7 @@ export abstract class TextFileService extends Disposable implements ITextFileSer } // Handle dirty source models if existing (if source URI is a folder, this can be multiple) - const dirtySourceModels = this.getDirtyFileModels().filter(model => isEqualOrParent(model.getResource(), source, !platform.isLinux /* ignorecase */)); + const dirtySourceModels = this.getDirtyFileModels().filter(model => isEqualOrParent(model.getResource(), source)); const dirtyTargetModelUris: URI[] = []; if (dirtySourceModels.length) { await Promise.all(dirtySourceModels.map(async sourceModel => { @@ -489,7 +474,7 @@ export abstract class TextFileService extends Disposable implements ITextFileSer let targetModelResource: URI; // If the source is the actual model, just use target as new resource - if (isEqual(sourceModelResource, source, !platform.isLinux /* ignorecase */)) { + if (isEqual(sourceModelResource, source)) { targetModelResource = target; } @@ -503,10 +488,7 @@ export abstract class TextFileService extends Disposable implements ITextFileSer dirtyTargetModelUris.push(targetModelResource); // Backup dirty source model to the target resource it will become later - const snapshot = sourceModel.createSnapshot(); - if (snapshot) { - await this.backupFileService.backupResource(targetModelResource, snapshot, sourceModel.getVersionId()); - } + await sourceModel.backup(targetModelResource); })); } @@ -515,10 +497,12 @@ export abstract class TextFileService extends Disposable implements ITextFileSer // Rename to target try { - await this.fileService.move(source, target, overwrite); + const stat = await this.fileService.move(source, target, overwrite); // Load models that were dirty before await Promise.all(dirtyTargetModelUris.map(dirtyTargetModel => this.models.loadOrCreate(dirtyTargetModel))); + + return stat; } catch (error) { // In case of an error, discard any dirty target backups that were made @@ -553,7 +537,7 @@ export abstract class TextFileService extends Disposable implements ITextFileSer async confirmSave(resources?: URI[]): Promise<ConfirmResult> { if (this.environmentService.isExtensionDevelopment) { - return ConfirmResult.DONT_SAVE; // no veto when we are in extension dev mode because we cannot assum we run interactive (e.g. tests) + return ConfirmResult.DONT_SAVE; // no veto when we are in extension dev mode because we cannot assume we run interactive (e.g. tests) } const resourcesToConfirm = this.getDirty(resources); @@ -608,11 +592,11 @@ export abstract class TextFileService extends Disposable implements ITextFileSer // split up between files and untitled const filesToSave: URI[] = []; const untitledToSave: URI[] = []; - toSave.forEach(s => { - if ((Array.isArray(arg1) || arg1 === true /* includeUntitled */) && s.scheme === Schemas.untitled) { - untitledToSave.push(s); + toSave.forEach(resourceToSave => { + if ((Array.isArray(arg1) || arg1 === true /* includeUntitled */) && resourceToSave.scheme === Schemas.untitled) { + untitledToSave.push(resourceToSave); } else { - filesToSave.push(s); + filesToSave.push(resourceToSave); } }); @@ -663,18 +647,19 @@ export abstract class TextFileService extends Disposable implements ITextFileSer return result; } - protected async promptForPath(resource: URI, defaultUri: URI): Promise<URI | undefined> { + protected async promptForPath(resource: URI, defaultUri: URI, availableFileSystems?: string[]): Promise<URI | undefined> { // Help user to find a name for the file by opening it first await this.editorService.openEditor({ resource, options: { revealIfOpened: true, preserveFocus: true, } }); - return this.fileDialogService.showSaveDialog(this.getSaveDialogOptions(defaultUri)); + return this.fileDialogService.pickFileToSave(this.getSaveDialogOptions(defaultUri, availableFileSystems)); } - private getSaveDialogOptions(defaultUri: URI): ISaveDialogOptions { + private getSaveDialogOptions(defaultUri: URI, availableFileSystems?: string[]): ISaveDialogOptions { const options: ISaveDialogOptions = { defaultUri, - title: nls.localize('saveAsTitle', "Save As") + title: nls.localize('saveAsTitle', "Save As"), + availableFileSystems, }; // Filters are only enabled on Windows where they work properly @@ -757,14 +742,14 @@ export abstract class TextFileService extends Disposable implements ITextFileSer private getFileModels(arg1?: URI | URI[]): ITextFileEditorModel[] { if (Array.isArray(arg1)) { const models: ITextFileEditorModel[] = []; - (<URI[]>arg1).forEach(resource => { + arg1.forEach(resource => { models.push(...this.getFileModels(resource)); }); return models; } - return this._models.getAll(<URI>arg1); + return this._models.getAll(arg1); } private getDirtyFileModels(resources?: URI | URI[]): ITextFileEditorModel[] { @@ -780,7 +765,7 @@ export abstract class TextFileService extends Disposable implements ITextFileSer dialogPath = this.suggestFileName(resource); } - targetResource = await this.promptForPath(resource, dialogPath); + targetResource = await this.promptForPath(resource, dialogPath, options ? options.availableFileSystems : undefined); } if (!targetResource) { @@ -870,19 +855,15 @@ export abstract class TextFileService extends Disposable implements ITextFileSer return false; } - // take over encoding, mode and model value from source model + // take over encoding, mode (only if more specific) and model value from source model targetModel.updatePreferredEncoding(sourceModel.getEncoding()); - if (targetModel.textEditorModel) { - const snapshot = sourceModel.createSnapshot(); - if (snapshot) { - this.modelService.updateModel(targetModel.textEditorModel, createTextBufferFactoryFromSnapshot(snapshot)); - } + if (sourceModel.isResolved() && targetModel.isResolved()) { + this.modelService.updateModel(targetModel.textEditorModel, createTextBufferFactoryFromSnapshot(sourceModel.createSnapshot())); - if (sourceModel.textEditorModel) { - const language = sourceModel.textEditorModel.getLanguageIdentifier(); - if (language.id > 1) { - targetModel.textEditorModel.setMode(language); // only use if more specific than plain/text - } + const sourceMode = sourceModel.textEditorModel.getLanguageIdentifier(); + const targetMode = targetModel.textEditorModel.getLanguageIdentifier(); + if (sourceMode.language !== PLAINTEXT_MODE_ID && targetMode.language === PLAINTEXT_MODE_ID) { + targetModel.textEditorModel.setMode(sourceMode); // only use if more specific than plain/text } } @@ -922,7 +903,7 @@ export abstract class TextFileService extends Disposable implements ITextFileSer return joinPath(lastActiveFolder, untitledFileName); } - return schemeFilter === Schemas.file ? URI.file(untitledFileName) : URI.from({ scheme: schemeFilter, authority: remoteAuthority, path: posix.sep + untitledFileName }); + return untitledResource.with({ path: untitledFileName }); } async revert(resource: URI, options?: IRevertOptions): Promise<boolean> { diff --git a/src/vs/workbench/services/textfile/node/textResourcePropertiesService.ts b/src/vs/workbench/services/textfile/common/textResourcePropertiesService.ts similarity index 97% rename from src/vs/workbench/services/textfile/node/textResourcePropertiesService.ts rename to src/vs/workbench/services/textfile/common/textResourcePropertiesService.ts index e9a71315b..ce097d6fd 100644 --- a/src/vs/workbench/services/textfile/node/textResourcePropertiesService.ts +++ b/src/vs/workbench/services/textfile/common/textResourcePropertiesService.ts @@ -17,7 +17,7 @@ import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiatio export class TextResourcePropertiesService implements ITextResourcePropertiesService { - _serviceBrand: ServiceIdentifier<any>; + _serviceBrand: ServiceIdentifier<ITextResourcePropertiesService>; private remoteEnvironment: IRemoteAgentEnvironment | null = null; diff --git a/src/vs/workbench/services/textfile/common/textfiles.ts b/src/vs/workbench/services/textfile/common/textfiles.ts index 422ea3949..1cbf25a56 100644 --- a/src/vs/workbench/services/textfile/common/textfiles.ts +++ b/src/vs/workbench/services/textfile/common/textfiles.ts @@ -6,7 +6,7 @@ import { URI } from 'vs/base/common/uri'; import { Event } from 'vs/base/common/event'; import { IDisposable } from 'vs/base/common/lifecycle'; -import { IEncodingSupport, ConfirmResult, IRevertOptions } from 'vs/workbench/common/editor'; +import { IEncodingSupport, ConfirmResult, IRevertOptions, IModeSupport } from 'vs/workbench/common/editor'; import { IBaseStatWithMetadata, IFileStatWithMetadata, IReadFileOptions, IWriteFileOptions, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files'; import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; import { ITextEditorModel } from 'vs/editor/common/services/resolverService'; @@ -125,7 +125,7 @@ export interface ITextFileService extends IDisposable { /** * Move a file. If the file is dirty, its contents will be preserved and restored. */ - move(source: URI, target: URI, overwrite?: boolean): Promise<void>; + move(source: URI, target: URI, overwrite?: boolean): Promise<IFileStatWithMetadata>; /** * Brings up the confirm dialog to either save, don't save or cancel. @@ -136,12 +136,12 @@ export interface ITextFileService extends IDisposable { confirmSave(resources?: URI[]): Promise<ConfirmResult>; /** - * Convinient fast access to the current auto save mode. + * Convenient fast access to the current auto save mode. */ getAutoSaveMode(): AutoSaveMode; /** - * Convinient fast access to the raw configured auto save settings. + * Convenient fast access to the raw configured auto save settings. */ getAutoSaveConfiguration(): IAutoSaveConfiguration; } @@ -367,6 +367,11 @@ export interface IModelLoadOrCreateOptions { */ reason?: LoadReason; + /** + * The language mode to use for the model text content. + */ + mode?: string; + /** * The encoding to use when resolving the model text content. */ @@ -423,6 +428,7 @@ export interface ISaveOptions { overwriteEncoding?: boolean; skipSaveParticipants?: boolean; writeElevated?: boolean; + availableFileSystems?: string[]; } export interface ILoadOptions { @@ -443,19 +449,15 @@ export interface ILoadOptions { reason?: LoadReason; } -export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport { +export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport, IModeSupport { readonly onDidContentChange: Event<StateChange>; readonly onDidStateChange: Event<StateChange>; - getVersionId(): number; - getResource(): URI; hasState(state: ModelState): boolean; - getETag(): string | null; - updatePreferredEncoding(encoding: string): void; save(options?: ISaveOptions): Promise<void>; @@ -464,16 +466,19 @@ export interface ITextFileEditorModel extends ITextEditorModel, IEncodingSupport revert(soft?: boolean): Promise<void>; - createSnapshot(): ITextSnapshot | null; + backup(target?: URI): Promise<void>; + + hasBackup(): boolean; isDirty(): boolean; - isResolved(): boolean; + isResolved(): this is IResolvedTextFileEditorModel; isDisposed(): boolean; } export interface IResolvedTextFileEditorModel extends ITextFileEditorModel { + readonly textEditorModel: ITextModel; createSnapshot(): ITextSnapshot; diff --git a/src/vs/workbench/services/textfile/node/textFileService.ts b/src/vs/workbench/services/textfile/node/textFileService.ts index aa8086287..3db51b4e1 100644 --- a/src/vs/workbench/services/textfile/node/textFileService.ts +++ b/src/vs/workbench/services/textfile/node/textFileService.ts @@ -11,9 +11,9 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { URI } from 'vs/base/common/uri'; import { IFileStatWithMetadata, ICreateFileOptions, FileOperationError, FileOperationResult, IFileStreamContent, IFileService } from 'vs/platform/files/common/files'; import { Schemas } from 'vs/base/common/network'; -import { exists, stat, chmod, rimraf } from 'vs/base/node/pfs'; +import { exists, stat, chmod, rimraf, MAX_FILE_SIZE, MAX_HEAP_SIZE } from 'vs/base/node/pfs'; import { join, dirname } from 'vs/base/common/path'; -import { isMacintosh, isLinux } from 'vs/base/common/platform'; +import { isMacintosh } from 'vs/base/common/platform'; import product from 'vs/platform/product/node/product'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; @@ -26,7 +26,6 @@ import { VSBufferReadable, VSBuffer, VSBufferReadableStream } from 'vs/base/comm import { Readable } from 'stream'; import { isUndefinedOrNull } from 'vs/base/common/types'; import { createTextBufferFactoryFromStream } from 'vs/editor/common/model/textModel'; -import { MAX_FILE_SIZE, MAX_HEAP_SIZE } from 'vs/platform/files/node/fileConstants'; import { ITextSnapshot } from 'vs/editor/common/model'; export class NodeTextFileService extends TextFileService { @@ -391,7 +390,7 @@ export class EncodingOracle extends Disposable implements IResourceEncodings { const defaultEncodingOverrides: IEncodingOverride[] = []; // Global settings - defaultEncodingOverrides.push({ parent: URI.file(this.environmentService.appSettingsHome), encoding: UTF8 }); + defaultEncodingOverrides.push({ parent: this.environmentService.userRoamingDataHome, encoding: UTF8 }); // Workspace files defaultEncodingOverrides.push({ extension: WORKSPACE_EXTENSION, encoding: UTF8 }); @@ -491,7 +490,7 @@ export class EncodingOracle extends Disposable implements IResourceEncodings { for (const override of this.encodingOverrides) { // check if the resource is child of encoding override path - if (override.parent && isEqualOrParent(resource, override.parent, !isLinux /* ignorecase */)) { + if (override.parent && isEqualOrParent(resource, override.parent)) { return override.encoding; } diff --git a/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts b/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts index ac6f03706..e22cbe034 100644 --- a/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileEditorModel.test.ts @@ -14,6 +14,7 @@ import { TextFileEditorModelManager } from 'vs/workbench/services/textfile/commo import { FileOperationResult, FileOperationError, IFileService } from 'vs/platform/files/common/files'; import { IModelService } from 'vs/editor/common/services/modelService'; import { timeout } from 'vs/base/common/async'; +import { ModesRegistry } from 'vs/editor/common/modes/modesRegistry'; class ServiceAccessor { constructor(@ITextFileService public textFileService: TestTextFileService, @IModelService public modelService: IModelService, @IFileService public fileService: TestFileService) { @@ -44,25 +45,53 @@ suite('Files - TextFileEditorModel', () => { accessor.fileService.setContent(content); }); - test('Save', async function () { - const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8'); + test('save', async function () { + const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined); await model.load(); model.textEditorModel!.setValue('bar'); assert.ok(getLastModifiedTime(model) <= Date.now()); + let savedEvent = false; + model.onDidStateChange(e => { + if (e === StateChange.SAVED) { + savedEvent = true; + } + }); + await model.save(); assert.ok(model.getLastSaveAttemptTime() <= Date.now()); assert.ok(!model.isDirty()); + assert.ok(savedEvent); + + model.dispose(); + assert.ok(!accessor.modelService.getModel(model.getResource())); + }); + + test('save - touching also emits saved event', async function () { + const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined); + + await model.load(); + + let savedEvent = false; + model.onDidStateChange(e => { + if (e === StateChange.SAVED) { + savedEvent = true; + } + }); + + await model.save({ force: true }); + + assert.ok(savedEvent); model.dispose(); assert.ok(!accessor.modelService.getModel(model.getResource())); }); test('setEncoding - encode', function () { - const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8'); + const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined); model.setEncoding('utf8', EncodingMode.Encode); // no-op assert.equal(getLastModifiedTime(model), -1); @@ -75,7 +104,7 @@ suite('Files - TextFileEditorModel', () => { }); test('setEncoding - decode', async function () { - const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8'); + const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined); model.setEncoding('utf16', EncodingMode.Decode); @@ -84,8 +113,24 @@ suite('Files - TextFileEditorModel', () => { model.dispose(); }); + test('create with mode', async function () { + const mode = 'text-file-model-test'; + ModesRegistry.registerLanguage({ + id: mode, + }); + + const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', mode); + + await model.load(); + + assert.equal(model.textEditorModel!.getModeId(), mode); + + model.dispose(); + assert.ok(!accessor.modelService.getModel(model.getResource())); + }); + test('disposes when underlying model is destroyed', async function () { - const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8'); + const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined); await model.load(); @@ -94,7 +139,7 @@ suite('Files - TextFileEditorModel', () => { }); test('Load does not trigger save', async function () { - const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index.txt'), 'utf8'); + const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index.txt'), 'utf8', undefined); assert.ok(model.hasState(ModelState.SAVED)); model.onDidStateChange(e => { @@ -108,7 +153,7 @@ suite('Files - TextFileEditorModel', () => { }); test('Load returns dirty model as long as model is dirty', async function () { - const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8'); + const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined); await model.load(); model.textEditorModel!.setValue('foo'); @@ -123,7 +168,7 @@ suite('Files - TextFileEditorModel', () => { test('Revert', async function () { let eventCounter = 0; - const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8'); + const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined); model.onDidStateChange(e => { if (e === StateChange.REVERTED) { @@ -145,7 +190,7 @@ suite('Files - TextFileEditorModel', () => { test('Revert (soft)', async function () { let eventCounter = 0; - const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8'); + const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined); model.onDidStateChange(e => { if (e === StateChange.REVERTED) { @@ -165,7 +210,7 @@ suite('Files - TextFileEditorModel', () => { }); test('Load and undo turns model dirty', async function () { - const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8'); + const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined); await model.load(); accessor.fileService.setContent('Hello Change'); @@ -175,7 +220,7 @@ suite('Files - TextFileEditorModel', () => { }); test('File not modified error is handled gracefully', async function () { - let model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8'); + let model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined); await model.load(); @@ -190,7 +235,7 @@ suite('Files - TextFileEditorModel', () => { }); test('Load error is handled gracefully if model already exists', async function () { - let model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8'); + let model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined); await model.load(); accessor.textFileService.setResolveTextContentErrorOnce(new FileOperationError('error', FileOperationResult.FILE_NOT_FOUND)); @@ -236,7 +281,7 @@ suite('Files - TextFileEditorModel', () => { test('Save Participant', async function () { let eventCounter = 0; - const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8'); + const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined); model.onDidStateChange(e => { if (e === StateChange.SAVED) { @@ -266,7 +311,7 @@ suite('Files - TextFileEditorModel', () => { test('Save Participant, async participant', async function () { - const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8'); + const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined); TextFileEditorModel.setSaveParticipant({ participate: (model) => { @@ -284,7 +329,7 @@ suite('Files - TextFileEditorModel', () => { }); test('Save Participant, bad participant', async function () { - const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8'); + const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined); TextFileEditorModel.setSaveParticipant({ participate: (model) => { diff --git a/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts b/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts index 15be3b853..1b5f490f4 100644 --- a/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileEditorModelManager.test.ts @@ -13,6 +13,7 @@ import { IFileService, FileChangesEvent, FileChangeType } from 'vs/platform/file import { IModelService } from 'vs/editor/common/services/modelService'; import { timeout } from 'vs/base/common/async'; import { toResource } from 'vs/base/test/common/utils'; +import { ModesRegistry, PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; export class TestTextFileEditorModelManager extends TextFileEditorModelManager { @@ -42,9 +43,9 @@ suite('Files - TextFileEditorModelManager', () => { test('add, remove, clear, get, getAll', function () { const manager: TestTextFileEditorModelManager = instantiationService.createInstance(TestTextFileEditorModelManager); - const model1: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/random1.txt'), 'utf8'); - const model2: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/random2.txt'), 'utf8'); - const model3: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/random3.txt'), 'utf8'); + const model1: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/random1.txt'), 'utf8', undefined); + const model2: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/random2.txt'), 'utf8', undefined); + const model3: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/random3.txt'), 'utf8', undefined); manager.add(URI.file('/test.html'), model1); manager.add(URI.file('/some/other.html'), model2); @@ -117,9 +118,9 @@ suite('Files - TextFileEditorModelManager', () => { test('removed from cache when model disposed', function () { const manager: TestTextFileEditorModelManager = instantiationService.createInstance(TestTextFileEditorModelManager); - const model1: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/random1.txt'), 'utf8'); - const model2: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/random2.txt'), 'utf8'); - const model3: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/random3.txt'), 'utf8'); + const model1: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/random1.txt'), 'utf8', undefined); + const model2: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/random2.txt'), 'utf8', undefined); + const model3: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/random3.txt'), 'utf8', undefined); manager.add(URI.file('/test.html'), model1); manager.add(URI.file('/some/other.html'), model2); @@ -290,4 +291,24 @@ suite('Files - TextFileEditorModelManager', () => { assert.ok(model.isDisposed()); manager.dispose(); }); + + test('mode', async function () { + const mode = 'text-file-model-manager-test'; + ModesRegistry.registerLanguage({ + id: mode, + }); + + const manager: TestTextFileEditorModelManager = instantiationService.createInstance(TestTextFileEditorModelManager); + + const resource = toResource.call(this, '/path/index_something.txt'); + + let model = await manager.loadOrCreate(resource, { mode }); + assert.equal(model.textEditorModel!.getModeId(), mode); + + model = await manager.loadOrCreate(resource, { mode: 'text' }); + assert.equal(model.textEditorModel!.getModeId(), PLAINTEXT_MODE_ID); + + manager.disposeModel((model as TextFileEditorModel)); + manager.dispose(); + }); }); \ No newline at end of file diff --git a/src/vs/workbench/services/textfile/test/textFileService.io.test.ts b/src/vs/workbench/services/textfile/test/textFileService.io.test.ts index 12d985b18..586639b4e 100644 --- a/src/vs/workbench/services/textfile/test/textFileService.io.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileService.io.test.ts @@ -17,12 +17,12 @@ import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; import { Schemas } from 'vs/base/common/network'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { rimraf, RimRafMode, copy, readFile, exists } from 'vs/base/node/pfs'; -import { dispose, IDisposable } from 'vs/base/common/lifecycle'; -import { FileService } from 'vs/workbench/services/files/common/fileService'; +import { DisposableStore } from 'vs/base/common/lifecycle'; +import { FileService } from 'vs/platform/files/common/fileService'; import { NullLogService } from 'vs/platform/log/common/log'; import { getRandomTestPath } from 'vs/base/test/node/testUtils'; import { tmpdir } from 'os'; -import { DiskFileSystemProvider } from 'vs/workbench/services/files/node/diskFileSystemProvider'; +import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; import { generateUuid } from 'vs/base/common/uuid'; import { join, basename } from 'vs/base/common/path'; import { getPathFromAmdModule } from 'vs/base/common/amd'; @@ -76,7 +76,7 @@ suite('Files - TextFileService i/o', () => { const parentDir = getRandomTestPath(tmpdir(), 'vsctests', 'textfileservice'); let accessor: ServiceAccessor; - let disposables: IDisposable[] = []; + const disposables = new DisposableStore(); let service: ITextFileService; let testDir: string; @@ -88,8 +88,8 @@ suite('Files - TextFileService i/o', () => { const fileService = new FileService(logService); const fileProvider = new DiskFileSystemProvider(logService); - disposables.push(fileService.registerProvider(Schemas.file, fileProvider)); - disposables.push(fileProvider); + disposables.add(fileService.registerProvider(Schemas.file, fileProvider)); + disposables.add(fileProvider); const collection = new ServiceCollection(); collection.set(IFileService, fileService); @@ -108,7 +108,7 @@ suite('Files - TextFileService i/o', () => { (<TextFileEditorModelManager>accessor.textFileService.models).dispose(); accessor.untitledEditorService.revertAll(); - disposables = dispose(disposables); + disposables.clear(); await rimraf(parentDir, RimRafMode.MOVE); }); @@ -247,7 +247,10 @@ suite('Files - TextFileService i/o', () => { } test('write - use encoding (cp1252)', async () => { - await testEncodingKeepsData(URI.file(join(testDir, 'some_cp1252.txt')), 'cp1252', ['ObjectCount = LoadObjects("Öffentlicher Ordner");', '', 'Private = "Persönliche Information"', ''].join(isWindows ? '\r\n' : '\n')); + const filePath = join(testDir, 'some_cp1252.txt'); + const contents = await readFile(filePath, 'utf8'); + const eol = /\r\n/.test(contents) ? '\r\n' : '\n'; + await testEncodingKeepsData(URI.file(filePath), 'cp1252', ['ObjectCount = LoadObjects("Öffentlicher Ordner");', '', 'Private = "Persönliche Information"', ''].join(eol)); }); test('write - use encoding (shiftjis)', async () => { diff --git a/src/vs/workbench/services/textfile/test/textFileService.test.ts b/src/vs/workbench/services/textfile/test/textFileService.test.ts index 72049db9f..ce5dd5dd7 100644 --- a/src/vs/workbench/services/textfile/test/textFileService.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileService.test.ts @@ -65,8 +65,8 @@ suite('Files - TextFileService', () => { accessor.untitledEditorService.revertAll(); }); - test('confirm onWillShutdown - no veto', function () { - model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8'); + test('confirm onWillShutdown - no veto', async function () { + model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); (<TextFileEditorModelManager>accessor.textFileService.models).add(model.getResource(), model); const event = new BeforeShutdownEventImpl(); @@ -76,14 +76,12 @@ suite('Files - TextFileService', () => { if (typeof veto === 'boolean') { assert.ok(!veto); } else { - veto.then(veto => { - assert.ok(!veto); - }); + assert.ok(!(await veto)); } }); test('confirm onWillShutdown - veto if user cancels', async function () { - model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8'); + model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); (<TextFileEditorModelManager>accessor.textFileService.models).add(model.getResource(), model); const service = accessor.textFileService; @@ -99,7 +97,7 @@ suite('Files - TextFileService', () => { }); test('confirm onWillShutdown - no veto and backups cleaned up if user does not want to save (hot.exit: off)', async function () { - model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8'); + model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); (<TextFileEditorModelManager>accessor.textFileService.models).add(model.getResource(), model); const service = accessor.textFileService; @@ -125,7 +123,7 @@ suite('Files - TextFileService', () => { }); test('confirm onWillShutdown - save (hot.exit: off)', async function () { - model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8'); + model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); (<TextFileEditorModelManager>accessor.textFileService.models).add(model.getResource(), model); const service = accessor.textFileService; @@ -144,7 +142,7 @@ suite('Files - TextFileService', () => { }); test('isDirty/getDirty - files and untitled', async function () { - model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8'); + model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); (<TextFileEditorModelManager>accessor.textFileService.models).add(model.getResource(), model); const service = accessor.textFileService; @@ -171,7 +169,7 @@ suite('Files - TextFileService', () => { }); test('save - file', async function () { - model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8'); + model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); (<TextFileEditorModelManager>accessor.textFileService.models).add(model.getResource(), model); const service = accessor.textFileService; @@ -187,11 +185,11 @@ suite('Files - TextFileService', () => { test('save - UNC path', async function () { const untitledUncUri = URI.from({ scheme: 'untitled', authority: 'server', path: '/share/path/file.txt' }); - model = instantiationService.createInstance(TextFileEditorModel, untitledUncUri, 'utf8'); + model = instantiationService.createInstance(TextFileEditorModel, untitledUncUri, 'utf8', undefined); (<TextFileEditorModelManager>accessor.textFileService.models).add(model.getResource(), model); const mockedFileUri = untitledUncUri.with({ scheme: Schemas.file }); - const mockedEditorInput = instantiationService.createInstance(TextFileEditorModel, mockedFileUri, 'utf8'); + const mockedEditorInput = instantiationService.createInstance(TextFileEditorModel, mockedFileUri, 'utf8', undefined); const loadOrCreateStub = sinon.stub(accessor.textFileService.models, 'loadOrCreate', () => Promise.resolve(mockedEditorInput)); sinon.stub(accessor.untitledEditorService, 'exists', () => true); @@ -211,7 +209,7 @@ suite('Files - TextFileService', () => { }); test('saveAll - file', async function () { - model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8'); + model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); (<TextFileEditorModelManager>accessor.textFileService.models).add(model.getResource(), model); const service = accessor.textFileService; @@ -228,7 +226,7 @@ suite('Files - TextFileService', () => { }); test('saveAs - file', async function () { - model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8'); + model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); (<TextFileEditorModelManager>accessor.textFileService.models).add(model.getResource(), model); const service = accessor.textFileService; @@ -244,7 +242,7 @@ suite('Files - TextFileService', () => { }); test('revert - file', async function () { - model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8'); + model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); (<TextFileEditorModelManager>accessor.textFileService.models).add(model.getResource(), model); const service = accessor.textFileService; @@ -260,7 +258,7 @@ suite('Files - TextFileService', () => { }); test('delete - dirty file', async function () { - model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8'); + model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); (<TextFileEditorModelManager>accessor.textFileService.models).add(model.getResource(), model); const service = accessor.textFileService; @@ -274,8 +272,8 @@ suite('Files - TextFileService', () => { }); test('move - dirty file', async function () { - let sourceModel: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8'); - let targetModel: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file_target.txt'), 'utf8'); + let sourceModel: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); + let targetModel: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file_target.txt'), 'utf8', undefined); (<TextFileEditorModelManager>accessor.textFileService.models).add(sourceModel.getResource(), sourceModel); (<TextFileEditorModelManager>accessor.textFileService.models).add(targetModel.getResource(), targetModel); @@ -395,7 +393,7 @@ suite('Files - TextFileService', () => { }); async function hotExitTest(this: any, setting: string, shutdownReason: ShutdownReason, multipleWindows: boolean, workspace: true, shouldVeto: boolean): Promise<void> { - model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8'); + model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file.txt'), 'utf8', undefined); (<TextFileEditorModelManager>accessor.textFileService.models).add(model.getResource(), model); const service = accessor.textFileService; diff --git a/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts b/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts index 42fc1561a..a2f3269ec 100644 --- a/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts +++ b/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts @@ -31,7 +31,7 @@ class ResourceModelCollection extends ReferenceCollection<Promise<ITextEditorMod super(); } - createReferencedObject(key: string, skipActivateProvider?: boolean): Promise<ITextEditorModel> { + async createReferencedObject(key: string, skipActivateProvider?: boolean): Promise<ITextEditorModel> { this.modelsToDispose.delete(key); const resource = URI.parse(key); @@ -43,15 +43,19 @@ class ResourceModelCollection extends ReferenceCollection<Promise<ITextEditorMod // Virtual documents if (this.providers[resource.scheme]) { - return this.resolveTextModelContent(key).then(() => this.instantiationService.createInstance(ResourceEditorModel, resource)); + await this.resolveTextModelContent(key); + + return this.instantiationService.createInstance(ResourceEditorModel, resource); } // Either unknown schema, or not yet registered, try to activate if (!skipActivateProvider) { - return this.fileService.activateProvider(resource.scheme).then(() => this.createReferencedObject(key, true)); + await this.fileService.activateProvider(resource.scheme); + + return this.createReferencedObject(key, true); } - return Promise.reject(new Error('resource is not available')); + throw new Error('resource is not available'); } destroyReferencedObject(key: string, modelPromise: Promise<ITextEditorModel>): void { @@ -101,18 +105,17 @@ class ResourceModelCollection extends ReferenceCollection<Promise<ITextEditorMod return this.providers[scheme] !== undefined; } - private resolveTextModelContent(key: string): Promise<ITextModel> { + private async resolveTextModelContent(key: string): Promise<ITextModel> { const resource = URI.parse(key); const providers = this.providers[resource.scheme] || []; const factories = providers.map(p => () => Promise.resolve(p.provideTextContent(resource))); - return first(factories).then(model => { - if (!model) { - return Promise.reject(new Error('resource is not available')); - } + const model = await first(factories); + if (!model) { + throw new Error('resource is not available'); + } - return model; - }); + return model; } } @@ -131,14 +134,16 @@ export class TextModelResolverService implements ITextModelService { } createModelReference(resource: URI): Promise<IReference<IResolvedTextEditorModel>> { - return this._createModelReference(resource); + return this.doCreateModelReference(resource); } - private _createModelReference(resource: URI): Promise<IReference<IResolvedTextEditorModel>> { + private async doCreateModelReference(resource: URI): Promise<IReference<IResolvedTextEditorModel>> { // Untitled Schema: go through cached input if (resource.scheme === network.Schemas.untitled) { - return this.untitledEditorService.loadOrCreate({ resource }).then(model => new ImmortalReference(model as IResolvedTextEditorModel)); + const model = await this.untitledEditorService.loadOrCreate({ resource }); + + return new ImmortalReference(model as IResolvedTextEditorModel); } // InMemory Schema: go through model service cache @@ -146,22 +151,23 @@ export class TextModelResolverService implements ITextModelService { const cachedModel = this.modelService.getModel(resource); if (!cachedModel) { - return Promise.reject(new Error('Cant resolve inmemory resource')); + throw new Error('Cant resolve inmemory resource'); } - return Promise.resolve(new ImmortalReference(this.instantiationService.createInstance(ResourceEditorModel, resource) as IResolvedTextEditorModel)); + return new ImmortalReference(this.instantiationService.createInstance(ResourceEditorModel, resource) as IResolvedTextEditorModel); } const ref = this.resourceModelCollection.acquire(resource.toString()); - return ref.object.then( - model => ({ object: model, dispose: () => ref.dispose() }), - err => { - ref.dispose(); + try { + const model = await ref.object; - return Promise.reject(err); - } - ); + return { object: model as IResolvedTextEditorModel, dispose: () => ref.dispose() }; + } catch (error) { + ref.dispose(); + + throw error; + } } registerTextModelContentProvider(scheme: string, provider: ITextModelContentProvider): IDisposable { diff --git a/src/vs/workbench/services/textmodelResolver/test/textModelResolverService.test.ts b/src/vs/workbench/services/textmodelResolver/test/textModelResolverService.test.ts index 10e4b34c2..b924c5596 100644 --- a/src/vs/workbench/services/textmodelResolver/test/textModelResolverService.test.ts +++ b/src/vs/workbench/services/textmodelResolver/test/textModelResolverService.test.ts @@ -53,7 +53,7 @@ suite('Workbench - TextModelResolverService', () => { accessor.untitledEditorService.revertAll(); }); - test('resolve resource', function () { + test('resolve resource', async () => { const dispose = accessor.textModelResolverService.registerTextModelContentProvider('test', { provideTextContent: function (resource: URI): Promise<ITextModel> { if (resource.scheme === 'test') { @@ -67,67 +67,60 @@ suite('Workbench - TextModelResolverService', () => { }); let resource = URI.from({ scheme: 'test', authority: null!, path: 'thePath' }); - let input: ResourceEditorInput = instantiationService.createInstance(ResourceEditorInput, 'The Name', 'The Description', resource); - - return input.resolve().then(async model => { - assert.ok(model); - assert.equal(snapshotToString((model as ResourceEditorModel).createSnapshot()!), 'Hello Test'); - - let disposed = false; - let disposedPromise = new Promise(resolve => { - Event.once(model.onDispose)(() => { - disposed = true; - resolve(); - }); + let input: ResourceEditorInput = instantiationService.createInstance(ResourceEditorInput, 'The Name', 'The Description', resource, undefined); + + const model = await input.resolve(); + assert.ok(model); + assert.equal(snapshotToString(((model as ResourceEditorModel).createSnapshot()!)), 'Hello Test'); + let disposed = false; + let disposedPromise = new Promise(resolve => { + Event.once(model.onDispose)(() => { + disposed = true; + resolve(); }); - input.dispose(); - await disposedPromise; - assert.equal(disposed, true); - - dispose.dispose(); }); + input.dispose(); + + await disposedPromise; + assert.equal(disposed, true); + dispose.dispose(); }); - test('resolve file', function () { - model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file_resolver.txt'), 'utf8'); - (<TextFileEditorModelManager>accessor.textFileService.models).add(model.getResource(), model); + test('resolve file', async function () { + const textModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/file_resolver.txt'), 'utf8', undefined); + (<TextFileEditorModelManager>accessor.textFileService.models).add(textModel.getResource(), textModel); - return model.load().then(() => { - return accessor.textModelResolverService.createModelReference(model.getResource()).then(ref => { - const model = ref.object; - const editorModel = model.textEditorModel; + await textModel.load(); - assert.ok(editorModel); - assert.equal(editorModel.getValue(), 'Hello Html'); + const ref = await accessor.textModelResolverService.createModelReference(textModel.getResource()); - let disposed = false; - Event.once(model.onDispose)(() => { - disposed = true; - }); + const model = ref.object; + const editorModel = model.textEditorModel; - ref.dispose(); - return timeout(0).then(() => { // due to the reference resolving the model first which is async - assert.equal(disposed, true); - }); - }); + assert.ok(editorModel); + assert.equal(editorModel.getValue(), 'Hello Html'); + + let disposed = false; + Event.once(model.onDispose)(() => { + disposed = true; }); + + ref.dispose(); + await timeout(0); // due to the reference resolving the model first which is async + assert.equal(disposed, true); }); - test('resolve untitled', function () { + test('resolve untitled', async () => { const service = accessor.untitledEditorService; const input = service.createOrGet(); - return input.resolve().then(() => { - return accessor.textModelResolverService.createModelReference(input.getResource()).then(ref => { - const model = ref.object; - const editorModel = model.textEditorModel; - - assert.ok(editorModel); - ref.dispose(); - - input.dispose(); - }); - }); + await input.resolve(); + const ref = await accessor.textModelResolverService.createModelReference(input.getResource()); + const model = ref.object; + const editorModel = model.textEditorModel; + assert.ok(editorModel); + ref.dispose(); + input.dispose(); }); test('even loading documents should be refcounted', async () => { @@ -135,12 +128,12 @@ suite('Workbench - TextModelResolverService', () => { let waitForIt = new Promise(c => resolveModel = c); const disposable = accessor.textModelResolverService.registerTextModelContentProvider('test', { - provideTextContent: (resource: URI): Promise<ITextModel> => { - return waitForIt.then(_ => { - let modelContent = 'Hello Test'; - let languageSelection = accessor.modeService.create('json'); - return accessor.modelService.createModel(modelContent, languageSelection, resource); - }); + provideTextContent: async (resource: URI): Promise<ITextModel> => { + await waitForIt; + + let modelContent = 'Hello Test'; + let languageSelection = accessor.modeService.create('json'); + return accessor.modelService.createModel(modelContent, languageSelection, resource); } }); diff --git a/src/vs/workbench/services/themes/common/fileIconThemeData.ts b/src/vs/workbench/services/themes/browser/fileIconThemeData.ts similarity index 97% rename from src/vs/workbench/services/themes/common/fileIconThemeData.ts rename to src/vs/workbench/services/themes/browser/fileIconThemeData.ts index 7d84be48b..3059579a6 100644 --- a/src/vs/workbench/services/themes/common/fileIconThemeData.ts +++ b/src/vs/workbench/services/themes/browser/fileIconThemeData.ts @@ -11,6 +11,7 @@ import * as Json from 'vs/base/common/json'; import { ExtensionData, IThemeExtensionPoint, IFileIconTheme } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { IFileService } from 'vs/platform/files/common/files'; import { getParseErrorMessage } from 'vs/base/common/jsonErrorMessages'; +import { asDomUri } from 'vs/base/browser/dom'; export class FileIconThemeData implements IFileIconTheme { id: string; @@ -118,7 +119,7 @@ export class FileIconThemeData implements IFileIconTheme { case 'hidesExplorerArrows': case 'hasFolderIcons': case 'watch': - theme[key] = data[key]; + (theme as any)[key] = data[key]; break; case 'location': theme.location = URI.revive(data.location); @@ -331,7 +332,7 @@ function _processIconThemeDocument(id: string, iconThemeDocumentLocation: URI, i 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(', '); + let src = font.src.map(l => `url('${asDomUri(resolvePath(l.path))}') format('${l.format}')`).join(', '); cssRules.push(`@font-face { src: ${src}; font-family: '${font.id}'; font-weight: ${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%'}}`); @@ -342,7 +343,7 @@ function _processIconThemeDocument(id: string, iconThemeDocumentLocation: URI, i let definition = iconThemeDocument.iconDefinitions[defId]; if (definition) { if (definition.iconPath) { - cssRules.push(`${selectors.join(', ')} { content: ' '; background-image: url("${resolvePath(definition.iconPath)}"); }`); + cssRules.push(`${selectors.join(', ')} { content: ' '; background-image: url("${asDomUri(resolvePath(definition.iconPath))}"); }`); } if (definition.fontCharacter || definition.fontColor) { let body = ''; @@ -366,5 +367,5 @@ function _processIconThemeDocument(id: string, iconThemeDocumentLocation: URI, i return result; } function escapeCSS(str: string) { - return window['CSS'].escape(str); + return (<any>window)['CSS'].escape(str); } diff --git a/src/vs/workbench/services/themes/common/fileIconThemeStore.ts b/src/vs/workbench/services/themes/browser/fileIconThemeStore.ts similarity index 94% rename from src/vs/workbench/services/themes/common/fileIconThemeStore.ts rename to src/vs/workbench/services/themes/browser/fileIconThemeStore.ts index b887b23de..e4eb557f5 100644 --- a/src/vs/workbench/services/themes/common/fileIconThemeStore.ts +++ b/src/vs/workbench/services/themes/browser/fileIconThemeStore.ts @@ -11,8 +11,9 @@ import { ExtensionsRegistry, ExtensionMessageCollector } from 'vs/workbench/serv import { ExtensionData, IThemeExtensionPoint } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { Event, Emitter } from 'vs/base/common/event'; -import { FileIconThemeData } from 'vs/workbench/services/themes/common/fileIconThemeData'; +import { FileIconThemeData } from 'vs/workbench/services/themes/browser/fileIconThemeData'; import { URI } from 'vs/base/common/uri'; +import { Disposable } from 'vs/base/common/lifecycle'; const iconThemeExtPoint = ExtensionsRegistry.registerExtensionPoint<IThemeExtensionPoint[]>({ extensionPoint: 'iconThemes', @@ -46,16 +47,16 @@ export interface FileIconThemeChangeEvent { added: FileIconThemeData[]; } -export class FileIconThemeStore { +export class FileIconThemeStore extends Disposable { private knownIconThemes: FileIconThemeData[]; - private readonly onDidChangeEmitter: Emitter<FileIconThemeChangeEvent>; - public get onDidChange(): Event<FileIconThemeChangeEvent> { return this.onDidChangeEmitter.event; } + private readonly onDidChangeEmitter = this._register(new Emitter<FileIconThemeChangeEvent>()); + readonly onDidChange: Event<FileIconThemeChangeEvent> = this.onDidChangeEmitter.event; constructor(@IExtensionService private readonly extensionService: IExtensionService) { + super(); this.knownIconThemes = []; - this.onDidChangeEmitter = new Emitter<FileIconThemeChangeEvent>(); this.initialize(); } @@ -167,5 +168,4 @@ export class FileIconThemeStore { return this.knownIconThemes; }); } - } diff --git a/src/vs/workbench/services/themes/browser/workbenchThemeService.ts b/src/vs/workbench/services/themes/browser/workbenchThemeService.ts index 2bb21797a..cf5e18177 100644 --- a/src/vs/workbench/services/themes/browser/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/browser/workbenchThemeService.ts @@ -19,8 +19,8 @@ import { Event, Emitter } from 'vs/base/common/event'; import { registerFileIconThemeSchemas } from 'vs/workbench/services/themes/common/fileIconThemeSchema'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { ColorThemeStore } from 'vs/workbench/services/themes/common/colorThemeStore'; -import { FileIconThemeStore } from 'vs/workbench/services/themes/common/fileIconThemeStore'; -import { FileIconThemeData } from 'vs/workbench/services/themes/common/fileIconThemeData'; +import { FileIconThemeStore } from 'vs/workbench/services/themes/browser/fileIconThemeStore'; +import { FileIconThemeData } from 'vs/workbench/services/themes/browser/fileIconThemeData'; import { removeClasses, addClasses } from 'vs/base/browser/dom'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IFileService, FileChangeType } from 'vs/platform/files/common/files'; @@ -31,6 +31,7 @@ import { textmateColorsSchemaId, registerColorThemeSchemas, textmateColorSetting import { workbenchColorsSchemaId } from 'vs/platform/theme/common/colorRegistry'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { getRemoteAuthority } from 'vs/platform/remote/common/remoteHosts'; +import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; // implementation @@ -44,6 +45,7 @@ const defaultThemeExtensionId = 'vscode-theme-defaults'; const oldDefaultThemeExtensionId = 'vscode-theme-colorful-defaults'; const DEFAULT_ICON_THEME_SETTING_VALUE = 'vs-seti'; +const DEFAULT_ICON_THEME_ID = 'vscode.vscode-theme-seti-vs-seti'; const fileIconsEnabledClass = 'file-icons-enabled'; const colorThemeRulesClassName = 'contributedColorTheme'; @@ -95,10 +97,11 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { @IConfigurationService private readonly configurationService: IConfigurationService, @ITelemetryService private readonly telemetryService: ITelemetryService, @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, - @IFileService private readonly fileService: IFileService + @IFileService private readonly fileService: IFileService, + @IWorkbenchLayoutService readonly layoutService: IWorkbenchLayoutService ) { - this.container = document.body; + this.container = layoutService.getWorkbenchContainer(); this.colorThemeStore = new ColorThemeStore(extensionService, ColorThemeData.createLoadedEmptyTheme(DEFAULT_THEME_ID, DEFAULT_THEME_SETTING_VALUE)); this.onFileIconThemeChange = new Emitter<IFileIconTheme>(); this.iconThemeStore = new FileIconThemeStore(extensionService); @@ -190,10 +193,10 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { if (!theme) { // current theme is no longer available prevFileIconId = this.currentIconTheme.id; - this.setFileIconTheme(DEFAULT_ICON_THEME_SETTING_VALUE, 'auto'); + this.setFileIconTheme(DEFAULT_ICON_THEME_ID, 'auto'); } else { // restore color - if (this.currentIconTheme.id === DEFAULT_ICON_THEME_SETTING_VALUE && !types.isUndefined(prevFileIconId) && await this.iconThemeStore.findThemeData(prevFileIconId)) { + if (this.currentIconTheme.id === DEFAULT_ICON_THEME_ID && !types.isUndefined(prevFileIconId) && await this.iconThemeStore.findThemeData(prevFileIconId)) { this.setFileIconTheme(prevFileIconId, 'auto'); prevFileIconId = undefined; } @@ -269,7 +272,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { if (devThemes.length) { return this.setFileIconTheme(devThemes[0].id, ConfigurationTarget.MEMORY); } else { - return this.setFileIconTheme(theme && theme.id || DEFAULT_ICON_THEME_SETTING_VALUE, undefined); + return this.setFileIconTheme(theme ? theme.id : DEFAULT_ICON_THEME_ID, undefined); } }); }), @@ -292,7 +295,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { let iconThemeSetting = this.configurationService.getValue<string | null>(ICON_THEME_SETTING); if (iconThemeSetting !== this.currentIconTheme.settingsId) { this.iconThemeStore.findThemeBySettingsId(iconThemeSetting).then(theme => { - this.setFileIconTheme(theme && theme.id || DEFAULT_ICON_THEME_SETTING_VALUE, undefined); + this.setFileIconTheme(theme ? theme.id : DEFAULT_ICON_THEME_ID, undefined); }); } } @@ -371,29 +374,26 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { } private updateDynamicCSSRules(themeData: ITheme) { - let cssRules: string[] = []; - let hasRule: { [rule: string]: boolean } = {}; - let ruleCollector = { + const cssRules = new Set<string>(); + const ruleCollector = { addRule: (rule: string) => { - if (!hasRule[rule]) { - cssRules.push(rule); - hasRule[rule] = true; + if (!cssRules.has(rule)) { + cssRules.add(rule); } } }; themingRegistry.getThemingParticipants().forEach(p => p(themeData, ruleCollector, this.environmentService)); - _applyRules(cssRules.join('\n'), colorThemeRulesClassName); + _applyRules([...cssRules].join('\n'), colorThemeRulesClassName); } private applyTheme(newTheme: ColorThemeData, settingsTarget: ConfigurationTarget | undefined | 'auto', silent = false): Promise<IColorTheme | null> { - if (this.container) { - if (this.currentColorTheme) { - removeClasses(this.container, this.currentColorTheme.id); - } else { - removeClasses(this.container, VS_DARK_THEME, VS_LIGHT_THEME, VS_HC_THEME); - } - addClasses(this.container, newTheme.id); + if (this.currentColorTheme) { + removeClasses(this.container, this.currentColorTheme.id); + } else { + removeClasses(this.container, VS_DARK_THEME, VS_LIGHT_THEME, VS_HC_THEME); } + addClasses(this.container, newTheme.id); + this.currentColorTheme = newTheme; if (!this.themingParticipantChangeListener) { this.themingParticipantChangeListener = themingRegistry.onThemingParticipantAdded(_ => this.updateDynamicCSSRules(this.currentColorTheme)); @@ -437,16 +437,21 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { 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", "isMeasurement": true }, - "publisherDisplayName": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "themeId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } - } - */ - this.telemetryService.publicLog('activatePlugin', { + type ActivatePluginClassification = { + id: { classification: 'PublicNonPersonalData', purpose: 'FeatureInsight' }; + name: { classification: 'PublicNonPersonalData', purpose: 'FeatureInsight' }; + isBuiltin: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; + publisherDisplayName: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + themeId: { classification: 'PublicNonPersonalData', purpose: 'FeatureInsight' }; + }; + type ActivatePluginEvent = { + id: string; + name: string; + isBuiltin: boolean; + publisherDisplayName: string; + themeId: string; + }; + this.telemetryService.publicLog2<ActivatePluginEvent, ActivatePluginClassification>('activatePlugin', { id: themeData.extensionId, name: themeData.extensionName, isBuiltin: themeData.extensionIsBuiltin, @@ -479,7 +484,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { this.doSetFileIconTheme(newIconTheme); // remember theme data for a quick restore - if (newIconTheme.isLoaded && newIconTheme.location && !getRemoteAuthority(newIconTheme.location)) { + if (newIconTheme.isLoaded && (!newIconTheme.location || !getRemoteAuthority(newIconTheme.location))) { this.storageService.store(PERSISTED_ICON_THEME_STORAGE_KEY, newIconTheme.toStorageData(), StorageScope.GLOBAL); } @@ -508,12 +513,10 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { private doSetFileIconTheme(iconThemeData: FileIconThemeData): void { this.currentIconTheme = iconThemeData; - if (this.container) { - if (iconThemeData.id) { - addClasses(this.container, fileIconsEnabledClass); - } else { - removeClasses(this.container, fileIconsEnabledClass); - } + if (iconThemeData.id) { + addClasses(this.container, fileIconsEnabledClass); + } else { + removeClasses(this.container, fileIconsEnabledClass); } if (this.fileService && !resources.isEqual(iconThemeData.location, this.watchedIconThemeLocation)) { @@ -570,12 +573,10 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { } private getBaseThemeFromContainer() { - if (this.container) { - for (let i = this.container.classList.length - 1; i >= 0; i--) { - const item = document.body.classList.item(i); - if (item === VS_LIGHT_THEME || item === VS_DARK_THEME || item === VS_HC_THEME) { - return item; - } + for (let i = this.container.classList.length - 1; i >= 0; i--) { + const item = this.container.classList.item(i); + if (item === VS_LIGHT_THEME || item === VS_DARK_THEME || item === VS_HC_THEME) { + return item; } } return VS_DARK_THEME; @@ -692,4 +693,4 @@ const tokenColorCustomizationConfiguration: IConfigurationNode = { }; configurationRegistry.registerConfiguration(tokenColorCustomizationConfiguration); -registerSingleton(IWorkbenchThemeService, WorkbenchThemeService); \ No newline at end of file +registerSingleton(IWorkbenchThemeService, WorkbenchThemeService); diff --git a/src/vs/workbench/services/themes/common/colorThemeData.ts b/src/vs/workbench/services/themes/common/colorThemeData.ts index acc4ba878..6d39ebd15 100644 --- a/src/vs/workbench/services/themes/common/colorThemeData.ts +++ b/src/vs/workbench/services/themes/common/colorThemeData.ts @@ -23,7 +23,7 @@ import { startsWith } from 'vs/base/common/strings'; let colorRegistry = Registry.as<IColorRegistry>(Extensions.ColorContribution); -const tokenGroupToScopesMap: { [setting: string]: string[] } = { +const tokenGroupToScopesMap = { comments: ['comment'], strings: ['string'], keywords: ['keyword - keyword.operator', 'keyword.control', 'storage', 'storage.type'], @@ -146,10 +146,11 @@ export class ColorThemeData implements IColorTheme { // Put the general customizations such as comments, strings, etc. first so that // they can be overridden by specific customizations like "string.interpolated" for (let tokenGroup in tokenGroupToScopesMap) { - let value = customTokenColors[tokenGroup]; + const group = <keyof typeof tokenGroupToScopesMap>tokenGroup; // TS doesn't type 'tokenGroup' properly + let value = customTokenColors[group]; if (value) { let settings = typeof value === 'string' ? { foreground: value } : value; - let scopes = tokenGroupToScopesMap[tokenGroup]; + let scopes = tokenGroupToScopesMap[group]; for (let scope of scopes) { this.customTokenColors.push({ scope, settings }); } @@ -186,7 +187,7 @@ export class ColorThemeData implements IColorTheme { } toStorageData() { - let colorMapData = {}; + let colorMapData: { [key: string]: string } = {}; for (let key in this.colorMap) { colorMapData[key] = Color.Format.CSS.formatHexA(this.colorMap[key], true); } @@ -251,7 +252,7 @@ export class ColorThemeData implements IColorTheme { break; case 'themeTokenColors': case 'id': case 'label': case 'settingsId': case 'extensionData': case 'watch': - theme[key] = data[key]; + (theme as any)[key] = data[key]; break; } } diff --git a/src/vs/workbench/services/themes/common/colorThemeStore.ts b/src/vs/workbench/services/themes/common/colorThemeStore.ts index a803474e6..272338755 100644 --- a/src/vs/workbench/services/themes/common/colorThemeStore.ts +++ b/src/vs/workbench/services/themes/common/colorThemeStore.ts @@ -53,17 +53,15 @@ export interface ColorThemeChangeEvent { export class ColorThemeStore { private extensionsColorThemes: ColorThemeData[]; - private readonly onDidChangeEmitter: Emitter<ColorThemeChangeEvent>; - public get onDidChange(): Event<ColorThemeChangeEvent> { return this.onDidChangeEmitter.event; } + private readonly onDidChangeEmitter = new Emitter<ColorThemeChangeEvent>(); + public readonly onDidChange: Event<ColorThemeChangeEvent> = this.onDidChangeEmitter.event; constructor(@IExtensionService private readonly extensionService: IExtensionService, defaultTheme: ColorThemeData) { this.extensionsColorThemes = [defaultTheme]; - this.onDidChangeEmitter = new Emitter<ColorThemeChangeEvent>(); this.initialize(); } - private initialize() { themesExtPoint.setHandler((extensions, delta) => { const previousIds: { [key: string]: boolean } = {}; diff --git a/src/vs/workbench/services/themes/common/plistParser.ts b/src/vs/workbench/services/themes/common/plistParser.ts index e4478a5ec..6825c6514 100644 --- a/src/vs/workbench/services/themes/common/plistParser.ts +++ b/src/vs/workbench/services/themes/common/plistParser.ts @@ -143,7 +143,7 @@ function _parse(content: string, filename: string | null, locationKeyName: strin if (curKey === null) { return fail('missing <key>'); } - let newDict = {}; + let newDict: { [key: string]: any } = {}; if (locationKeyName !== null) { newDict[locationKeyName] = { filename: filename, @@ -168,7 +168,7 @@ function _parse(content: string, filename: string | null, locationKeyName: strin const arrState = { enterDict: function () { - let newDict = {}; + let newDict: { [key: string]: any } = {}; if (locationKeyName !== null) { newDict[locationKeyName] = { filename: filename, diff --git a/src/vs/workbench/services/themes/common/themeCompatibility.ts b/src/vs/workbench/services/themes/common/themeCompatibility.ts index 577b32e42..6518ff4a4 100644 --- a/src/vs/workbench/services/themes/common/themeCompatibility.ts +++ b/src/vs/workbench/services/themes/common/themeCompatibility.ts @@ -26,7 +26,8 @@ export function convertSettings(oldSettings: ITokenColorizationRule[], resultRul if (!settings) { rule.settings = {}; } else { - for (let key in settings) { + for (const settingKey in settings) { + const key = <keyof typeof settings>settingKey; let mappings = settingToColorIdMapping[key]; if (mappings) { let colorHex = settings[key]; diff --git a/src/vs/workbench/services/themes/common/workbenchThemeService.ts b/src/vs/workbench/services/themes/common/workbenchThemeService.ts index 831b8ad33..deb116b60 100644 --- a/src/vs/workbench/services/themes/common/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/common/workbenchThemeService.ts @@ -69,6 +69,7 @@ export interface IColorCustomizations { } export interface ITokenColorCustomizations { + [groupIdOrThemeSettingsId: string]: string | ITokenColorizationSetting | ITokenColorCustomizations | undefined | ITokenColorizationRule[]; comments?: string | ITokenColorizationSetting; strings?: string | ITokenColorizationSetting; numbers?: string | ITokenColorizationSetting; @@ -103,5 +104,6 @@ export interface IThemeExtensionPoint { label?: string; description?: string; path: string; + uiTheme?: typeof VS_LIGHT_THEME | typeof VS_DARK_THEME | typeof VS_HC_THEME; _watch: boolean; // unsupported options to watch location } \ No newline at end of file diff --git a/src/vs/workbench/services/timer/electron-browser/timerService.ts b/src/vs/workbench/services/timer/electron-browser/timerService.ts index b26edf948..ffc085490 100644 --- a/src/vs/workbench/services/timer/electron-browser/timerService.ts +++ b/src/vs/workbench/services/timer/electron-browser/timerService.ts @@ -12,7 +12,6 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { isNonEmptyArray } from 'vs/base/common/arrays'; import { IUpdateService } from 'vs/platform/update/common/update'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; @@ -23,14 +22,12 @@ import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessi /* __GDPR__FRAGMENT__ "IMemoryInfo" : { "workingSetSize" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "peakWorkingSetSize": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "privateBytes": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "sharedBytes": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true } } */ export interface IMemoryInfo { readonly workingSetSize: number; - readonly peakWorkingSetSize: number; readonly privateBytes: number; readonly sharedBytes: number; } @@ -211,7 +208,7 @@ export interface IStartupMetrics { readonly ellapsedWorkspaceServiceInit: number; /** - * The time it took to load the main-bundle of the workbench, e.g `workbench.main.js`. + * The time it took to load the main-bundle of the workbench, e.g. `workbench.main.js`. * * * Happens in the renderer-process * * Measured with the `willLoadWorkbenchMain` and `didLoadWorkbenchMain` performance marks. @@ -355,7 +352,13 @@ class TimerService implements ITimerService { release = os.release(); arch = os.arch(); loadavg = os.loadavg(); - meminfo = process.getProcessMemoryInfo(); + + const processMemoryInfo = await process.getProcessMemoryInfo(); + meminfo = { + workingSetSize: processMemoryInfo.residentSet, + privateBytes: processMemoryInfo.private, + sharedBytes: processMemoryInfo.shared + }; isVMLikelyhood = Math.round((virtualMachineHint.value() * 100)); @@ -428,16 +431,19 @@ export function didUseCachedData(): boolean { if (!Boolean((<any>global).require.getConfig().nodeCachedData)) { return false; } - // whenever cached data is produced or rejected a onNodeCachedData-callback is invoked. That callback - // stores data in the `MonacoEnvironment.onNodeCachedData` global. See: - // https://github.com/Microsoft/vscode/blob/efe424dfe76a492eab032343e2fa4cfe639939f0/src/vs/workbench/electron-browser/bootstrap/index.js#L299 - if (isNonEmptyArray(MonacoEnvironment.onNodeCachedData)) { - return false; + // There are loader events that signal if cached data was missing, rejected, + // or used. The former two mean no cached data. + let cachedDataFound = 0; + for (const event of require.getStats()) { + switch (event.type) { + case LoaderEventType.CachedDataRejected: + return false; + case LoaderEventType.CachedDataFound: + cachedDataFound += 1; + break; + } } - return true; + return cachedDataFound > 0; } -declare type OnNodeCachedDataArgs = [{ errorCode: string, path: string, detail?: string }, { path: string, length: number }]; -declare const MonacoEnvironment: { onNodeCachedData: OnNodeCachedDataArgs[] }; - //#endregion diff --git a/src/vs/workbench/services/untitled/common/untitledEditorService.ts b/src/vs/workbench/services/untitled/common/untitledEditorService.ts index 6b343944f..ad0498407 100644 --- a/src/vs/workbench/services/untitled/common/untitledEditorService.ts +++ b/src/vs/workbench/services/untitled/common/untitledEditorService.ts @@ -21,7 +21,7 @@ export const IUntitledEditorService = createDecorator<IUntitledEditorService>('u export interface IModelLoadOrCreateOptions { resource?: URI; - modeId?: string; + mode?: string; initialValue?: string; encoding?: string; useResourcePath?: boolean; @@ -29,7 +29,7 @@ export interface IModelLoadOrCreateOptions { export interface IUntitledEditorService { - _serviceBrand: any; + _serviceBrand: ServiceIdentifier<IUntitledEditorService>; /** * Events for when untitled editors content changes (e.g. any keystroke). @@ -66,6 +66,11 @@ export interface IUntitledEditorService { */ isDirty(resource: URI): boolean; + /** + * Find out if a backup with the provided resource exists and has a backup on disk. + */ + hasBackup(resource: URI): boolean; + /** * Reverts the untitled resources if found. */ @@ -78,7 +83,7 @@ export interface IUntitledEditorService { * It is valid to pass in a file resource. In that case the path will be used as identifier. * The use case is to be able to create a new file with a specific path with VSCode. */ - createOrGet(resource?: URI, modeId?: string, initialValue?: string, encoding?: string): UntitledEditorInput; + createOrGet(resource?: URI, mode?: string, initialValue?: string, encoding?: string): UntitledEditorInput; /** * Creates a new untitled model with the optional resource URI or returns an existing one @@ -113,16 +118,16 @@ export class UntitledEditorService extends Disposable implements IUntitledEditor private mapResourceToAssociatedFilePath = new ResourceMap<boolean>(); private readonly _onDidChangeContent: Emitter<URI> = this._register(new Emitter<URI>()); - get onDidChangeContent(): Event<URI> { return this._onDidChangeContent.event; } + readonly onDidChangeContent: Event<URI> = this._onDidChangeContent.event; private readonly _onDidChangeDirty: Emitter<URI> = this._register(new Emitter<URI>()); - get onDidChangeDirty(): Event<URI> { return this._onDidChangeDirty.event; } + readonly onDidChangeDirty: Event<URI> = this._onDidChangeDirty.event; private readonly _onDidChangeEncoding: Emitter<URI> = this._register(new Emitter<URI>()); - get onDidChangeEncoding(): Event<URI> { return this._onDidChangeEncoding.event; } + readonly onDidChangeEncoding: Event<URI> = this._onDidChangeEncoding.event; private readonly _onDidDisposeModel: Emitter<URI> = this._register(new Emitter<URI>()); - get onDidDisposeModel(): Event<URI> { return this._onDidDisposeModel.event; } + readonly onDidDisposeModel: Event<URI> = this._onDidDisposeModel.event; constructor( @IInstantiationService private readonly instantiationService: IInstantiationService, @@ -170,6 +175,12 @@ export class UntitledEditorService extends Disposable implements IUntitledEditor return input ? input.isDirty() : false; } + hasBackup(resource: URI): boolean { + const input = this.get(resource); + + return input ? input.hasBackup() : false; + } + getDirty(resources?: URI[]): URI[] { let inputs: UntitledEditorInput[]; if (resources) { @@ -184,10 +195,10 @@ export class UntitledEditorService extends Disposable implements IUntitledEditor } loadOrCreate(options: IModelLoadOrCreateOptions = Object.create(null)): Promise<UntitledEditorModel> { - return this.createOrGet(options.resource, options.modeId, options.initialValue, options.encoding, options.useResourcePath).resolve(); + return this.createOrGet(options.resource, options.mode, options.initialValue, options.encoding, options.useResourcePath).resolve(); } - createOrGet(resource?: URI, modeId?: string, initialValue?: string, encoding?: string, hasAssociatedFilePath: boolean = false): UntitledEditorInput { + createOrGet(resource?: URI, mode?: string, initialValue?: string, encoding?: string, hasAssociatedFilePath: boolean = false): UntitledEditorInput { if (resource) { // Massage resource if it comes with known file based resource @@ -207,45 +218,37 @@ export class UntitledEditorService extends Disposable implements IUntitledEditor } // Create new otherwise - return this.doCreate(resource, hasAssociatedFilePath, modeId, initialValue, encoding); + return this.doCreate(resource, hasAssociatedFilePath, mode, initialValue, encoding); } - private doCreate(resource?: URI, hasAssociatedFilePath?: boolean, modeId?: string, initialValue?: string, encoding?: string): UntitledEditorInput { - if (!resource) { + private doCreate(resource?: URI, hasAssociatedFilePath?: boolean, mode?: string, initialValue?: string, encoding?: string): UntitledEditorInput { + let untitledResource: URI; + if (resource) { + untitledResource = resource; + } else { // Create new taking a resource URI that is not already taken let counter = this.mapResourceToInput.size + 1; do { - resource = URI.from({ scheme: Schemas.untitled, path: `Untitled-${counter}` }); + untitledResource = URI.from({ scheme: Schemas.untitled, path: `Untitled-${counter}` }); counter++; - } while (this.mapResourceToInput.has(resource)); + } while (this.mapResourceToInput.has(untitledResource)); } // Look up default language from settings if any - if (!modeId && !hasAssociatedFilePath) { + if (!mode && !hasAssociatedFilePath) { const configuration = this.configurationService.getValue<IFilesConfiguration>(); if (configuration.files && configuration.files.defaultLanguage) { - modeId = configuration.files.defaultLanguage; + mode = configuration.files.defaultLanguage; } } - const input = this.instantiationService.createInstance(UntitledEditorInput, resource, hasAssociatedFilePath, modeId, initialValue, encoding); - - const contentListener = input.onDidModelChangeContent(() => { - this._onDidChangeContent.fire(resource!); - }); - - const dirtyListener = input.onDidChangeDirty(() => { - this._onDidChangeDirty.fire(resource!); - }); - - const encodingListener = input.onDidModelChangeEncoding(() => { - this._onDidChangeEncoding.fire(resource!); - }); + const input = this.instantiationService.createInstance(UntitledEditorInput, untitledResource, hasAssociatedFilePath, mode, initialValue, encoding); - const disposeListener = input.onDispose(() => { - this._onDidDisposeModel.fire(resource!); - }); + const contentListener = input.onDidModelChangeContent(() => this._onDidChangeContent.fire(untitledResource)); + const dirtyListener = input.onDidChangeDirty(() => this._onDidChangeDirty.fire(untitledResource)); + const encodingListener = input.onDidModelChangeEncoding(() => this._onDidChangeEncoding.fire(untitledResource)); + const disposeListener = input.onDispose(() => this._onDidDisposeModel.fire(untitledResource)); // Remove from cache on dispose const onceDispose = Event.once(input.onDispose); @@ -259,7 +262,7 @@ export class UntitledEditorService extends Disposable implements IUntitledEditor }); // Add to cache - this.mapResourceToInput.set(resource, input); + this.mapResourceToInput.set(untitledResource, input); return input; } diff --git a/src/vs/workbench/services/userData/common/fileUserDataProvider.ts b/src/vs/workbench/services/userData/common/fileUserDataProvider.ts new file mode 100644 index 000000000..4bf98510a --- /dev/null +++ b/src/vs/workbench/services/userData/common/fileUserDataProvider.ts @@ -0,0 +1,142 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import { IFileSystemProviderWithFileReadWriteCapability, IFileChange, IWatchOptions, IStat, FileOverwriteOptions, FileType, FileWriteOptions, FileDeleteOptions, FileSystemProviderCapabilities, IFileSystemProviderWithOpenReadWriteCloseCapability, FileOpenOptions, hasReadWriteCapability, hasOpenReadWriteCloseCapability } from 'vs/platform/files/common/files'; +import { URI } from 'vs/base/common/uri'; +import * as resources from 'vs/base/common/resources'; +import { startsWith } from 'vs/base/common/strings'; +import { BACKUPS } from 'vs/platform/environment/common/environment'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; + +export class FileUserDataProvider extends Disposable implements IFileSystemProviderWithFileReadWriteCapability, IFileSystemProviderWithOpenReadWriteCloseCapability { + + readonly capabilities: FileSystemProviderCapabilities = this.fileSystemProvider.capabilities; + readonly onDidChangeCapabilities: Event<void> = Event.None; + + private readonly _onDidChangeFile: Emitter<IFileChange[]> = this._register(new Emitter<IFileChange[]>()); + readonly onDidChangeFile: Event<IFileChange[]> = this._onDidChangeFile.event; + + private readonly userDataHome: URI; + + constructor( + private readonly fileSystemUserDataHome: URI, + private readonly fileSystemBackupsHome: URI, + private readonly fileSystemProvider: IFileSystemProviderWithFileReadWriteCapability | IFileSystemProviderWithOpenReadWriteCloseCapability, + environmentService: IWorkbenchEnvironmentService + ) { + super(); + + this.userDataHome = environmentService.userRoamingDataHome; + + // Assumption: This path always exists + this._register(this.fileSystemProvider.watch(this.fileSystemUserDataHome, { recursive: false, excludes: [] })); + this._register(this.fileSystemProvider.onDidChangeFile(e => this.handleFileChanges(e))); + } + + watch(resource: URI, opts: IWatchOptions): IDisposable { + return this.fileSystemProvider.watch(this.toFileSystemResource(resource), opts); + } + + stat(resource: URI): Promise<IStat> { + return this.fileSystemProvider.stat(this.toFileSystemResource(resource)); + } + + mkdir(resource: URI): Promise<void> { + return this.fileSystemProvider.mkdir(this.toFileSystemResource(resource)); + } + + rename(from: URI, to: URI, opts: FileOverwriteOptions): Promise<void> { + return this.fileSystemProvider.rename(this.toFileSystemResource(from), this.toFileSystemResource(to), opts); + } + + readFile(resource: URI): Promise<Uint8Array> { + if (hasReadWriteCapability(this.fileSystemProvider)) { + return this.fileSystemProvider.readFile(this.toFileSystemResource(resource)); + } + throw new Error('not supported'); + } + + readdir(resource: URI): Promise<[string, FileType][]> { + return this.fileSystemProvider.readdir(this.toFileSystemResource(resource)); + } + + writeFile(resource: URI, content: Uint8Array, opts: FileWriteOptions): Promise<void> { + if (hasReadWriteCapability(this.fileSystemProvider)) { + return this.fileSystemProvider.writeFile(this.toFileSystemResource(resource), content, opts); + } + throw new Error('not supported'); + } + + open(resource: URI, opts: FileOpenOptions): Promise<number> { + if (hasOpenReadWriteCloseCapability(this.fileSystemProvider)) { + return this.fileSystemProvider.open(this.toFileSystemResource(resource), opts); + } + throw new Error('not supported'); + } + + close(fd: number): Promise<void> { + if (hasOpenReadWriteCloseCapability(this.fileSystemProvider)) { + return this.fileSystemProvider.close(fd); + } + throw new Error('not supported'); + } + + read(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise<number> { + if (hasOpenReadWriteCloseCapability(this.fileSystemProvider)) { + return this.fileSystemProvider.read(fd, pos, data, offset, length); + } + throw new Error('not supported'); + } + + write(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise<number> { + if (hasOpenReadWriteCloseCapability(this.fileSystemProvider)) { + return this.fileSystemProvider.write(fd, pos, data, offset, length); + } + throw new Error('not supported'); + } + + delete(resource: URI, opts: FileDeleteOptions): Promise<void> { + return this.fileSystemProvider.delete(this.toFileSystemResource(resource), opts); + } + + private handleFileChanges(changes: IFileChange[]): void { + const userDataChanges: IFileChange[] = []; + for (const change of changes) { + const userDataResource = this.toUserDataResource(change.resource); + if (userDataResource) { + userDataChanges.push({ + resource: userDataResource, + type: change.type + }); + } + } + if (userDataChanges.length) { + this._onDidChangeFile.fire(userDataChanges); + } + } + + private toFileSystemResource(userDataResource: URI): URI { + const relativePath = resources.relativePath(this.userDataHome, userDataResource)!; + if (startsWith(relativePath, BACKUPS)) { + return resources.joinPath(resources.dirname(this.fileSystemBackupsHome), relativePath); + } + return resources.joinPath(this.fileSystemUserDataHome, relativePath); + } + + private toUserDataResource(fileSystemResource: URI): URI | null { + if (resources.isEqualOrParent(fileSystemResource, this.fileSystemUserDataHome)) { + const relativePath = resources.relativePath(this.fileSystemUserDataHome, fileSystemResource); + return relativePath ? resources.joinPath(this.userDataHome, relativePath) : this.userDataHome; + } + if (resources.isEqualOrParent(fileSystemResource, this.fileSystemBackupsHome)) { + const relativePath = resources.relativePath(this.fileSystemBackupsHome, fileSystemResource); + return relativePath ? resources.joinPath(this.userDataHome, BACKUPS, relativePath) : resources.joinPath(this.userDataHome, BACKUPS); + } + return null; + } + +} \ No newline at end of file diff --git a/src/vs/workbench/services/userData/common/inMemoryUserDataProvider.ts b/src/vs/workbench/services/userData/common/inMemoryUserDataProvider.ts new file mode 100644 index 000000000..ffed9c53d --- /dev/null +++ b/src/vs/workbench/services/userData/common/inMemoryUserDataProvider.ts @@ -0,0 +1,232 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import * as resources from 'vs/base/common/resources'; +import { FileChangeType, IFileSystemProvider, FileType, IWatchOptions, IStat, FileSystemProviderErrorCode, FileSystemProviderError, FileWriteOptions, IFileChange, FileDeleteOptions, FileSystemProviderCapabilities, FileOverwriteOptions } from 'vs/platform/files/common/files'; +import { URI } from 'vs/base/common/uri'; + +class File implements IStat { + + type: FileType; + ctime: number; + mtime: number; + size: number; + + name: string; + data?: Uint8Array; + + constructor(name: string) { + this.type = FileType.File; + this.ctime = Date.now(); + this.mtime = Date.now(); + this.size = 0; + this.name = name; + } +} + +class Directory implements IStat { + + type: FileType; + ctime: number; + mtime: number; + size: number; + + name: string; + entries: Map<string, File | Directory>; + + constructor(name: string) { + this.type = FileType.Directory; + this.ctime = Date.now(); + this.mtime = Date.now(); + this.size = 0; + this.name = name; + this.entries = new Map(); + } +} + +export type Entry = File | Directory; + +export class InMemoryUserDataProvider extends Disposable implements IFileSystemProvider { + + readonly capabilities: FileSystemProviderCapabilities = FileSystemProviderCapabilities.FileReadWrite; + readonly onDidChangeCapabilities: Event<void> = Event.None; + + root = new Directory(''); + + // --- manage file metadata + + async stat(resource: URI): Promise<IStat> { + return this._lookup(resource, false); + } + + async readdir(resource: URI): Promise<[string, FileType][]> { + const entry = this._lookupAsDirectory(resource, false); + let result: [string, FileType][] = []; + for (const [name, child] of entry.entries) { + result.push([name, child.type]); + } + return result; + } + + // --- manage file contents + + async readFile(resource: URI): Promise<Uint8Array> { + const data = this._lookupAsFile(resource, false).data; + if (data) { + return data; + } + throw new FileSystemProviderError('file not found', FileSystemProviderErrorCode.FileNotFound); + } + + async writeFile(resource: URI, content: Uint8Array, opts: FileWriteOptions): Promise<void> { + let basename = resources.basename(resource); + let parent = this._lookupParentDirectory(resource); + let entry = parent.entries.get(basename); + if (entry instanceof Directory) { + throw new FileSystemProviderError('file is directory', FileSystemProviderErrorCode.FileIsADirectory); + } + if (!entry && !opts.create) { + throw new FileSystemProviderError('file not found', FileSystemProviderErrorCode.FileNotFound); + } + if (entry && opts.create && !opts.overwrite) { + throw new FileSystemProviderError('file exists already', FileSystemProviderErrorCode.FileExists); + } + if (!entry) { + entry = new File(basename); + parent.entries.set(basename, entry); + this._fireSoon({ type: FileChangeType.ADDED, resource }); + } + entry.mtime = Date.now(); + entry.size = content.byteLength; + entry.data = content; + + this._fireSoon({ type: FileChangeType.UPDATED, resource }); + } + + // --- manage files/folders + + async rename(from: URI, to: URI, opts: FileOverwriteOptions): Promise<void> { + if (!opts.overwrite && this._lookup(to, true)) { + throw new FileSystemProviderError('file exists already', FileSystemProviderErrorCode.FileExists); + } + + let entry = this._lookup(from, false); + let oldParent = this._lookupParentDirectory(from); + + let newParent = this._lookupParentDirectory(to); + let newName = resources.basename(to); + + oldParent.entries.delete(entry.name); + entry.name = newName; + newParent.entries.set(newName, entry); + + this._fireSoon( + { type: FileChangeType.DELETED, resource: from }, + { type: FileChangeType.ADDED, resource: to } + ); + } + + async delete(resource: URI, opts: FileDeleteOptions): Promise<void> { + let dirname = resources.dirname(resource); + let basename = resources.basename(resource); + let parent = this._lookupAsDirectory(dirname, false); + if (!parent.entries.has(basename)) { + throw new FileSystemProviderError('file not found', FileSystemProviderErrorCode.FileNotFound); + } + parent.entries.delete(basename); + parent.mtime = Date.now(); + parent.size -= 1; + this._fireSoon({ type: FileChangeType.UPDATED, resource: dirname }, { resource, type: FileChangeType.DELETED }); + } + + async mkdir(resource: URI): Promise<void> { + let basename = resources.basename(resource); + let dirname = resources.dirname(resource); + let parent = this._lookupAsDirectory(dirname, false); + + let entry = new Directory(basename); + parent.entries.set(entry.name, entry); + parent.mtime = Date.now(); + parent.size += 1; + this._fireSoon({ type: FileChangeType.UPDATED, resource: dirname }, { type: FileChangeType.ADDED, resource }); + } + + // --- lookup + + private _lookup(uri: URI, silent: false): Entry; + private _lookup(uri: URI, silent: boolean): Entry | undefined; + private _lookup(uri: URI, silent: boolean): Entry | undefined { + let parts = uri.path.split('/'); + let entry: Entry = this.root; + for (const part of parts) { + if (!part) { + continue; + } + let child: Entry | undefined; + if (entry instanceof Directory) { + child = entry.entries.get(part); + } + if (!child) { + if (!silent) { + throw new FileSystemProviderError('file not found', FileSystemProviderErrorCode.FileNotFound); + } else { + return undefined; + } + } + entry = child; + } + return entry; + } + + private _lookupAsDirectory(uri: URI, silent: boolean): Directory { + let entry = this._lookup(uri, silent); + if (entry instanceof Directory) { + return entry; + } + throw new FileSystemProviderError('file not a directory', FileSystemProviderErrorCode.FileNotADirectory); + } + + private _lookupAsFile(uri: URI, silent: boolean): File { + let entry = this._lookup(uri, silent); + if (entry instanceof File) { + return entry; + } + throw new FileSystemProviderError('file is a directory', FileSystemProviderErrorCode.FileIsADirectory); + } + + private _lookupParentDirectory(uri: URI): Directory { + const dirname = resources.dirname(uri); + return this._lookupAsDirectory(dirname, false); + } + + // --- manage file events + + private readonly _onDidChangeFile: Emitter<IFileChange[]> = this._register(new Emitter<IFileChange[]>()); + readonly onDidChangeFile: Event<IFileChange[]> = this._onDidChangeFile.event; + + private _bufferedChanges: IFileChange[] = []; + private _fireSoonHandle?: NodeJS.Timer; + + + watch(resource: URI, opts: IWatchOptions): IDisposable { + // ignore, fires for all changes... + return Disposable.None; + } + + private _fireSoon(...changes: IFileChange[]): void { + this._bufferedChanges.push(...changes); + + if (this._fireSoonHandle) { + clearTimeout(this._fireSoonHandle); + } + + this._fireSoonHandle = setTimeout(() => { + this._onDidChangeFile.fire(this._bufferedChanges); + this._bufferedChanges.length = 0; + }, 5); + } +} \ No newline at end of file diff --git a/src/vs/workbench/services/userData/test/electron-browser/fileUserDataProvider.test.ts b/src/vs/workbench/services/userData/test/electron-browser/fileUserDataProvider.test.ts new file mode 100644 index 000000000..b8ba819bb --- /dev/null +++ b/src/vs/workbench/services/userData/test/electron-browser/fileUserDataProvider.test.ts @@ -0,0 +1,478 @@ +/*--------------------------------------------------------------------------------------------- + * 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 os from 'os'; +import * as path from 'vs/base/common/path'; +import * as uuid from 'vs/base/common/uuid'; +import * as pfs from 'vs/base/node/pfs'; +import { IFileService, FileChangeType, IFileChange, IFileSystemProviderWithFileReadWriteCapability, IStat, FileType, FileSystemProviderCapabilities } from 'vs/platform/files/common/files'; +import { FileService } from 'vs/platform/files/common/fileService'; +import { NullLogService } from 'vs/platform/log/common/log'; +import { Schemas } from 'vs/base/common/network'; +import { URI } from 'vs/base/common/uri'; +import { FileUserDataProvider } from 'vs/workbench/services/userData/common/fileUserDataProvider'; +import { joinPath, dirname } from 'vs/base/common/resources'; +import { VSBuffer } from 'vs/base/common/buffer'; +import { DiskFileSystemProvider } from 'vs/platform/files/electron-browser/diskFileSystemProvider'; +import { BACKUPS } from 'vs/platform/environment/common/environment'; +import { DisposableStore, IDisposable, Disposable } from 'vs/base/common/lifecycle'; +import { BrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService'; +import { Emitter, Event } from 'vs/base/common/event'; +import { timeout } from 'vs/base/common/async'; + +suite('FileUserDataProvider', () => { + + let testObject: IFileService; + let rootPath: string; + let userDataPath: string; + let backupsPath: string; + let userDataResource: URI; + const disposables = new DisposableStore(); + + setup(async () => { + const logService = new NullLogService(); + testObject = new FileService(logService); + disposables.add(testObject); + + const diskFileSystemProvider = new DiskFileSystemProvider(logService); + disposables.add(diskFileSystemProvider); + disposables.add(testObject.registerProvider(Schemas.file, diskFileSystemProvider)); + + rootPath = path.join(os.tmpdir(), 'vsctests', uuid.generateUuid()); + userDataPath = path.join(rootPath, 'user'); + backupsPath = path.join(rootPath, BACKUPS); + userDataResource = URI.file(userDataPath).with({ scheme: Schemas.userData }); + await Promise.all([pfs.mkdirp(userDataPath), pfs.mkdirp(backupsPath)]); + + const environmentService = new BrowserWorkbenchEnvironmentService({ workspaceId: 'workspaceId' }); + environmentService.userRoamingDataHome = userDataResource; + + const userDataFileSystemProvider = new FileUserDataProvider(URI.file(userDataPath), URI.file(backupsPath), diskFileSystemProvider, environmentService); + disposables.add(userDataFileSystemProvider); + disposables.add(testObject.registerProvider(Schemas.userData, userDataFileSystemProvider)); + }); + + teardown(async () => { + disposables.clear(); + await pfs.rimraf(rootPath, pfs.RimRafMode.MOVE); + }); + + test('exists return false when file does not exist', async () => { + const exists = await testObject.exists(joinPath(userDataResource, 'settings.json')); + assert.equal(exists, false); + }); + + test('read file throws error if not exist', async () => { + try { + await testObject.readFile(joinPath(userDataResource, 'settings.json')); + assert.fail('Should fail since file does not exist'); + } catch (e) { } + }); + + test('read existing file', async () => { + await pfs.writeFile(path.join(userDataPath, 'settings.json'), '{}'); + const result = await testObject.readFile(joinPath(userDataResource, 'settings.json')); + assert.equal(result.value, '{}'); + }); + + test('create file', async () => { + const resource = joinPath(userDataResource, 'settings.json'); + const actual1 = await testObject.createFile(resource, VSBuffer.fromString('{}')); + assert.equal(actual1.resource.toString(), resource.toString()); + const actual2 = await pfs.readFile(path.join(userDataPath, 'settings.json')); + assert.equal(actual2, '{}'); + }); + + test('write file creates the file if not exist', async () => { + const resource = joinPath(userDataResource, 'settings.json'); + const actual1 = await testObject.writeFile(resource, VSBuffer.fromString('{}')); + assert.equal(actual1.resource.toString(), resource.toString()); + const actual2 = await pfs.readFile(path.join(userDataPath, 'settings.json')); + assert.equal(actual2, '{}'); + }); + + test('write to existing file', async () => { + const resource = joinPath(userDataResource, 'settings.json'); + await pfs.writeFile(path.join(userDataPath, 'settings.json'), '{}'); + const actual1 = await testObject.writeFile(resource, VSBuffer.fromString('{a:1}')); + assert.equal(actual1.resource.toString(), resource.toString()); + const actual2 = await pfs.readFile(path.join(userDataPath, 'settings.json')); + assert.equal(actual2, '{a:1}'); + }); + + test('delete file', async () => { + await pfs.writeFile(path.join(userDataPath, 'settings.json'), ''); + await testObject.del(joinPath(userDataResource, 'settings.json')); + const result = await pfs.exists(path.join(userDataPath, 'settings.json')); + assert.equal(false, result); + }); + + test('resolve file', async () => { + await pfs.writeFile(path.join(userDataPath, 'settings.json'), ''); + const result = await testObject.resolve(joinPath(userDataResource, 'settings.json')); + assert.ok(!result.isDirectory); + assert.ok(result.children === undefined); + }); + + test('exists return false for folder that does not exist', async () => { + const exists = await testObject.exists(joinPath(userDataResource, 'snippets')); + assert.equal(exists, false); + }); + + test('exists return true for folder that exists', async () => { + await pfs.mkdirp(path.join(userDataPath, 'snippets')); + const exists = await testObject.exists(joinPath(userDataResource, 'snippets')); + assert.equal(exists, true); + }); + + test('read file throws error for folder', async () => { + await pfs.mkdirp(path.join(userDataPath, 'snippets')); + try { + await testObject.readFile(joinPath(userDataResource, 'snippets')); + assert.fail('Should fail since read file is not supported for folders'); + } catch (e) { } + }); + + test('read file under folder', async () => { + await pfs.mkdirp(path.join(userDataPath, 'snippets')); + await pfs.writeFile(path.join(userDataPath, 'snippets', 'settings.json'), '{}'); + const resource = joinPath(userDataResource, 'snippets/settings.json'); + const actual = await testObject.readFile(resource); + assert.equal(actual.resource.toString(), resource.toString()); + assert.equal(actual.value, '{}'); + }); + + test('read file under sub folder', async () => { + await pfs.mkdirp(path.join(userDataPath, 'snippets', 'java')); + await pfs.writeFile(path.join(userDataPath, 'snippets', 'java', 'settings.json'), '{}'); + const resource = joinPath(userDataResource, 'snippets/java/settings.json'); + const actual = await testObject.readFile(resource); + assert.equal(actual.resource.toString(), resource.toString()); + assert.equal(actual.value, '{}'); + }); + + test('create file under folder that exists', async () => { + await pfs.mkdirp(path.join(userDataPath, 'snippets')); + const resource = joinPath(userDataResource, 'snippets/settings.json'); + const actual1 = await testObject.createFile(resource, VSBuffer.fromString('{}')); + assert.equal(actual1.resource.toString(), resource.toString()); + const actual2 = await pfs.readFile(path.join(userDataPath, 'snippets', 'settings.json')); + assert.equal(actual2, '{}'); + }); + + test('create file under folder that does not exist', async () => { + const resource = joinPath(userDataResource, 'snippets/settings.json'); + const actual1 = await testObject.createFile(resource, VSBuffer.fromString('{}')); + assert.equal(actual1.resource.toString(), resource.toString()); + const actual2 = await pfs.readFile(path.join(userDataPath, 'snippets', 'settings.json')); + assert.equal(actual2, '{}'); + }); + + test('write to not existing file under container that exists', async () => { + await pfs.mkdirp(path.join(userDataPath, 'snippets')); + const resource = joinPath(userDataResource, 'snippets/settings.json'); + const actual1 = await testObject.writeFile(resource, VSBuffer.fromString('{}')); + assert.equal(actual1.resource.toString(), resource.toString()); + const actual = await pfs.readFile(path.join(userDataPath, 'snippets', 'settings.json')); + assert.equal(actual, '{}'); + }); + + test('write to not existing file under container that does not exists', async () => { + const resource = joinPath(userDataResource, 'snippets/settings.json'); + const actual1 = await testObject.writeFile(resource, VSBuffer.fromString('{}')); + assert.equal(actual1.resource.toString(), resource.toString()); + const actual = await pfs.readFile(path.join(userDataPath, 'snippets', 'settings.json')); + assert.equal(actual, '{}'); + }); + + test('write to existing file under container', async () => { + await pfs.mkdirp(path.join(userDataPath, 'snippets')); + await pfs.writeFile(path.join(userDataPath, 'snippets', 'settings.json'), '{}'); + const resource = joinPath(userDataResource, 'snippets/settings.json'); + const actual1 = await testObject.writeFile(resource, VSBuffer.fromString('{a:1}')); + assert.equal(actual1.resource.toString(), resource.toString()); + const actual = await pfs.readFile(path.join(userDataPath, 'snippets', 'settings.json')); + assert.equal(actual.toString(), '{a:1}'); + }); + + test('write file under sub container', async () => { + const resource = joinPath(userDataResource, 'snippets/java/settings.json'); + const actual1 = await testObject.writeFile(resource, VSBuffer.fromString('{}')); + assert.equal(actual1.resource.toString(), resource.toString()); + const actual = await pfs.readFile(path.join(userDataPath, 'snippets', 'java', 'settings.json')); + assert.equal(actual, '{}'); + }); + + test('delete throws error for folder that does not exist', async () => { + try { + await testObject.del(joinPath(userDataResource, 'snippets')); + assert.fail('Should fail the folder does not exist'); + } catch (e) { } + }); + + test('delete not existing file under container that exists', async () => { + await pfs.mkdirp(path.join(userDataPath, 'snippets')); + try { + await testObject.del(joinPath(userDataResource, 'snippets/settings.json')); + assert.fail('Should fail since file does not exist'); + } catch (e) { } + }); + + test('delete not existing file under container that does not exists', async () => { + try { + await testObject.del(joinPath(userDataResource, 'snippets/settings.json')); + assert.fail('Should fail since file does not exist'); + } catch (e) { } + }); + + test('delete existing file under folder', async () => { + await pfs.mkdirp(path.join(userDataPath, 'snippets')); + await pfs.writeFile(path.join(userDataPath, 'snippets', 'settings.json'), '{}'); + await testObject.del(joinPath(userDataResource, 'snippets/settings.json')); + const exists = await pfs.exists(path.join(userDataPath, 'snippets', 'settings.json')); + assert.equal(exists, false); + }); + + test('resolve folder', async () => { + await pfs.mkdirp(path.join(userDataPath, 'snippets')); + await pfs.writeFile(path.join(userDataPath, 'snippets', 'settings.json'), '{}'); + const result = await testObject.resolve(joinPath(userDataResource, 'snippets')); + assert.ok(result.isDirectory); + assert.ok(result.children !== undefined); + assert.equal(result.children!.length, 1); + assert.equal(result.children![0].resource.toString(), joinPath(userDataResource, 'snippets/settings.json').toString()); + }); + + test('read backup file', async () => { + await pfs.writeFile(path.join(backupsPath, 'backup.json'), '{}'); + const result = await testObject.readFile(joinPath(userDataResource, `${BACKUPS}/backup.json`)); + assert.equal(result.value, '{}'); + }); + + test('create backup file', async () => { + await testObject.createFile(joinPath(userDataResource, `${BACKUPS}/backup.json`), VSBuffer.fromString('{}')); + const result = await pfs.readFile(path.join(backupsPath, 'backup.json')); + assert.equal(result, '{}'); + }); + + test('write backup file', async () => { + await pfs.writeFile(path.join(backupsPath, 'backup.json'), '{}'); + await testObject.writeFile(joinPath(userDataResource, `${BACKUPS}/backup.json`), VSBuffer.fromString('{a:1}')); + const result = await pfs.readFile(path.join(backupsPath, 'backup.json')); + assert.equal(result, '{a:1}'); + }); + + test('resolve backups folder', async () => { + await pfs.writeFile(path.join(backupsPath, 'backup.json'), '{}'); + const result = await testObject.resolve(joinPath(userDataResource, BACKUPS)); + assert.ok(result.isDirectory); + assert.ok(result.children !== undefined); + assert.equal(result.children!.length, 1); + assert.equal(result.children![0].resource.toString(), joinPath(userDataResource, `${BACKUPS}/backup.json`).toString()); + }); +}); + +class TestFileSystemProvider implements IFileSystemProviderWithFileReadWriteCapability { + + constructor(readonly onDidChangeFile: Event<IFileChange[]>) { } + + readonly capabilities: FileSystemProviderCapabilities = FileSystemProviderCapabilities.FileReadWrite; + + readonly onDidChangeCapabilities: Event<void> = Event.None; + + watch(): IDisposable { return Disposable.None; } + + stat(): Promise<IStat> { throw new Error('Not Supported'); } + + mkdir(resource: URI): Promise<void> { throw new Error('Not Supported'); } + + rename(): Promise<void> { throw new Error('Not Supported'); } + + readFile(resource: URI): Promise<Uint8Array> { throw new Error('Not Supported'); } + + readdir(resource: URI): Promise<[string, FileType][]> { throw new Error('Not Supported'); } + + writeFile(): Promise<void> { throw new Error('Not Supported'); } + + delete(): Promise<void> { throw new Error('Not Supported'); } + +} + +suite('FileUserDataProvider - Watching', () => { + + let testObject: IFileService; + let localBackupsResource: URI; + let localUserDataResource: URI; + let userDataResource: URI; + const disposables = new DisposableStore(); + + const fileEventEmitter: Emitter<IFileChange[]> = new Emitter<IFileChange[]>(); + disposables.add(fileEventEmitter); + + setup(() => { + + const rootPath = path.join(os.tmpdir(), 'vsctests', uuid.generateUuid()); + const userDataPath = path.join(rootPath, 'user'); + const backupsPath = path.join(rootPath, BACKUPS); + localBackupsResource = URI.file(backupsPath); + localUserDataResource = URI.file(userDataPath); + userDataResource = localUserDataResource.with({ scheme: Schemas.userData }); + + const environmentService = new BrowserWorkbenchEnvironmentService({ workspaceId: 'workspaceId' }); + environmentService.userRoamingDataHome = userDataResource; + + const userDataFileSystemProvider = new FileUserDataProvider(localUserDataResource, localBackupsResource, new TestFileSystemProvider(fileEventEmitter.event), environmentService); + disposables.add(userDataFileSystemProvider); + + testObject = new FileService(new NullLogService()); + disposables.add(testObject); + disposables.add(testObject.registerProvider(Schemas.userData, userDataFileSystemProvider)); + }); + + teardown(() => { + disposables.clear(); + }); + + test('file added change event', done => { + const expected = joinPath(userDataResource, 'settings.json'); + const target = joinPath(localUserDataResource, 'settings.json'); + testObject.onFileChanges(e => { + if (e.contains(expected, FileChangeType.ADDED)) { + done(); + } + }); + fileEventEmitter.fire([{ + resource: target, + type: FileChangeType.ADDED + }]); + }); + + test('file updated change event', done => { + const expected = joinPath(userDataResource, 'settings.json'); + const target = joinPath(localUserDataResource, 'settings.json'); + testObject.onFileChanges(e => { + if (e.contains(expected, FileChangeType.UPDATED)) { + done(); + } + }); + fileEventEmitter.fire([{ + resource: target, + type: FileChangeType.UPDATED + }]); + }); + + test('file deleted change event', done => { + const expected = joinPath(userDataResource, 'settings.json'); + const target = joinPath(localUserDataResource, 'settings.json'); + testObject.onFileChanges(e => { + if (e.contains(expected, FileChangeType.DELETED)) { + done(); + } + }); + fileEventEmitter.fire([{ + resource: target, + type: FileChangeType.DELETED + }]); + }); + + test('file under folder created change event', done => { + const expected = joinPath(userDataResource, 'snippets', 'settings.json'); + const target = joinPath(localUserDataResource, 'snippets', 'settings.json'); + testObject.onFileChanges(e => { + if (e.contains(expected, FileChangeType.ADDED)) { + done(); + } + }); + fileEventEmitter.fire([{ + resource: target, + type: FileChangeType.ADDED + }]); + }); + + test('file under folder updated change event', done => { + const expected = joinPath(userDataResource, 'snippets', 'settings.json'); + const target = joinPath(localUserDataResource, 'snippets', 'settings.json'); + testObject.onFileChanges(e => { + if (e.contains(expected, FileChangeType.UPDATED)) { + done(); + } + }); + fileEventEmitter.fire([{ + resource: target, + type: FileChangeType.UPDATED + }]); + }); + + test('file under folder deleted change event', done => { + const expected = joinPath(userDataResource, 'snippets', 'settings.json'); + const target = joinPath(localUserDataResource, 'snippets', 'settings.json'); + testObject.onFileChanges(e => { + if (e.contains(expected, FileChangeType.DELETED)) { + done(); + } + }); + fileEventEmitter.fire([{ + resource: target, + type: FileChangeType.DELETED + }]); + }); + + test('event is not triggered if file is not under user data', async () => { + const target = joinPath(dirname(localUserDataResource), 'settings.json'); + let triggered = false; + testObject.onFileChanges(() => triggered = true); + fileEventEmitter.fire([{ + resource: target, + type: FileChangeType.DELETED + }]); + await timeout(0); + if (triggered) { + assert.fail('event should not be triggered'); + } + }); + + test('backup file created change event', done => { + const expected = joinPath(userDataResource, BACKUPS, 'settings.json'); + const target = joinPath(localBackupsResource, 'settings.json'); + testObject.onFileChanges(e => { + if (e.contains(expected, FileChangeType.ADDED)) { + done(); + } + }); + fileEventEmitter.fire([{ + resource: target, + type: FileChangeType.ADDED + }]); + }); + + test('backup file update change event', done => { + const expected = joinPath(userDataResource, BACKUPS, 'settings.json'); + const target = joinPath(localBackupsResource, 'settings.json'); + testObject.onFileChanges(e => { + if (e.contains(expected, FileChangeType.UPDATED)) { + done(); + } + }); + fileEventEmitter.fire([{ + resource: target, + type: FileChangeType.UPDATED + }]); + }); + + test('backup file delete change event', done => { + const expected = joinPath(userDataResource, BACKUPS, 'settings.json'); + const target = joinPath(localBackupsResource, 'settings.json'); + testObject.onFileChanges(e => { + if (e.contains(expected, FileChangeType.DELETED)) { + done(); + } + }); + fileEventEmitter.fire([{ + resource: target, + type: FileChangeType.DELETED + }]); + }); +}); \ No newline at end of file diff --git a/src/vs/workbench/services/viewlet/browser/viewlet.ts b/src/vs/workbench/services/viewlet/browser/viewlet.ts index 3883013c4..92349b87a 100644 --- a/src/vs/workbench/services/viewlet/browser/viewlet.ts +++ b/src/vs/workbench/services/viewlet/browser/viewlet.ts @@ -7,17 +7,18 @@ import { IViewlet } from 'vs/workbench/common/viewlet'; import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; import { Event } from 'vs/base/common/event'; import { ViewletDescriptor } from 'vs/workbench/browser/viewlet'; -import { IProgressService } from 'vs/platform/progress/common/progress'; +import { IProgressIndicator } from 'vs/platform/progress/common/progress'; export const IViewletService = createDecorator<IViewletService>('viewletService'); export interface IViewletService { + _serviceBrand: ServiceIdentifier<any>; - onDidViewletRegister: Event<ViewletDescriptor>; - onDidViewletDeregister: Event<ViewletDescriptor>; - onDidViewletOpen: Event<IViewlet>; - onDidViewletClose: Event<IViewlet>; + readonly onDidViewletRegister: Event<ViewletDescriptor>; + readonly onDidViewletDeregister: Event<ViewletDescriptor>; + readonly onDidViewletOpen: Event<IViewlet>; + readonly onDidViewletClose: Event<IViewlet>; /** * Opens a viewlet with the given identifier and pass keyboard focus to it if specified. @@ -47,7 +48,7 @@ export interface IViewletService { /** * Returns the progress indicator for the side bar. */ - getProgressIndicator(id: string): IProgressService | null; + getProgressIndicator(id: string): IProgressIndicator | null; /** * Hide the active viewlet. diff --git a/src/vs/workbench/services/window/electron-browser/windowService.ts b/src/vs/workbench/services/window/electron-browser/windowService.ts index d3975f0ac..031e01558 100644 --- a/src/vs/workbench/services/window/electron-browser/windowService.ts +++ b/src/vs/workbench/services/window/electron-browser/windowService.ts @@ -5,7 +5,7 @@ import { Event } from 'vs/base/common/event'; import { IWindowService, IWindowsService, INativeOpenDialogOptions, IEnterWorkspaceResult, IMessageBoxResult, IDevToolsOptions, IOpenSettings, IURIToOpen, isFolderToOpen, isWorkspaceToOpen } from 'vs/platform/windows/common/windows'; -import { IRecentlyOpened } from 'vs/platform/history/common/history'; +import { IRecentlyOpened, IRecent } from 'vs/platform/history/common/history'; import { ISerializableCommandAction } from 'vs/platform/actions/common/actions'; import { ParsedArgs } from 'vs/platform/environment/common/environment'; import { URI } from 'vs/base/common/uri'; @@ -109,7 +109,7 @@ export class WindowService extends Disposable implements IWindowService { return this.windowsService.closeWindow(this.windowId); } - toggleFullScreen(): Promise<void> { + toggleFullScreen(target?: HTMLElement): Promise<void> { return this.windowsService.toggleFullScreen(this.windowId); } @@ -121,6 +121,14 @@ export class WindowService extends Disposable implements IWindowService { return this.windowsService.getRecentlyOpened(this.windowId); } + addRecentlyOpened(recents: IRecent[]): Promise<void> { + return this.windowsService.addRecentlyOpened(recents); + } + + removeFromRecentlyOpened(paths: URI[]): Promise<void> { + return this.windowsService.removeFromRecentlyOpened(paths); + } + focusWindow(): Promise<void> { return this.windowsService.focusWindow(this.windowId); } diff --git a/src/vs/workbench/services/workspace/electron-browser/workspaceEditingService.ts b/src/vs/workbench/services/workspace/electron-browser/workspaceEditingService.ts index b09b8d1d5..500f4761c 100644 --- a/src/vs/workbench/services/workspace/electron-browser/workspaceEditingService.ts +++ b/src/vs/workbench/services/workspace/electron-browser/workspaceEditingService.ts @@ -16,8 +16,8 @@ import { StorageService } from 'vs/platform/storage/node/storageService'; import { ConfigurationScope, IConfigurationRegistry, Extensions as ConfigurationExtensions, IConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry'; import { Registry } from 'vs/platform/registry/common/platform'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; -import { BackupFileService } from 'vs/workbench/services/backup/node/backupFileService'; +import { IBackupFileService, toBackupWorkspaceResource } from 'vs/workbench/services/backup/common/backup'; +import { BackupFileService } from 'vs/workbench/services/backup/common/backupFileService'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { distinct } from 'vs/base/common/arrays'; import { isLinux, isWindows, isMacintosh } from 'vs/base/common/platform'; @@ -32,10 +32,11 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { ILabelService } from 'vs/platform/label/common/label'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; +import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; export class WorkspaceEditingService implements IWorkspaceEditingService { - _serviceBrand: any; + _serviceBrand: ServiceIdentifier<IWorkspaceEditingService>; constructor( @IJSONEditingService private readonly jsonEditingService: IJSONEditingService, @@ -57,83 +58,93 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { @ILifecycleService readonly lifecycleService: ILifecycleService, @ILabelService readonly labelService: ILabelService ) { + this.registerListeners(); + } - lifecycleService.onBeforeShutdown(async e => { + private registerListeners(): void { + this.lifecycleService.onBeforeShutdown(async e => { const saveOperation = this.saveUntitedBeforeShutdown(e.reason); if (saveOperation) { e.veto(saveOperation); } }); - } - private saveUntitedBeforeShutdown(reason: ShutdownReason): Promise<boolean> | undefined { + private async saveUntitedBeforeShutdown(reason: ShutdownReason): Promise<boolean> { if (reason !== ShutdownReason.LOAD && reason !== ShutdownReason.CLOSE) { - return undefined; // only interested when window is closing or loading + return false; // only interested when window is closing or loading } + const workspaceIdentifier = this.getCurrentWorkspaceIdentifier(); if (!workspaceIdentifier || !isEqualOrParent(workspaceIdentifier.configPath, this.environmentService.untitledWorkspacesHome)) { - return undefined; // only care about untitled workspaces to ask for saving + return false; // only care about untitled workspaces to ask for saving } - return this.windowsService.getWindowCount().then(windowCount => { - if (reason === ShutdownReason.CLOSE && !isMacintosh && windowCount === 1) { - return false; // Windows/Linux: quits when last window is closed, so do not ask then - } - enum ConfirmResult { - SAVE, - DONT_SAVE, - CANCEL - } + const windowCount = await this.windowsService.getWindowCount(); - const save = { label: mnemonicButtonLabel(nls.localize('save', "Save")), result: ConfirmResult.SAVE }; - const dontSave = { label: mnemonicButtonLabel(nls.localize('doNotSave', "Don't Save")), result: ConfirmResult.DONT_SAVE }; - const cancel = { label: nls.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); - } + if (reason === ShutdownReason.CLOSE && !isMacintosh && windowCount === 1) { + return false; // Windows/Linux: quits when last window is closed, so do not ask then + } + + enum ConfirmResult { + SAVE, + DONT_SAVE, + CANCEL + } - const message = nls.localize('saveWorkspaceMessage', "Do you want to save your workspace configuration as a file?"); - const detail = nls.localize('saveWorkspaceDetail', "Save your workspace if you plan to open it again."); - const cancelId = buttons.indexOf(cancel); - - return this.dialogService.show(Severity.Warning, message, buttons.map(button => button.label), { detail, cancelId }).then(res => { - switch (buttons[res].result) { - - // Cancel: veto unload - case ConfirmResult.CANCEL: - return true; - - // Don't Save: delete workspace - case ConfirmResult.DONT_SAVE: - this.workspaceService.deleteUntitledWorkspace(workspaceIdentifier); - return false; - - // Save: save workspace, but do not veto unload - case ConfirmResult.SAVE: { - return this.pickNewWorkspacePath().then(newWorkspacePath => { - if (newWorkspacePath) { - return this.saveWorkspaceAs(workspaceIdentifier, newWorkspacePath).then(_ => { - return this.workspaceService.getWorkspaceIdentifier(newWorkspacePath).then(newWorkspaceIdentifier => { - const label = this.labelService.getWorkspaceLabel(newWorkspaceIdentifier, { verbose: true }); - this.windowsService.addRecentlyOpened([{ label, workspace: newWorkspaceIdentifier }]); - this.workspaceService.deleteUntitledWorkspace(workspaceIdentifier); - return false; - }); - }, () => false); - } - return true; // keep veto if no target was provided - }); - } + const save = { label: mnemonicButtonLabel(nls.localize('save', "Save")), result: ConfirmResult.SAVE }; + const dontSave = { label: mnemonicButtonLabel(nls.localize('doNotSave', "Don't Save")), result: ConfirmResult.DONT_SAVE }; + const cancel = { label: nls.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 message = nls.localize('saveWorkspaceMessage', "Do you want to save your workspace configuration as a file?"); + const detail = nls.localize('saveWorkspaceDetail', "Save your workspace if you plan to open it again."); + const cancelId = buttons.indexOf(cancel); + + const res = await this.dialogService.show(Severity.Warning, message, buttons.map(button => button.label), { detail, cancelId }); + + switch (buttons[res].result) { + + // Cancel: veto unload + case ConfirmResult.CANCEL: + return true; + + // Don't Save: delete workspace + case ConfirmResult.DONT_SAVE: + this.workspaceService.deleteUntitledWorkspace(workspaceIdentifier); + return false; + + // Save: save workspace, but do not veto unload if path provided + case ConfirmResult.SAVE: { + const newWorkspacePath = await this.pickNewWorkspacePath(); + if (!newWorkspacePath) { + return true; // keep veto if no target was provided } - }); - }); + + try { + await this.saveWorkspaceAs(workspaceIdentifier, newWorkspacePath); + + const newWorkspaceIdentifier = await this.workspaceService.getWorkspaceIdentifier(newWorkspacePath); + + const label = this.labelService.getWorkspaceLabel(newWorkspaceIdentifier, { verbose: true }); + this.windowService.addRecentlyOpened([{ label, workspace: newWorkspaceIdentifier }]); + + this.workspaceService.deleteUntitledWorkspace(workspaceIdentifier); + } catch (error) { + // ignore + } + + return false; + } + } } pickNewWorkspacePath(): Promise<URI | undefined> { @@ -190,17 +201,31 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { } } - private doUpdateFolders(foldersToAdd: IWorkspaceFolderCreationData[], foldersToDelete: URI[], index?: number, donotNotifyError: boolean = false): Promise<void> { - return this.contextService.updateFolders(foldersToAdd, foldersToDelete, index) - .then(() => null, error => donotNotifyError ? Promise.reject(error) : this.handleWorkspaceConfigurationEditingError(error)); + private async doUpdateFolders(foldersToAdd: IWorkspaceFolderCreationData[], foldersToDelete: URI[], index?: number, donotNotifyError: boolean = false): Promise<void> { + try { + await this.contextService.updateFolders(foldersToAdd, foldersToDelete, index); + } catch (error) { + if (donotNotifyError) { + throw error; + } + + this.handleWorkspaceConfigurationEditingError(error); + } } addFolders(foldersToAdd: IWorkspaceFolderCreationData[], donotNotifyError: boolean = false): Promise<void> { return this.doAddFolders(foldersToAdd, undefined, donotNotifyError); } - private doAddFolders(foldersToAdd: IWorkspaceFolderCreationData[], index?: number, donotNotifyError: boolean = false): Promise<void> { + private async doAddFolders(foldersToAdd: IWorkspaceFolderCreationData[], index?: number, donotNotifyError: boolean = false): Promise<void> { const state = this.contextService.getWorkbenchState(); + if (this.environmentService.configuration.remoteAuthority) { + // Do not allow workspace folders with scheme different than the current remote scheme + const schemas = this.contextService.getWorkspace().folders.map(f => f.uri.scheme); + if (schemas.length && foldersToAdd.some(f => schemas.indexOf(f.uri.scheme) === -1)) { + return Promise.reject(new Error(nls.localize('differentSchemeRoots', "Workspace folders from different providers are not allowed in the same workspace."))); + } + } // If we are in no-workspace or single-folder workspace, adding folders has to // enter a workspace. @@ -210,18 +235,25 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { newWorkspaceFolders = distinct(newWorkspaceFolders, folder => getComparisonKey(folder.uri)); if (state === WorkbenchState.EMPTY && newWorkspaceFolders.length === 0 || state === WorkbenchState.FOLDER && newWorkspaceFolders.length === 1) { - return Promise.resolve(); // return if the operation is a no-op for the current state + return; // return if the operation is a no-op for the current state } return this.createAndEnterWorkspace(newWorkspaceFolders); } // Delegate addition of folders to workspace service otherwise - return this.contextService.addFolders(foldersToAdd, index) - .then(() => null, error => donotNotifyError ? Promise.reject(error) : this.handleWorkspaceConfigurationEditingError(error)); + try { + await this.contextService.addFolders(foldersToAdd, index); + } catch (error) { + if (donotNotifyError) { + throw error; + } + + this.handleWorkspaceConfigurationEditingError(error); + } } - removeFolders(foldersToRemove: URI[], donotNotifyError: boolean = false): Promise<void> { + async removeFolders(foldersToRemove: URI[], donotNotifyError: boolean = false): Promise<void> { // If we are in single-folder state and the opened folder is to be removed, // we create an empty workspace and enter it. @@ -230,8 +262,15 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { } // Delegate removal of folders to workspace service otherwise - return this.contextService.removeFolders(foldersToRemove) - .then(() => null, error => donotNotifyError ? Promise.reject(error) : this.handleWorkspaceConfigurationEditingError(error)); + try { + await this.contextService.removeFolders(foldersToRemove); + } catch (error) { + if (donotNotifyError) { + throw error; + } + + this.handleWorkspaceConfigurationEditingError(error); + } } private includesSingleFolderWorkspace(folders: URI[]): boolean { @@ -245,7 +284,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { async createAndEnterWorkspace(folders: IWorkspaceFolderCreationData[], path?: URI): Promise<void> { if (path && !await this.isValidTargetWorkspacePath(path)) { - return Promise.reject(null); + return; } const remoteAuthority = this.environmentService.configuration.remoteAuthority; const untitledWorkspace = await this.workspaceService.createUntitledWorkspace(folders, remoteAuthority); @@ -259,11 +298,11 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { async saveAndEnterWorkspace(path: URI): Promise<void> { if (!await this.isValidTargetWorkspacePath(path)) { - return Promise.reject(null); + return; } const workspaceIdentifier = this.getCurrentWorkspaceIdentifier(); if (!workspaceIdentifier) { - return Promise.reject(null); + return; } await this.saveWorkspaceAs(workspaceIdentifier, path); @@ -283,10 +322,12 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { detail: nls.localize('workspaceOpenedDetail', "The workspace is already opened in another window. Please close that window first and then try again."), noLink: true }; - return this.windowService.showMessageBox(options).then(() => false); + await this.windowService.showMessageBox(options); + + return false; } - return Promise.resolve(true); // OK + return true; // OK } private async saveWorkspaceAs(workspace: IWorkspaceIdentifier, targetConfigPathURI: URI): Promise<any> { @@ -294,7 +335,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { // Return early if target is same as source if (isEqual(configPathURI, targetConfigPathURI)) { - return Promise.resolve(null); + return; } // Read the contents of the workspace file, update it to new location and save it. @@ -303,18 +344,17 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { await this.textFileService.create(targetConfigPathURI, newRawWorkspaceContents, { overwrite: true }); } - private handleWorkspaceConfigurationEditingError(error: JSONEditingError): Promise<void> { + private handleWorkspaceConfigurationEditingError(error: JSONEditingError): void { switch (error.code) { case JSONEditingErrorCode.ERROR_INVALID_FILE: this.onInvalidWorkspaceConfigurationFileError(); - return Promise.resolve(); + break; case JSONEditingErrorCode.ERROR_FILE_DIRTY: this.onWorkspaceConfigurationFileDirtyError(); - return Promise.resolve(); + break; + default: + this.notificationService.error(error.message); } - this.notificationService.error(error.message); - - return Promise.resolve(); } private onInvalidWorkspaceConfigurationFileError(): void { @@ -338,7 +378,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { async enterWorkspace(path: URI): Promise<void> { if (!!this.environmentService.extensionTestsLocationURI) { - return Promise.reject(new Error('Entering a new workspace is not possible in tests.')); + throw new Error('Entering a new workspace is not possible in tests.'); } const workspace = await this.workspaceService.getWorkspaceIdentifier(path); @@ -358,7 +398,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { await this.migrateStorage(result.workspace); // Reinitialize backup service if (this.backupFileService instanceof BackupFileService) { - this.backupFileService.initialize(result.backupPath!); + this.backupFileService.initialize(toBackupWorkspaceResource(result.backupPath!, this.environmentService)); } } @@ -385,7 +425,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { private doCopyWorkspaceSettings(toWorkspace: IWorkspaceIdentifier, filter?: (config: IConfigurationPropertySchema) => boolean): Promise<void> { const configurationProperties = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration).getConfigurationProperties(); - const targetWorkspaceConfiguration = {}; + const targetWorkspaceConfiguration: any = {}; for (const key of this.configurationService.keys().workspace) { if (configurationProperties[key]) { if (filter && !filter(configurationProperties[key])) { diff --git a/src/vs/workbench/test/browser/part.test.ts b/src/vs/workbench/test/browser/part.test.ts index 73878b4e6..ed151b3ac 100644 --- a/src/vs/workbench/test/browser/part.test.ts +++ b/src/vs/workbench/test/browser/part.test.ts @@ -10,7 +10,6 @@ import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService import { append, $, hide } from 'vs/base/browser/dom'; import { TestStorageService, TestLayoutService } from 'vs/workbench/test/workbenchTestServices'; import { StorageScope } from 'vs/platform/storage/common/storage'; -import { Orientation } from 'vs/base/browser/ui/grid/grid'; class SimplePart extends Part { @@ -19,7 +18,7 @@ class SimplePart extends Part { minimumHeight: number; maximumHeight: number; - layout(width: number, height: number, orientation: Orientation): void { + layout(width: number, height: number): void { throw new Error('Method not implemented.'); } @@ -172,4 +171,4 @@ suite('Workbench parts', () => { assert(!document.getElementById('myPart.title')); assert(document.getElementById('myPart.content')); }); -}); \ No newline at end of file +}); diff --git a/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts b/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts index 4f7400dbc..5b5fa096f 100644 --- a/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts +++ b/src/vs/workbench/test/browser/parts/editor/baseEditor.test.ts @@ -86,7 +86,7 @@ class MyResourceInput extends ResourceEditorInput { } suite('Workbench base editor', () => { - test('BaseEditor API', function () { + test('BaseEditor API', async () => { let e = new MyEditor(NullTelemetryService); let input = new MyOtherInput(); let options = new EditorOptions(); @@ -94,25 +94,24 @@ suite('Workbench base editor', () => { assert(!e.isVisible()); assert(!e.input); assert(!e.options); - return e.setInput(input, options, CancellationToken.None).then(() => { - assert.strictEqual(input, e.input); - assert.strictEqual(options, e.options); - - const group = new TestEditorGroup(1); - e.setVisible(true, group); - assert(e.isVisible()); - assert.equal(e.group, group); - input.onDispose(() => { - assert(false); - }); - e.dispose(); - e.clearInput(); - e.setVisible(false, group); - assert(!e.isVisible()); - assert(!e.input); - assert(!e.options); - assert(!e.getControl()); + + await e.setInput(input, options, CancellationToken.None); + assert.strictEqual(input, e.input); + assert.strictEqual(options, e.options); + const group = new TestEditorGroup(1); + e.setVisible(true, group); + assert(e.isVisible()); + assert.equal(e.group, group); + input.onDispose(() => { + assert(false); }); + e.dispose(); + e.clearInput(); + e.setVisible(false, group); + assert(!e.isVisible()); + assert(!e.input); + assert(!e.options); + assert(!e.getControl()); }); test('EditorDescriptor', () => { @@ -128,7 +127,7 @@ suite('Workbench base editor', () => { let oldEditorsCnt = EditorRegistry.getEditors().length; let oldInputCnt = (<any>EditorRegistry).getEditorInputs().length; - EditorRegistry.registerEditor(d1, new SyncDescriptor(MyInput)); + EditorRegistry.registerEditor(d1, [new SyncDescriptor(MyInput)]); EditorRegistry.registerEditor(d2, [new SyncDescriptor(MyInput), new SyncDescriptor(MyOtherInput)]); assert.equal(EditorRegistry.getEditors().length, oldEditorsCnt + 2); @@ -149,15 +148,15 @@ suite('Workbench base editor', () => { let oldEditors = EditorRegistry.getEditors(); (<any>EditorRegistry).setEditors([]); - EditorRegistry.registerEditor(d2, new SyncDescriptor(ResourceEditorInput)); - EditorRegistry.registerEditor(d1, new SyncDescriptor(MyResourceInput)); + EditorRegistry.registerEditor(d2, [new SyncDescriptor(ResourceEditorInput)]); + EditorRegistry.registerEditor(d1, [new SyncDescriptor(MyResourceInput)]); let inst = new TestInstantiationService(); - const editor = EditorRegistry.getEditor(inst.createInstance(MyResourceInput, 'fake', '', URI.file('/fake')))!.instantiate(inst); + const editor = EditorRegistry.getEditor(inst.createInstance(MyResourceInput, 'fake', '', URI.file('/fake'), undefined))!.instantiate(inst); assert.strictEqual(editor.getId(), 'myEditor'); - const otherEditor = EditorRegistry.getEditor(inst.createInstance(ResourceEditorInput, 'fake', '', URI.file('/fake')))!.instantiate(inst); + const otherEditor = EditorRegistry.getEditor(inst.createInstance(ResourceEditorInput, 'fake', '', URI.file('/fake'), undefined))!.instantiate(inst); assert.strictEqual(otherEditor.getId(), 'myOtherEditor'); (<any>EditorRegistry).setEditors(oldEditors); @@ -169,11 +168,11 @@ suite('Workbench base editor', () => { let oldEditors = EditorRegistry.getEditors(); (<any>EditorRegistry).setEditors([]); - EditorRegistry.registerEditor(d1, new SyncDescriptor(ResourceEditorInput)); + EditorRegistry.registerEditor(d1, [new SyncDescriptor(ResourceEditorInput)]); let inst = new TestInstantiationService(); - const editor = EditorRegistry.getEditor(inst.createInstance(MyResourceInput, 'fake', '', URI.file('/fake')))!.instantiate(inst); + const editor = EditorRegistry.getEditor(inst.createInstance(MyResourceInput, 'fake', '', URI.file('/fake'), undefined))!.instantiate(inst); assert.strictEqual('myOtherEditor', editor.getId()); (<any>EditorRegistry).setEditors(oldEditors); diff --git a/src/vs/workbench/test/common/editor/editorDiffModel.test.ts b/src/vs/workbench/test/common/editor/editorDiffModel.test.ts index 3023add68..662bd56d2 100644 --- a/src/vs/workbench/test/common/editor/editorDiffModel.test.ts +++ b/src/vs/workbench/test/common/editor/editorDiffModel.test.ts @@ -35,7 +35,7 @@ suite('Workbench editor model', () => { accessor = instantiationService.createInstance(ServiceAccessor); }); - test('TextDiffEditorModel', () => { + test('TextDiffEditorModel', async () => { const dispose = accessor.textModelResolverService.registerTextModelContentProvider('test', { provideTextContent: function (resource: URI): Promise<ITextModel> { if (resource.scheme === 'test') { @@ -48,27 +48,26 @@ suite('Workbench editor model', () => { } }); - let input = instantiationService.createInstance(ResourceEditorInput, 'name', 'description', URI.from({ scheme: 'test', authority: null!, path: 'thePath' })); - let otherInput = instantiationService.createInstance(ResourceEditorInput, 'name2', 'description', URI.from({ scheme: 'test', authority: null!, path: 'thePath' })); + let input = instantiationService.createInstance(ResourceEditorInput, 'name', 'description', URI.from({ scheme: 'test', authority: null!, path: 'thePath' }), undefined); + let otherInput = instantiationService.createInstance(ResourceEditorInput, 'name2', 'description', URI.from({ scheme: 'test', authority: null!, path: 'thePath' }), undefined); let diffInput = new DiffEditorInput('name', 'description', input, otherInput); - return diffInput.resolve().then((model: any) => { - assert(model); - assert(model instanceof TextDiffEditorModel); + let model = await diffInput.resolve() as TextDiffEditorModel; - let diffEditorModel = model.textDiffEditorModel; - assert(diffEditorModel.original); - assert(diffEditorModel.modified); + assert(model); + assert(model instanceof TextDiffEditorModel); - return diffInput.resolve().then((model: any) => { - assert(model.isResolved()); + let diffEditorModel = model.textDiffEditorModel!; + assert(diffEditorModel.original); + assert(diffEditorModel.modified); - assert(diffEditorModel !== model.textDiffEditorModel); - diffInput.dispose(); - assert(!model.textDiffEditorModel); + model = await diffInput.resolve() as TextDiffEditorModel; + assert(model.isResolved()); - dispose.dispose(); - }); - }); + assert(diffEditorModel !== model.textDiffEditorModel); + diffInput.dispose(); + assert(!model.textDiffEditorModel); + + dispose.dispose(); }); }); diff --git a/src/vs/workbench/test/common/editor/editorGroups.test.ts b/src/vs/workbench/test/common/editor/editorGroups.test.ts index fde39c097..18d862a91 100644 --- a/src/vs/workbench/test/common/editor/editorGroups.test.ts +++ b/src/vs/workbench/test/common/editor/editorGroups.test.ts @@ -111,27 +111,17 @@ class TestFileEditorInput extends EditorInput implements IFileEditorInput { } getTypeId() { return 'testFileEditorInputForGroups'; } resolve(): Promise<IEditorModel> { return Promise.resolve(null!); } + setEncoding(encoding: string) { } + getEncoding(): string { return null!; } + setPreferredEncoding(encoding: string) { } + getResource(): URI { return this.resource; } + setForceOpenAsBinary(): void { } + setMode(mode: string) { } + setPreferredMode(mode: string) { } matches(other: TestFileEditorInput): boolean { return other && this.id === other.id && other instanceof TestFileEditorInput; } - - setEncoding(encoding: string) { - } - - getEncoding(): string { - return null!; - } - - setPreferredEncoding(encoding: string) { - } - - getResource(): URI { - return this.resource; - } - - setForceOpenAsBinary(): void { - } } function input(id = String(index++), nonSerializable?: boolean, resource?: URI): EditorInput { diff --git a/src/vs/workbench/test/common/editor/editorModel.test.ts b/src/vs/workbench/test/common/editor/editorModel.test.ts index 513d2783f..663f92685 100644 --- a/src/vs/workbench/test/common/editor/editorModel.test.ts +++ b/src/vs/workbench/test/common/editor/editorModel.test.ts @@ -21,8 +21,8 @@ import { TestTextResourcePropertiesService } from 'vs/workbench/test/workbenchTe class MyEditorModel extends EditorModel { } class MyTextEditorModel extends BaseTextEditorModel { - public createTextEditorModel(value: ITextBufferFactory, resource?: URI, modeId?: string) { - return super.createTextEditorModel(value, resource, modeId); + public createTextEditorModel(value: ITextBufferFactory, resource?: URI, preferredMode?: string) { + return super.createTextEditorModel(value, resource, preferredMode); } isReadonly(): boolean { @@ -40,7 +40,7 @@ suite('Workbench editor model', () => { modeService = instantiationService.stub(IModeService, ModeServiceImpl); }); - test('EditorModel', () => { + test('EditorModel', async () => { let counter = 0; let m = new MyEditorModel(); @@ -50,25 +50,23 @@ suite('Workbench editor model', () => { counter++; }); - return m.load().then(model => { - assert(model === m); - assert.strictEqual(m.isResolved(), true); - m.dispose(); - assert.equal(counter, 1); - }); + const model = await m.load(); + assert(model === m); + assert.strictEqual(m.isResolved(), true); + m.dispose(); + assert.equal(counter, 1); }); - test('BaseTextEditorModel', () => { + test('BaseTextEditorModel', async () => { let modelService = stubModelService(instantiationService); let m = new MyTextEditorModel(modelService, modeService); - return m.load().then((model: MyTextEditorModel) => { - assert(model === m); - model.createTextEditorModel(createTextBufferFactory('foo'), null!, 'text/plain'); - assert.strictEqual(m.isResolved(), true); - }).then(() => { - m.dispose(); - }); + const model = await m.load() as MyTextEditorModel; + + assert(model === m); + model.createTextEditorModel(createTextBufferFactory('foo'), null!, 'text/plain'); + assert.strictEqual(m.isResolved(), true); + m.dispose(); }); function stubModelService(instantiationService: TestInstantiationService): IModelService { diff --git a/src/vs/workbench/test/common/editor/resourceEditorInput.test.ts b/src/vs/workbench/test/common/editor/resourceEditorInput.test.ts index 954b83d93..d1e788e80 100644 --- a/src/vs/workbench/test/common/editor/resourceEditorInput.test.ts +++ b/src/vs/workbench/test/common/editor/resourceEditorInput.test.ts @@ -12,17 +12,16 @@ import { workbenchInstantiationService } from 'vs/workbench/test/workbenchTestSe import { IModelService } from 'vs/editor/common/services/modelService'; import { IModeService } from 'vs/editor/common/services/modeService'; import { snapshotToString } from 'vs/workbench/services/textfile/common/textfiles'; +import { ModesRegistry, PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; class ServiceAccessor { constructor( @IModelService public modelService: IModelService, @IModeService public modeService: IModeService - ) { - } + ) { } } suite('Workbench resource editor input', () => { - let instantiationService: IInstantiationService; let accessor: ServiceAccessor; @@ -31,14 +30,33 @@ suite('Workbench resource editor input', () => { accessor = instantiationService.createInstance(ServiceAccessor); }); - test('simple', () => { - let resource = URI.from({ scheme: 'inmemory', authority: null!, path: 'thePath' }); + test('basics', async () => { + const resource = URI.from({ scheme: 'inmemory', authority: null!, path: 'thePath' }); accessor.modelService.createModel('function test() {}', accessor.modeService.create('text'), resource); - let input: ResourceEditorInput = instantiationService.createInstance(ResourceEditorInput, 'The Name', 'The Description', resource); - return input.resolve().then(model => { - assert.ok(model); - assert.equal(snapshotToString((model as ResourceEditorModel).createSnapshot()!), 'function test() {}'); + const input: ResourceEditorInput = instantiationService.createInstance(ResourceEditorInput, 'The Name', 'The Description', resource, undefined); + + const model = await input.resolve(); + + assert.ok(model); + assert.equal(snapshotToString(((model as ResourceEditorModel).createSnapshot()!)), 'function test() {}'); + }); + + test('custom mode', async () => { + ModesRegistry.registerLanguage({ + id: 'resource-input-test', }); + + const resource = URI.from({ scheme: 'inmemory', authority: null!, path: 'thePath' }); + accessor.modelService.createModel('function test() {}', accessor.modeService.create('text'), resource); + + const input: ResourceEditorInput = instantiationService.createInstance(ResourceEditorInput, 'The Name', 'The Description', resource, 'resource-input-test'); + + const model = await input.resolve(); + assert.ok(model); + assert.equal(model.textEditorModel.getModeId(), 'resource-input-test'); + + input.setMode('text'); + assert.equal(model.textEditorModel.getModeId(), PLAINTEXT_MODE_ID); }); }); \ No newline at end of file diff --git a/src/vs/workbench/test/common/editor/untitledEditor.test.ts b/src/vs/workbench/test/common/editor/untitledEditor.test.ts index 3dc06265b..001ad7a6a 100644 --- a/src/vs/workbench/test/common/editor/untitledEditor.test.ts +++ b/src/vs/workbench/test/common/editor/untitledEditor.test.ts @@ -16,6 +16,7 @@ import { ModeServiceImpl } from 'vs/editor/common/services/modeServiceImpl'; import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput'; import { timeout } from 'vs/base/common/async'; import { snapshotToString } from 'vs/workbench/services/textfile/common/textfiles'; +import { ModesRegistry, PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry'; export class TestUntitledEditorService extends UntitledEditorService { get(resource: URI) { return super.get(resource); } @@ -45,7 +46,7 @@ suite('Workbench untitled editors', () => { accessor.untitledEditorService.dispose(); }); - test('Untitled Editor Service', function (done) { + test('Untitled Editor Service', async (done) => { const service = accessor.untitledEditorService; assert.equal(service.getAll().length, 0); @@ -68,36 +69,35 @@ suite('Workbench untitled editors', () => { assert.equal(service.getAll().length, 1); // dirty - input2.resolve().then(model => { - assert.ok(!service.isDirty(input2.getResource())); + const model = await input2.resolve(); - const listener = service.onDidChangeDirty(resource => { - listener.dispose(); + assert.ok(!service.isDirty(input2.getResource())); - assert.equal(resource.toString(), input2.getResource().toString()); + const listener = service.onDidChangeDirty(resource => { + listener.dispose(); - assert.ok(service.isDirty(input2.getResource())); - assert.equal(service.getDirty()[0].toString(), input2.getResource().toString()); - assert.equal(service.getDirty([input2.getResource()])[0].toString(), input2.getResource().toString()); - assert.equal(service.getDirty([input1.getResource()]).length, 0); + assert.equal(resource.toString(), input2.getResource().toString()); - service.revertAll(); - assert.equal(service.getAll().length, 0); - assert.ok(!input2.isDirty()); - assert.ok(!model.isDirty()); + assert.ok(service.isDirty(input2.getResource())); + assert.equal(service.getDirty()[0].toString(), input2.getResource().toString()); + assert.equal(service.getDirty([input2.getResource()])[0].toString(), input2.getResource().toString()); + assert.equal(service.getDirty([input1.getResource()]).length, 0); - input2.dispose(); + service.revertAll(); + assert.equal(service.getAll().length, 0); + assert.ok(!input2.isDirty()); + assert.ok(!model.isDirty()); - assert.ok(!service.exists(input2.getResource())); + input2.dispose(); - done(); - }); + assert.ok(!service.exists(input2.getResource())); + done(); + }); - model.textEditorModel.setValue('foo bar'); - }, err => done(err)); + model.textEditorModel.setValue('foo bar'); }); - test('Untitled with associated resource', function () { + test('Untitled with associated resource', () => { const service = accessor.untitledEditorService; const file = URI.file(join('C:\\', '/foo/file.txt')); const untitled = service.createOrGet(file); @@ -107,53 +107,49 @@ suite('Workbench untitled editors', () => { untitled.dispose(); }); - test('Untitled no longer dirty when content gets empty', function () { + test('Untitled no longer dirty when content gets empty', async () => { const service = accessor.untitledEditorService; const input = service.createOrGet(); // dirty - return input.resolve().then(model => { - model.textEditorModel.setValue('foo bar'); - assert.ok(model.isDirty()); - - model.textEditorModel.setValue(''); - assert.ok(!model.isDirty()); - - input.dispose(); - }); + const model = await input.resolve(); + model.textEditorModel.setValue('foo bar'); + assert.ok(model.isDirty()); + model.textEditorModel.setValue(''); + assert.ok(!model.isDirty()); + input.dispose(); }); - test('Untitled via loadOrCreate', function () { + test('Untitled via loadOrCreate', async () => { const service = accessor.untitledEditorService; - service.loadOrCreate().then(model1 => { - model1.textEditorModel!.setValue('foo bar'); - assert.ok(model1.isDirty()); - - model1.textEditorModel!.setValue(''); - assert.ok(!model1.isDirty()); - - return service.loadOrCreate({ initialValue: 'Hello World' }).then(model2 => { - assert.equal(snapshotToString(model2.createSnapshot()!), 'Hello World'); - - const input = service.createOrGet(); - - return service.loadOrCreate({ resource: input.getResource() }).then(model3 => { - assert.equal(model3.getResource().toString(), input.getResource().toString()); - - const file = URI.file(join('C:\\', '/foo/file44.txt')); - return service.loadOrCreate({ resource: file }).then(model4 => { - assert.ok(service.hasAssociatedFilePath(model4.getResource())); - assert.ok(model4.isDirty()); - - model1.dispose(); - model2.dispose(); - model3.dispose(); - model4.dispose(); - input.dispose(); - }); - }); - }); - }); + + const model1 = await service.loadOrCreate(); + + model1.textEditorModel!.setValue('foo bar'); + assert.ok(model1.isDirty()); + + model1.textEditorModel!.setValue(''); + assert.ok(!model1.isDirty()); + + const model2 = await service.loadOrCreate({ initialValue: 'Hello World' }); + assert.equal(snapshotToString(model2.createSnapshot()!), 'Hello World'); + + const input = service.createOrGet(); + + const model3 = await service.loadOrCreate({ resource: input.getResource() }); + + assert.equal(model3.getResource().toString(), input.getResource().toString()); + + const file = URI.file(join('C:\\', '/foo/file44.txt')); + const model4 = await service.loadOrCreate({ resource: file }); + assert.ok(service.hasAssociatedFilePath(model4.getResource())); + assert.ok(model4.isDirty()); + + model1.dispose(); + model2.dispose(); + model3.dispose(); + model4.dispose(); + input.dispose(); }); test('Untitled suggest name', function () { @@ -163,24 +159,31 @@ suite('Workbench untitled editors', () => { assert.ok(service.suggestFileName(input.getResource())); }); - test('Untitled with associated path remains dirty when content gets empty', function () { + test('Untitled with associated path remains dirty when content gets empty', async () => { const service = accessor.untitledEditorService; const file = URI.file(join('C:\\', '/foo/file.txt')); const input = service.createOrGet(file); // dirty - return input.resolve().then(model => { - model.textEditorModel.setValue('foo bar'); - assert.ok(model.isDirty()); + const model = await input.resolve(); + model.textEditorModel.setValue('foo bar'); + assert.ok(model.isDirty()); + model.textEditorModel.setValue(''); + assert.ok(model.isDirty()); + input.dispose(); + }); - model.textEditorModel.setValue(''); - assert.ok(model.isDirty()); + test('Untitled with initial content is dirty', async () => { + const service = accessor.untitledEditorService; + const input = service.createOrGet(undefined, undefined, 'Hello World'); - input.dispose(); - }); + // dirty + const model = await input.resolve(); + assert.ok(model.isDirty()); + input.dispose(); }); - test('Untitled created with files.defaultLanguage setting', function () { + test('Untitled created with files.defaultLanguage setting', () => { const defaultLanguage = 'javascript'; const config = accessor.testConfigurationService; config.setUserConfiguration('files', { 'defaultLanguage': defaultLanguage }); @@ -188,30 +191,52 @@ suite('Workbench untitled editors', () => { const service = accessor.untitledEditorService; const input = service.createOrGet(); - assert.equal(input.getModeId(), defaultLanguage); + assert.equal(input.getMode(), defaultLanguage); config.setUserConfiguration('files', { 'defaultLanguage': undefined }); input.dispose(); }); - test('Untitled created with modeId overrides files.defaultLanguage setting', function () { - const modeId = 'typescript'; + test('Untitled created with mode overrides files.defaultLanguage setting', () => { + const mode = 'typescript'; const defaultLanguage = 'javascript'; const config = accessor.testConfigurationService; config.setUserConfiguration('files', { 'defaultLanguage': defaultLanguage }); const service = accessor.untitledEditorService; - const input = service.createOrGet(null!, modeId); + const input = service.createOrGet(null!, mode); - assert.equal(input.getModeId(), modeId); + assert.equal(input.getMode(), mode); config.setUserConfiguration('files', { 'defaultLanguage': undefined }); input.dispose(); }); - test('encoding change event', function () { + test('Untitled can change mode afterwards', async () => { + const mode = 'untitled-input-test'; + + ModesRegistry.registerLanguage({ + id: mode, + }); + + const service = accessor.untitledEditorService; + const input = service.createOrGet(null!, mode); + + assert.equal(input.getMode(), mode); + + const model = await input.resolve(); + assert.equal(model.getMode(), mode); + + input.setMode('text'); + + assert.equal(input.getMode(), PLAINTEXT_MODE_ID); + + input.dispose(); + }); + + test('encoding change event', async () => { const service = accessor.untitledEditorService; const input = service.createOrGet(); @@ -223,16 +248,13 @@ suite('Workbench untitled editors', () => { }); // dirty - return input.resolve().then(model => { - model.setEncoding('utf16'); - - assert.equal(counter, 1); - - input.dispose(); - }); + const model = await input.resolve(); + model.setEncoding('utf16'); + assert.equal(counter, 1); + input.dispose(); }); - test('onDidChangeContent event', () => { + test('onDidChangeContent event', async () => { const service = accessor.untitledEditorService; const input = service.createOrGet(); @@ -245,39 +267,32 @@ suite('Workbench untitled editors', () => { assert.equal(r.toString(), input.getResource().toString()); }); - return input.resolve().then(model => { - model.textEditorModel.setValue('foo'); - assert.equal(counter, 0, 'Dirty model should not trigger event immediately'); + const model = await input.resolve(); + model.textEditorModel.setValue('foo'); + assert.equal(counter, 0, 'Dirty model should not trigger event immediately'); - return timeout(3).then(() => { - assert.equal(counter, 1, 'Dirty model should trigger event'); + await timeout(3); + assert.equal(counter, 1, 'Dirty model should trigger event'); + model.textEditorModel.setValue('bar'); - model.textEditorModel.setValue('bar'); - return timeout(3).then(() => { - assert.equal(counter, 2, 'Content change when dirty should trigger event'); + await timeout(3); + assert.equal(counter, 2, 'Content change when dirty should trigger event'); + model.textEditorModel.setValue(''); - model.textEditorModel.setValue(''); - return timeout(3).then(() => { - assert.equal(counter, 3, 'Manual revert should trigger event'); + await timeout(3); + assert.equal(counter, 3, 'Manual revert should trigger event'); + model.textEditorModel.setValue('foo'); - model.textEditorModel.setValue('foo'); - return timeout(3).then(() => { - assert.equal(counter, 4, 'Dirty model should trigger event'); + await timeout(3); + assert.equal(counter, 4, 'Dirty model should trigger event'); + model.revert(); - model.revert(); - return timeout(3).then(() => { - assert.equal(counter, 5, 'Revert should trigger event'); - - input.dispose(); - }); - }); - }); - }); - }); - }); + await timeout(3); + assert.equal(counter, 5, 'Revert should trigger event'); + input.dispose(); }); - test('onDidDisposeModel event', () => { + test('onDidDisposeModel event', async () => { const service = accessor.untitledEditorService; const input = service.createOrGet(); @@ -288,10 +303,9 @@ suite('Workbench untitled editors', () => { assert.equal(r.toString(), input.getResource().toString()); }); - return input.resolve().then(model => { - assert.equal(counter, 0); - input.dispose(); - assert.equal(counter, 1); - }); + await input.resolve(); + assert.equal(counter, 0); + input.dispose(); + assert.equal(counter, 1); }); }); \ No newline at end of file diff --git a/src/vs/workbench/test/common/notifications.test.ts b/src/vs/workbench/test/common/notifications.test.ts index 678c6aab2..30312d509 100644 --- a/src/vs/workbench/test/common/notifications.test.ts +++ b/src/vs/workbench/test/common/notifications.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { NotificationsModel, NotificationViewItem, INotificationChangeEvent, NotificationChangeType, NotificationViewItemLabelKind } from 'vs/workbench/common/notifications'; +import { NotificationsModel, NotificationViewItem, INotificationChangeEvent, NotificationChangeType, NotificationViewItemLabelKind, IStatusMessageChangeEvent, StatusMessageChangeType } from 'vs/workbench/common/notifications'; import { Action } from 'vs/base/common/actions'; import { INotification, Severity } from 'vs/platform/notification/common/notification'; import { createErrorWithActions } from 'vs/base/common/errorsWithActions'; @@ -132,9 +132,14 @@ suite('Notifications', () => { test('Model', () => { const model = new NotificationsModel(); - let lastEvent!: INotificationChangeEvent; + let lastNotificationEvent!: INotificationChangeEvent; model.onDidNotificationChange(e => { - lastEvent = e; + lastNotificationEvent = e; + }); + + let lastStatusMessageEvent!: IStatusMessageChangeEvent; + model.onDidStatusMessageChange(e => { + lastStatusMessageEvent = e; }); let item1: INotification = { severity: Severity.Error, message: 'Error Message', actions: { primary: [new Action('id', 'label')] } }; @@ -142,23 +147,23 @@ suite('Notifications', () => { let item2Duplicate: INotification = { severity: Severity.Warning, message: 'Warning Message', source: 'Some Source' }; let item3: INotification = { severity: Severity.Info, message: 'Info Message' }; - let item1Handle = model.notify(item1); - assert.equal(lastEvent.item.severity, item1.severity); - assert.equal(lastEvent.item.message.value, item1.message); - assert.equal(lastEvent.index, 0); - assert.equal(lastEvent.kind, NotificationChangeType.ADD); + let item1Handle = model.addNotification(item1); + assert.equal(lastNotificationEvent.item.severity, item1.severity); + assert.equal(lastNotificationEvent.item.message.value, item1.message); + assert.equal(lastNotificationEvent.index, 0); + assert.equal(lastNotificationEvent.kind, NotificationChangeType.ADD); - let item2Handle = model.notify(item2); - assert.equal(lastEvent.item.severity, item2.severity); - assert.equal(lastEvent.item.message.value, item2.message); - assert.equal(lastEvent.index, 0); - assert.equal(lastEvent.kind, NotificationChangeType.ADD); + let item2Handle = model.addNotification(item2); + assert.equal(lastNotificationEvent.item.severity, item2.severity); + assert.equal(lastNotificationEvent.item.message.value, item2.message); + assert.equal(lastNotificationEvent.index, 0); + assert.equal(lastNotificationEvent.kind, NotificationChangeType.ADD); - model.notify(item3); - assert.equal(lastEvent.item.severity, item3.severity); - assert.equal(lastEvent.item.message.value, item3.message); - assert.equal(lastEvent.index, 0); - assert.equal(lastEvent.kind, NotificationChangeType.ADD); + model.addNotification(item3); + assert.equal(lastNotificationEvent.item.severity, item3.severity); + assert.equal(lastNotificationEvent.item.message.value, item3.message); + assert.equal(lastNotificationEvent.index, 0); + assert.equal(lastNotificationEvent.kind, NotificationChangeType.ADD); assert.equal(model.notifications.length, 3); @@ -170,29 +175,48 @@ suite('Notifications', () => { item1Handle.close(); assert.equal(called, 1); assert.equal(model.notifications.length, 2); - assert.equal(lastEvent.item.severity, item1.severity); - assert.equal(lastEvent.item.message.value, item1.message); - assert.equal(lastEvent.index, 2); - assert.equal(lastEvent.kind, NotificationChangeType.REMOVE); + assert.equal(lastNotificationEvent.item.severity, item1.severity); + assert.equal(lastNotificationEvent.item.message.value, item1.message); + assert.equal(lastNotificationEvent.index, 2); + assert.equal(lastNotificationEvent.kind, NotificationChangeType.REMOVE); - model.notify(item2Duplicate); + model.addNotification(item2Duplicate); assert.equal(model.notifications.length, 2); - assert.equal(lastEvent.item.severity, item2Duplicate.severity); - assert.equal(lastEvent.item.message.value, item2Duplicate.message); - assert.equal(lastEvent.index, 0); - assert.equal(lastEvent.kind, NotificationChangeType.ADD); + assert.equal(lastNotificationEvent.item.severity, item2Duplicate.severity); + assert.equal(lastNotificationEvent.item.message.value, item2Duplicate.message); + assert.equal(lastNotificationEvent.index, 0); + assert.equal(lastNotificationEvent.kind, NotificationChangeType.ADD); item2Handle.close(); assert.equal(model.notifications.length, 1); - assert.equal(lastEvent.item.severity, item2Duplicate.severity); - assert.equal(lastEvent.item.message.value, item2Duplicate.message); - assert.equal(lastEvent.index, 0); - assert.equal(lastEvent.kind, NotificationChangeType.REMOVE); + assert.equal(lastNotificationEvent.item.severity, item2Duplicate.severity); + assert.equal(lastNotificationEvent.item.message.value, item2Duplicate.message); + assert.equal(lastNotificationEvent.index, 0); + assert.equal(lastNotificationEvent.kind, NotificationChangeType.REMOVE); model.notifications[0].expand(); - assert.equal(lastEvent.item.severity, item3.severity); - assert.equal(lastEvent.item.message.value, item3.message); - assert.equal(lastEvent.index, 0); - assert.equal(lastEvent.kind, NotificationChangeType.CHANGE); + assert.equal(lastNotificationEvent.item.severity, item3.severity); + assert.equal(lastNotificationEvent.item.message.value, item3.message); + assert.equal(lastNotificationEvent.index, 0); + assert.equal(lastNotificationEvent.kind, NotificationChangeType.CHANGE); + + const disposable = model.showStatusMessage('Hello World'); + assert.equal(model.statusMessage!.message, 'Hello World'); + assert.equal(lastStatusMessageEvent.item.message, model.statusMessage!.message); + assert.equal(lastStatusMessageEvent.kind, StatusMessageChangeType.ADD); + disposable.dispose(); + assert.ok(!model.statusMessage); + assert.equal(lastStatusMessageEvent.kind, StatusMessageChangeType.REMOVE); + + let disposable2 = model.showStatusMessage('Hello World 2'); + const disposable3 = model.showStatusMessage('Hello World 3'); + + assert.equal(model.statusMessage!.message, 'Hello World 3'); + + disposable2.dispose(); + assert.equal(model.statusMessage!.message, 'Hello World 3'); + + disposable3.dispose(); + assert.ok(!model.statusMessage); }); }); \ No newline at end of file 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 2f39779eb..779c40e96 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostApiCommands.test.ts @@ -16,10 +16,8 @@ import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/c import { IModelService } from 'vs/editor/common/services/modelService'; import { ExtHostLanguageFeatures } from 'vs/workbench/api/common/extHostLanguageFeatures'; import { MainThreadLanguageFeatures } from 'vs/workbench/api/browser/mainThreadLanguageFeatures'; -import { IHeapService, NullHeapService } from 'vs/workbench/services/heap/common/heap'; import { ExtHostApiCommands } from 'vs/workbench/api/common/extHostApiCommands'; import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands'; -import { ExtHostHeapService } from 'vs/workbench/api/common/extHostHeapService'; import { MainThreadCommands } from 'vs/workbench/api/browser/mainThreadCommands'; import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments'; import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors'; @@ -67,14 +65,14 @@ suite('ExtHostLanguageFeatureCommands', function () { { let instantiationService = new TestInstantiationService(); rpcProtocol = new TestRPCProtocol(); - instantiationService.stub(IHeapService, NullHeapService); instantiationService.stub(ICommandService, { _serviceBrand: undefined, executeCommand(id: string, args: any): any { - if (!CommandsRegistry.getCommands()[id]) { + const command = CommandsRegistry.getCommands().get(id); + if (!command) { return Promise.reject(new Error(id + ' NOT known')); } - let { handler } = CommandsRegistry.getCommands()[id]; + const { handler } = command; return Promise.resolve(instantiationService.invokeFunction(handler, args)); } }); @@ -109,9 +107,7 @@ suite('ExtHostLanguageFeatureCommands', function () { const extHostDocuments = new ExtHostDocuments(rpcProtocol, extHostDocumentsAndEditors); rpcProtocol.set(ExtHostContext.ExtHostDocuments, extHostDocuments); - const heapService = new ExtHostHeapService(); - - commands = new ExtHostCommands(rpcProtocol, heapService, new NullLogService()); + commands = new ExtHostCommands(rpcProtocol, new NullLogService()); rpcProtocol.set(ExtHostContext.ExtHostCommands, commands); rpcProtocol.set(MainContext.MainThreadCommands, inst.createInstance(MainThreadCommands, rpcProtocol)); ExtHostApiCommands.register(commands); @@ -119,7 +115,7 @@ suite('ExtHostLanguageFeatureCommands', function () { const diagnostics = new ExtHostDiagnostics(rpcProtocol); rpcProtocol.set(ExtHostContext.ExtHostDiagnostics, diagnostics); - extHost = new ExtHostLanguageFeatures(rpcProtocol, null, extHostDocuments, commands, heapService, diagnostics, new NullLogService()); + extHost = new ExtHostLanguageFeatures(rpcProtocol, null, extHostDocuments, commands, diagnostics, new NullLogService()); rpcProtocol.set(ExtHostContext.ExtHostLanguageFeatures, extHost); mainThread = rpcProtocol.set(MainContext.MainThreadLanguageFeatures, inst.createInstance(MainThreadLanguageFeatures, rpcProtocol)); @@ -801,9 +797,9 @@ suite('ExtHostLanguageFeatureCommands', function () { })); await rpcProtocol.sync(); - let value = await commands.executeCommand<vscode.SelectionRange[][]>('vscode.executeSelectionRangeProvider', model.uri, [new types.Position(0, 10)]); + let value = await commands.executeCommand<vscode.SelectionRange[]>('vscode.executeSelectionRangeProvider', model.uri, [new types.Position(0, 10)]); assert.equal(value.length, 1); - assert.ok(value[0].length >= 2); + assert.ok(value[0].parent); }); }); diff --git a/src/vs/workbench/test/electron-browser/api/extHostCommands.test.ts b/src/vs/workbench/test/electron-browser/api/extHostCommands.test.ts index 07bb3ac3c..d0cf59f32 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostCommands.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostCommands.test.ts @@ -26,7 +26,7 @@ suite('ExtHostCommands', function () { } }; - const commands = new ExtHostCommands(SingleProxyRPCProtocol(shape), undefined!, new NullLogService()); + const commands = new ExtHostCommands(SingleProxyRPCProtocol(shape), new NullLogService()); commands.registerCommand(true, 'foo', (): any => { }).dispose(); assert.equal(lastUnregister!, 'foo'); assert.equal(CommandsRegistry.getCommand('foo'), undefined); @@ -46,7 +46,7 @@ suite('ExtHostCommands', function () { } }; - const commands = new ExtHostCommands(SingleProxyRPCProtocol(shape), undefined!, new NullLogService()); + const commands = new ExtHostCommands(SingleProxyRPCProtocol(shape), new NullLogService()); const reg = commands.registerCommand(true, 'foo', (): any => { }); reg.dispose(); reg.dispose(); 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 16a5eef9f..db4999172 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostConfiguration.test.ts @@ -40,7 +40,7 @@ suite('ExtHostConfiguration', function () { user: new ConfigurationModel(contents), workspace: new ConfigurationModel(), folders: Object.create(null), - configurationScopes: {} + configurationScopes: [] }; } @@ -138,7 +138,7 @@ suite('ExtHostConfiguration', function () { testObject = all.getConfiguration('workbench'); actual = testObject.get('colorCustomizations')!; - delete actual['statusBar.foreground']; + actual['statusBar.foreground'] = undefined; assert.equal(actual['statusBar.foreground'], undefined); testObject = all.getConfiguration('workbench'); actual = testObject.get('colorCustomizations')!; @@ -278,7 +278,7 @@ suite('ExtHostConfiguration', function () { }, ['editor.wordWrap']), workspace: new ConfigurationModel({}, []), folders: Object.create(null), - configurationScopes: {} + configurationScopes: [] } ); @@ -326,7 +326,7 @@ suite('ExtHostConfiguration', function () { }, ['editor.wordWrap']), workspace, folders, - configurationScopes: {} + configurationScopes: [] } ); @@ -402,7 +402,7 @@ suite('ExtHostConfiguration', function () { }, ['editor.wordWrap']), workspace, folders, - configurationScopes: {} + configurationScopes: [] } ); 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 38c627a64..4eca9307e 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostDiagnostics.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostDiagnostics.test.ts @@ -91,18 +91,18 @@ suite('ExtHostDiagnostics', () => { new Diagnostic(new Range(0, 0, 1, 1), 'message-2') ]); - let array = collection.get(URI.parse('foo:bar')); + let array = collection.get(URI.parse('foo:bar')) as Diagnostic[]; assert.throws(() => array.length = 0); assert.throws(() => array.pop()); assert.throws(() => array[0] = new Diagnostic(new Range(0, 0, 0, 0), 'evil')); - collection.forEach((uri, array) => { + collection.forEach((uri, array: Diagnostic[]) => { assert.throws(() => array.length = 0); assert.throws(() => array.pop()); assert.throws(() => array[0] = new Diagnostic(new Range(0, 0, 0, 0), 'evil')); }); - array = collection.get(URI.parse('foo:bar')); + array = collection.get(URI.parse('foo:bar')) as Diagnostic[]; assert.equal(array.length, 2); collection.dispose(); 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 0096e76b9..99724c53a 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostDocumentSaveParticipant.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostDocumentSaveParticipant.test.ts @@ -85,7 +85,7 @@ suite('ExtHostDocumentSaveParticipant', () => { sub.dispose(); assert.ok(event); - assert.throws(() => { event.document = null!; }); + assert.throws(() => { (event.document as any) = null!; }); }); }); 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 a31180c8d..18ecedc67 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts @@ -18,7 +18,6 @@ import { ExtHostLanguageFeatures } from 'vs/workbench/api/common/extHostLanguage import { MainThreadLanguageFeatures } from 'vs/workbench/api/browser/mainThreadLanguageFeatures'; import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands'; import { MainThreadCommands } from 'vs/workbench/api/browser/mainThreadCommands'; -import { IHeapService, NullHeapService } from 'vs/workbench/services/heap/common/heap'; import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments'; import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors'; import { getDocumentSymbols } from 'vs/editor/contrib/quickOpen/quickOpen'; @@ -37,7 +36,6 @@ import { getDocumentFormattingEditsUntilResult, getDocumentRangeFormattingEditsU import { getLinks } from 'vs/editor/contrib/links/getLinks'; import { MainContext, ExtHostContext } from 'vs/workbench/api/common/extHost.protocol'; import { ExtHostDiagnostics } from 'vs/workbench/api/common/extHostDiagnostics'; -import { ExtHostHeapService } from 'vs/workbench/api/common/extHostHeapService'; import * as vscode from 'vscode'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { NullLogService } from 'vs/platform/log/common/log'; @@ -81,7 +79,6 @@ suite('ExtHostLanguageFeatures', function () { { let instantiationService = new TestInstantiationService(); instantiationService.stub(IMarkerService, MarkerService); - instantiationService.stub(IHeapService, NullHeapService); inst = instantiationService; } @@ -102,16 +99,14 @@ suite('ExtHostLanguageFeatures', function () { const extHostDocuments = new ExtHostDocuments(rpcProtocol, extHostDocumentsAndEditors); rpcProtocol.set(ExtHostContext.ExtHostDocuments, extHostDocuments); - const heapService = new ExtHostHeapService(); - - const commands = new ExtHostCommands(rpcProtocol, heapService, new NullLogService()); + const commands = new ExtHostCommands(rpcProtocol, new NullLogService()); rpcProtocol.set(ExtHostContext.ExtHostCommands, commands); rpcProtocol.set(MainContext.MainThreadCommands, inst.createInstance(MainThreadCommands, rpcProtocol)); const diagnostics = new ExtHostDiagnostics(rpcProtocol); rpcProtocol.set(ExtHostContext.ExtHostDiagnostics, diagnostics); - extHost = new ExtHostLanguageFeatures(rpcProtocol, null, extHostDocuments, commands, heapService, diagnostics, new NullLogService()); + extHost = new ExtHostLanguageFeatures(rpcProtocol, null, extHostDocuments, commands, diagnostics, new NullLogService()); rpcProtocol.set(ExtHostContext.ExtHostLanguageFeatures, extHost); mainThread = rpcProtocol.set(MainContext.MainThreadLanguageFeatures, inst.createInstance(MainThreadLanguageFeatures, rpcProtocol)); @@ -194,7 +189,7 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const value = await getCodeLensData(model, CancellationToken.None); - assert.equal(value.length, 1); + assert.equal(value.lenses.length, 1); }); test('CodeLens, do not resolve a resolved lens', async () => { @@ -212,8 +207,8 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const value = await getCodeLensData(model, CancellationToken.None); - assert.equal(value.length, 1); - const data = value[0]; + assert.equal(value.lenses.length, 1); + const [data] = value.lenses; const symbol = await Promise.resolve(data.provider.resolveCodeLens!(model, data.symbol, CancellationToken.None)); assert.equal(symbol!.command!.id, 'id'); assert.equal(symbol!.command!.title, 'Title'); @@ -229,8 +224,8 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const value = await getCodeLensData(model, CancellationToken.None); - assert.equal(value.length, 1); - let data = value[0]; + assert.equal(value.lenses.length, 1); + let [data] = value.lenses; const symbol = await Promise.resolve(data.provider.resolveCodeLens!(model, data.symbol, CancellationToken.None)); assert.equal(symbol!.command!.id, 'missing'); assert.equal(symbol!.command!.title, '!!MISSING: command!!'); @@ -1041,7 +1036,9 @@ suite('ExtHostLanguageFeatures', function () { disposables.push(extHost.registerDocumentLinkProvider(defaultExtension, defaultSelector, new class implements vscode.DocumentLinkProvider { provideDocumentLinks() { - return [new types.DocumentLink(new types.Range(0, 0, 1, 1), URI.parse('foo:bar#3'))]; + const link = new types.DocumentLink(new types.Range(0, 0, 1, 1), URI.parse('foo:bar#3')); + link.tooltip = 'tooltip'; + return [link]; } })); @@ -1051,6 +1048,7 @@ suite('ExtHostLanguageFeatures', function () { let [first] = links; assert.equal(first.url, 'foo:bar#3'); assert.deepEqual(first.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 2, endColumn: 2 }); + assert.equal(first.tooltip, 'tooltip'); }); test('Links, evil provider', async () => { 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 9ffa9aee7..991bfbede 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostMessagerService.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostMessagerService.test.ts @@ -6,9 +6,11 @@ import * as assert from 'assert'; import { MainThreadMessageService } from 'vs/workbench/api/browser/mainThreadMessageService'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { INotificationService, INotification, NoOpNotification, INotificationHandle, Severity, IPromptChoice, IPromptOptions } from 'vs/platform/notification/common/notification'; +import { INotificationService, INotification, NoOpNotification, INotificationHandle, Severity, IPromptChoice, IPromptOptions, IStatusMessageOptions } from 'vs/platform/notification/common/notification'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { mock } from 'vs/workbench/test/electron-browser/api/mock'; +import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; const emptyDialogService = new class implements IDialogService { _serviceBrand: 'dialogService'; @@ -24,13 +26,14 @@ const emptyDialogService = new class implements IDialogService { const emptyCommandService: ICommandService = { _serviceBrand: undefined, onWillExecuteCommand: () => ({ dispose: () => { } }), + onDidExecuteCommand: () => ({ dispose: () => { } }), executeCommand: (commandId: string, ...args: any[]): Promise<any> => { return Promise.resolve(undefined); } }; const emptyNotificationService = new class implements INotificationService { - _serviceBrand: 'notificiationService'; + _serviceBrand: ServiceIdentifier<INotificationService>; notify(...args: any[]): never { throw new Error('not implemented'); } @@ -46,11 +49,13 @@ const emptyNotificationService = new class implements INotificationService { prompt(severity: Severity, message: string, choices: IPromptChoice[], options?: IPromptOptions): INotificationHandle { throw new Error('not implemented'); } + status(message: string | Error, options?: IStatusMessageOptions): IDisposable { + return Disposable.None; + } }; class EmptyNotificationService implements INotificationService { - - _serviceBrand: any; + _serviceBrand: ServiceIdentifier<INotificationService>; constructor(private withNotify: (notification: INotification) => void) { } @@ -72,6 +77,9 @@ class EmptyNotificationService implements INotificationService { prompt(severity: Severity, message: string, choices: IPromptChoice[], options?: IPromptOptions): INotificationHandle { throw new Error('not implemented'); } + status(message: string, options?: IStatusMessageOptions): IDisposable { + return Disposable.None; + } } suite('ExtHostMessageService', function () { diff --git a/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts b/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts index ed496ed0e..0d15201d8 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; import { mapArrayOrNot } from 'vs/base/common/arrays'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { isPromiseCanceledError } from 'vs/base/common/errors'; -import { dispose } from 'vs/base/common/lifecycle'; +import { DisposableStore } from 'vs/base/common/lifecycle'; import { joinPath } from 'vs/base/common/resources'; import { URI, UriComponents } from 'vs/base/common/uri'; import * as pfs from 'vs/base/node/pfs'; @@ -16,12 +16,12 @@ import { ExtHostSearch } from 'vs/workbench/api/node/extHostSearch'; import { Range } from 'vs/workbench/api/common/extHostTypes'; import { IFileMatch, IFileQuery, IPatternInfo, IRawFileMatch2, ISearchCompleteStats, ISearchQuery, ITextQuery, QueryType, resultIsMatch } from 'vs/workbench/services/search/common/search'; import { TestRPCProtocol } from 'vs/workbench/test/electron-browser/api/testRPCProtocol'; -import { TestLogService } from 'vs/workbench/test/workbenchTestServices'; import * as vscode from 'vscode'; +import { NullLogService } from 'vs/platform/log/common/log'; let rpcProtocol: TestRPCProtocol; let extHostSearch: ExtHostSearch; -let disposables: vscode.Disposable[] = []; +const disposables = new DisposableStore(); let mockMainThreadSearch: MockMainThreadSearch; class MockMainThreadSearch implements MainThreadSearchShape { @@ -63,12 +63,12 @@ export function extensionResultIsMatch(data: vscode.TextSearchResult): data is v suite('ExtHostSearch', () => { async function registerTestTextSearchProvider(provider: vscode.TextSearchProvider, scheme = 'file'): Promise<void> { - disposables.push(extHostSearch.registerTextSearchProvider(scheme, provider)); + disposables.add(extHostSearch.registerTextSearchProvider(scheme, provider)); await rpcProtocol.sync(); } async function registerTestFileSearchProvider(provider: vscode.FileSearchProvider, scheme = 'file'): Promise<void> { - disposables.push(extHostSearch.registerFileSearchProvider(scheme, provider)); + disposables.add(extHostSearch.registerFileSearchProvider(scheme, provider)); await rpcProtocol.sync(); } @@ -130,7 +130,7 @@ suite('ExtHostSearch', () => { rpcProtocol = new TestRPCProtocol(); mockMainThreadSearch = new MockMainThreadSearch(); - const logService = new TestLogService(); + const logService = new NullLogService(); rpcProtocol.set(MainContext.MainThreadSearch, mockMainThreadSearch); @@ -139,7 +139,7 @@ suite('ExtHostSearch', () => { }); teardown(() => { - dispose(disposables); + disposables.clear(); return rpcProtocol.sync(); }); 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 7619369f0..5f05a9bc4 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostTreeViews.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostTreeViews.test.ts @@ -11,7 +11,6 @@ import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands'; import { MainThreadTreeViewsShape, MainContext } from 'vs/workbench/api/common/extHost.protocol'; import { TreeDataProvider, TreeItem } from 'vscode'; import { TestRPCProtocol } from './testRPCProtocol'; -import { ExtHostHeapService } from 'vs/workbench/api/common/extHostHeapService'; import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { MainThreadCommands } from 'vs/workbench/api/browser/mainThreadCommands'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -72,7 +71,7 @@ suite('ExtHostTreeView', function () { rpcProtocol.set(MainContext.MainThreadCommands, inst.createInstance(MainThreadCommands, rpcProtocol)); target = new RecordingShape(); - testObject = new ExtHostTreeViews(target, new ExtHostCommands(rpcProtocol, new ExtHostHeapService(), new NullLogService()), new NullLogService()); + testObject = new ExtHostTreeViews(target, new ExtHostCommands(rpcProtocol, new NullLogService()), new NullLogService()); onDidChangeTreeNode = new Emitter<{ key: string }>(); onDidChangeTreeNodeWithId = new Emitter<{ key: string }>(); testObject.createTreeView('testNodeTreeProvider', { treeDataProvider: aNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription); diff --git a/src/vs/workbench/test/electron-browser/api/extHostTypes.test.ts b/src/vs/workbench/test/electron-browser/api/extHostTypes.test.ts index 56517bdd7..f33a4d5f6 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostTypes.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostTypes.test.ts @@ -31,6 +31,7 @@ suite('ExtHostTypes', function () { scheme: 'file', path: '/path/test.file', fsPath: '/path/test.file'.replace(/\//g, isWindows ? '\\' : '/'), + _sep: isWindows ? 1 : undefined, }); assert.ok(uri.toString()); @@ -39,6 +40,7 @@ suite('ExtHostTypes', function () { scheme: 'file', path: '/path/test.file', fsPath: '/path/test.file'.replace(/\//g, isWindows ? '\\' : '/'), + _sep: isWindows ? 1 : undefined, external: 'file:///path/test.file' }); }); diff --git a/src/vs/workbench/test/electron-browser/api/extHostWebview.test.ts b/src/vs/workbench/test/electron-browser/api/extHostWebview.test.ts index a0d8a8c41..8a1212790 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostWebview.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostWebview.test.ts @@ -4,20 +4,21 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { MainThreadWebviews } from 'vs/workbench/api/electron-browser/mainThreadWebview'; +import { MainThreadWebviews } from 'vs/workbench/api/browser/mainThreadWebview'; import { ExtHostWebviews } from 'vs/workbench/api/common/extHostWebview'; import { mock } from 'vs/workbench/test/electron-browser/api/mock'; import * as vscode from 'vscode'; import { SingleProxyRPCProtocol } from './testRPCProtocol'; import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor'; +import { URI } from 'vs/base/common/uri'; -suite('ExtHostWebview', function () { +suite('ExtHostWebview', () => { test('Cannot register multiple serializers for the same view type', async () => { const viewType = 'view.type'; const shape = createNoopMainThreadWebviews(); - const extHostWebviews = new ExtHostWebviews(SingleProxyRPCProtocol(shape)); + const extHostWebviews = new ExtHostWebviews(SingleProxyRPCProtocol(shape), { webviewCspSource: '', webviewResourceRoot: '' }); let lastInvokedDeserializer: vscode.WebviewPanelSerializer | undefined = undefined; @@ -46,11 +47,95 @@ suite('ExtHostWebview', function () { await extHostWebviews.$deserializeWebviewPanel('x', viewType, 'title', {}, 0 as EditorViewColumn, {}); assert.strictEqual(lastInvokedDeserializer, serializerB); }); + + test('toWebviewResource for desktop vscode-resource scheme', () => { + const shape = createNoopMainThreadWebviews(); + const extHostWebviews = new ExtHostWebviews(SingleProxyRPCProtocol(shape), { + webviewCspSource: '', + webviewResourceRoot: 'vscode-resource:{{resource}}' + }); + const webview = extHostWebviews.createWebviewPanel({} as any, 'type', 'title', 1, {}); + + assert.strictEqual( + webview.webview.toWebviewResource(URI.parse('file:///Users/codey/file.html')).toString(), + 'vscode-resource:/Users/codey/file.html', + 'Unix basic' + ); + + assert.strictEqual( + webview.webview.toWebviewResource(URI.parse('file:///Users/codey/file.html#frag')).toString(), + 'vscode-resource:/Users/codey/file.html#frag', + 'Unix should preserve fragment' + ); + + assert.strictEqual( + webview.webview.toWebviewResource(URI.parse('file:///Users/codey/f%20ile.html')).toString(), + 'vscode-resource:/Users/codey/f%20ile.html', + 'Unix with encoding' + ); + + assert.strictEqual( + webview.webview.toWebviewResource(URI.parse('file://localhost/Users/codey/file.html')).toString(), + 'vscode-resource://localhost/Users/codey/file.html', + 'Unix should preserve authority' + ); + + assert.strictEqual( + webview.webview.toWebviewResource(URI.parse('file:///c:/codey/file.txt')).toString(), + 'vscode-resource:/c%3A/codey/file.txt', + 'Windows C drive' + ); + }); + + test('toWebviewResource for web endpoint', () => { + const shape = createNoopMainThreadWebviews(); + + const extHostWebviews = new ExtHostWebviews(SingleProxyRPCProtocol(shape), { + webviewCspSource: '', + webviewResourceRoot: `https://{{uuid}}.webview.contoso.com/commit{{resource}}` + }); + const webview = extHostWebviews.createWebviewPanel({} as any, 'type', 'title', 1, {}); + + function stripEndpointUuid(input: string) { + return input.replace(/^https:\/\/[^\.]+?\./, ''); + } + + assert.strictEqual( + stripEndpointUuid(webview.webview.toWebviewResource(URI.parse('file:///Users/codey/file.html')).toString()), + 'webview.contoso.com/commit///Users/codey/file.html', + 'Unix basic' + ); + + assert.strictEqual( + stripEndpointUuid(webview.webview.toWebviewResource(URI.parse('file:///Users/codey/file.html#frag')).toString()), + 'webview.contoso.com/commit///Users/codey/file.html#frag', + 'Unix should preserve fragment' + ); + + assert.strictEqual( + stripEndpointUuid(webview.webview.toWebviewResource(URI.parse('file:///Users/codey/f%20ile.html')).toString()), + 'webview.contoso.com/commit///Users/codey/f%20ile.html', + 'Unix with encoding' + ); + + assert.strictEqual( + stripEndpointUuid(webview.webview.toWebviewResource(URI.parse('file://localhost/Users/codey/file.html')).toString()), + 'webview.contoso.com/commit//localhost/Users/codey/file.html', + 'Unix should preserve authority' + ); + + assert.strictEqual( + stripEndpointUuid(webview.webview.toWebviewResource(URI.parse('file:///c:/codey/file.txt')).toString()), + 'webview.contoso.com/commit///c%3A/codey/file.txt', + 'Windows C drive' + ); + }); }); function createNoopMainThreadWebviews() { return new class extends mock<MainThreadWebviews>() { + $createWebviewPanel() { /* noop */ } $registerSerializer() { /* noop */ } $unregisterSerializer() { /* noop */ } }; 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 e1edb23fe..76040fc8e 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts @@ -573,18 +573,18 @@ suite('ExtHostWorkspace', function () { let mainThreadCalled = false; rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() { - $startFileSearch(includePattern: string, _includeFolder: UriComponents | undefined, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise<URI[] | undefined> { + $startFileSearch(includePattern: string, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise<URI[] | null> { mainThreadCalled = true; assert.equal(includePattern, 'foo'); - assert.equal(_includeFolder, undefined); - assert.equal(excludePatternOrDisregardExcludes, undefined); + assert.equal(_includeFolder, null); + assert.equal(excludePatternOrDisregardExcludes, null); assert.equal(maxResults, 10); - return Promise.resolve(undefined); + return Promise.resolve(null); } }); const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService(), new Counter()); - return ws.findFiles('foo', undefined!, 10, new ExtensionIdentifier('test')).then(() => { + return ws.findFiles('foo', undefined, 10, new ExtensionIdentifier('test')).then(() => { assert(mainThreadCalled, 'mainThreadCalled'); }); }); @@ -595,17 +595,17 @@ suite('ExtHostWorkspace', function () { let mainThreadCalled = false; rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() { - $startFileSearch(includePattern: string, _includeFolder: UriComponents | undefined, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise<URI[] | undefined> { + $startFileSearch(includePattern: string, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise<URI[] | null> { mainThreadCalled = true; assert.equal(includePattern, 'glob/**'); assert.deepEqual(_includeFolder, URI.file('/other/folder').toJSON()); - assert.equal(excludePatternOrDisregardExcludes, undefined); - return Promise.resolve(undefined); + assert.equal(excludePatternOrDisregardExcludes, null); + return Promise.resolve(null); } }); const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService(), new Counter()); - return ws.findFiles(new RelativePattern('/other/folder', 'glob/**'), undefined!, 10, new ExtensionIdentifier('test')).then(() => { + return ws.findFiles(new RelativePattern('/other/folder', 'glob/**'), undefined, 10, new ExtensionIdentifier('test')).then(() => { assert(mainThreadCalled, 'mainThreadCalled'); }); }); @@ -616,12 +616,12 @@ suite('ExtHostWorkspace', function () { let mainThreadCalled = false; rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() { - $startFileSearch(includePattern: string, _includeFolder: UriComponents | undefined, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise<URI[] | undefined> { + $startFileSearch(includePattern: string, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise<URI[] | null> { mainThreadCalled = true; assert.equal(includePattern, 'glob/**'); assert.deepEqual(_includeFolder, URI.file('/other/folder').toJSON()); assert.equal(excludePatternOrDisregardExcludes, false); - return Promise.resolve(undefined); + return Promise.resolve(null); } }); @@ -637,9 +637,9 @@ suite('ExtHostWorkspace', function () { let mainThreadCalled = false; rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() { - $startFileSearch(includePattern: string, _includeFolder: UriComponents | undefined, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise<URI[] | undefined> { + $startFileSearch(includePattern: string, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise<URI[] | null> { mainThreadCalled = true; - return Promise.resolve(undefined); + return Promise.resolve(null); } }); @@ -657,10 +657,10 @@ suite('ExtHostWorkspace', function () { let mainThreadCalled = false; rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() { - $startFileSearch(includePattern: string, _includeFolder: UriComponents | undefined, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise<URI[] | undefined> { + $startFileSearch(includePattern: string, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise<URI[] | null> { mainThreadCalled = true; assert(excludePatternOrDisregardExcludes, 'glob/**'); // Note that the base portion is ignored, see #52651 - return Promise.resolve(undefined); + return Promise.resolve(null); } }); diff --git a/src/vs/workbench/test/electron-browser/api/mainThreadEditors.test.ts b/src/vs/workbench/test/electron-browser/api/mainThreadEditors.test.ts index 129d48cab..35489e8cb 100644 --- a/src/vs/workbench/test/electron-browser/api/mainThreadEditors.test.ts +++ b/src/vs/workbench/test/electron-browser/api/mainThreadEditors.test.ts @@ -62,7 +62,7 @@ suite('MainThreadEditors', () => { } move(source: URI, target: URI) { movedResources.set(source, target); - return Promise.resolve(undefined); + return Promise.resolve(Object.create(null)); } models = <any>{ onModelSaved: Event.None, 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 54cced7af..502d3fae8 100644 --- a/src/vs/workbench/test/electron-browser/api/mainThreadSaveParticipant.test.ts +++ b/src/vs/workbench/test/electron-browser/api/mainThreadSaveParticipant.test.ts @@ -37,7 +37,7 @@ suite('MainThreadSaveParticipant', function () { }); test('insert final new line', async function () { - const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/final_new_line.txt'), 'utf8') as IResolvedTextFileEditorModel; + const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/final_new_line.txt'), 'utf8', undefined) as IResolvedTextFileEditorModel; await model.load(); const configService = new TestConfigurationService(); @@ -70,7 +70,7 @@ suite('MainThreadSaveParticipant', function () { }); test('trim final new lines', async function () { - const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/trim_final_new_line.txt'), 'utf8') as IResolvedTextFileEditorModel; + const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/trim_final_new_line.txt'), 'utf8', undefined) as IResolvedTextFileEditorModel; await model.load(); const configService = new TestConfigurationService(); @@ -105,7 +105,7 @@ suite('MainThreadSaveParticipant', function () { }); test('trim final new lines bug#39750', async function () { - const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/trim_final_new_line.txt'), 'utf8') as IResolvedTextFileEditorModel; + const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/trim_final_new_line.txt'), 'utf8', undefined) as IResolvedTextFileEditorModel; await model.load(); const configService = new TestConfigurationService(); @@ -132,7 +132,7 @@ suite('MainThreadSaveParticipant', function () { }); test('trim final new lines bug#46075', async function () { - const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/trim_final_new_line.txt'), 'utf8') as IResolvedTextFileEditorModel; + const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/trim_final_new_line.txt'), 'utf8', undefined) as IResolvedTextFileEditorModel; await model.load(); const configService = new TestConfigurationService(); diff --git a/src/vs/workbench/test/electron-browser/api/mainThreadWorkspace.test.ts b/src/vs/workbench/test/electron-browser/api/mainThreadWorkspace.test.ts index 07ee0ca62..50f8a7aa0 100644 --- a/src/vs/workbench/test/electron-browser/api/mainThreadWorkspace.test.ts +++ b/src/vs/workbench/test/electron-browser/api/mainThreadWorkspace.test.ts @@ -39,7 +39,7 @@ suite('MainThreadWorkspace', () => { }); const mtw: MainThreadWorkspace = instantiationService.createInstance(<any>MainThreadWorkspace, SingleProxyRPCProtocol({ $initializeWorkspace: () => { } })); - return mtw.$startFileSearch('foo', undefined, undefined, 10, new CancellationTokenSource().token); + return mtw.$startFileSearch('foo', null, null, 10, new CancellationTokenSource().token); }); test('exclude defaults', () => { @@ -61,7 +61,7 @@ suite('MainThreadWorkspace', () => { }); const mtw: MainThreadWorkspace = instantiationService.createInstance(<any>MainThreadWorkspace, SingleProxyRPCProtocol({ $initializeWorkspace: () => { } })); - return mtw.$startFileSearch('', undefined, undefined, 10, new CancellationTokenSource().token); + return mtw.$startFileSearch('', null, null, 10, new CancellationTokenSource().token); }); test('disregard excludes', () => { @@ -82,7 +82,7 @@ suite('MainThreadWorkspace', () => { }); const mtw: MainThreadWorkspace = instantiationService.createInstance(<any>MainThreadWorkspace, SingleProxyRPCProtocol({ $initializeWorkspace: () => { } })); - return mtw.$startFileSearch('', undefined, false, 10, new CancellationTokenSource().token); + return mtw.$startFileSearch('', null, false, 10, new CancellationTokenSource().token); }); test('exclude string', () => { @@ -96,6 +96,6 @@ suite('MainThreadWorkspace', () => { }); const mtw: MainThreadWorkspace = instantiationService.createInstance(<any>MainThreadWorkspace, SingleProxyRPCProtocol({ $initializeWorkspace: () => { } })); - return mtw.$startFileSearch('', undefined, 'exclude/**', 10, new CancellationTokenSource().token); + return mtw.$startFileSearch('', null, 'exclude/**', 10, new CancellationTokenSource().token); }); }); diff --git a/src/vs/workbench/test/electron-browser/colorRegistry.releaseTest.ts b/src/vs/workbench/test/electron-browser/colorRegistry.releaseTest.ts index 40eb17f7d..c61f19b0d 100644 --- a/src/vs/workbench/test/electron-browser/colorRegistry.releaseTest.ts +++ b/src/vs/workbench/test/electron-browser/colorRegistry.releaseTest.ts @@ -12,12 +12,15 @@ import { debugExceptionWidgetBackground } from 'vs/workbench/contrib/debug/brows import { debugToolBarBackground } from 'vs/workbench/contrib/debug/browser/debugToolBar'; import { buttonBackground } from 'vs/workbench/contrib/welcome/page/browser/welcomePage'; import { embeddedEditorBackground } from 'vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart'; -import { request, asText } from 'vs/base/node/request'; +import { asText } from 'vs/platform/request/common/request'; import * as pfs from 'vs/base/node/pfs'; import * as path from 'vs/base/common/path'; import * as assert from 'assert'; import { getPathFromAmdModule } from 'vs/base/common/amd'; import { CancellationToken } from 'vs/base/common/cancellation'; +import { RequestService } from 'vs/platform/request/node/requestService'; +import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; +import { NullLogService } from 'vs/platform/log/common/log'; interface ColorInfo { @@ -40,7 +43,7 @@ export const experimental: string[] = []; // 'settings.modifiedItemForeground', suite('Color Registry', function () { test('all colors documented', async function () { - const reqContext = await request({ url: 'https://raw.githubusercontent.com/Microsoft/vscode-docs/vnext/docs/getstarted/theme-color-reference.md' }, CancellationToken.None); + const reqContext = await new RequestService(new TestConfigurationService(), new NullLogService()).request({ url: 'https://raw.githubusercontent.com/Microsoft/vscode-docs/vnext/docs/getstarted/theme-color-reference.md' }, CancellationToken.None); const content = (await asText(reqContext))!; const expression = /\-\s*\`([\w\.]+)\`: (.*)/g; diff --git a/src/vs/workbench/test/electron-browser/quickopen.perf.integrationTest.ts b/src/vs/workbench/test/electron-browser/quickopen.perf.integrationTest.ts index 4d5e9e0a4..4b2467192 100644 --- a/src/vs/workbench/test/electron-browser/quickopen.perf.integrationTest.ts +++ b/src/vs/workbench/test/electron-browser/quickopen.perf.integrationTest.ts @@ -26,9 +26,10 @@ import { Extensions, IQuickOpenRegistry } from 'vs/workbench/browser/quickopen'; import 'vs/workbench/contrib/search/browser/search.contribution'; // load contributions import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; -import { SearchService } from 'vs/workbench/services/search/node/searchService'; +import { LocalSearchService } from 'vs/workbench/services/search/node/searchService'; import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; import { TestContextService, TestEditorGroupsService, TestEditorService, TestEnvironmentService, TestTextResourcePropertiesService } from 'vs/workbench/test/workbenchTestServices'; +import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings'; namespace Timer { export interface ITimerEvent { @@ -78,7 +79,7 @@ suite.skip('QuickOpen performance (integration)', () => { [IEditorGroupsService, new TestEditorGroupsService()], [IEnvironmentService, TestEnvironmentService], [IUntitledEditorService, createSyncDescriptor(UntitledEditorService)], - [ISearchService, createSyncDescriptor(SearchService)] + [ISearchService, createSyncDescriptor(LocalSearchService)] )); const registry = Registry.as<IQuickOpenRegistry>(Extensions.Quickopen); @@ -172,6 +173,10 @@ class TestTelemetryService implements ITelemetryService { return Promise.resolve(undefined); } + public publicLog2<E extends ClassifiedEvent<T> = never, T extends GDPRClassification<T> = never>(eventName: string, data?: StrictPropertyCheck<T, E>) { + return this.publicLog(eventName, data as any); + } + public getTelemetryInfo(): Promise<ITelemetryInfo> { return Promise.resolve({ instanceId: 'someValue.instanceId', 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 10e2781f7..e08748c63 100644 --- a/src/vs/workbench/test/electron-browser/textsearch.perf.integrationTest.ts +++ b/src/vs/workbench/test/electron-browser/textsearch.perf.integrationTest.ts @@ -15,7 +15,7 @@ import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/serv import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import * as minimist from 'minimist'; import * as path from 'vs/base/common/path'; -import { SearchService } from 'vs/workbench/services/search/node/searchService'; +import { LocalSearchService } from 'vs/workbench/services/search/node/searchService'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { TestEnvironmentService, TestContextService, TestEditorService, TestEditorGroupsService, TestTextResourcePropertiesService } from 'vs/workbench/test/workbenchTestServices'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -33,6 +33,7 @@ import { Event, Emitter } from 'vs/base/common/event'; import { testWorkspace } from 'vs/platform/workspace/test/common/testWorkspace'; import { NullLogService, ILogService } from 'vs/platform/log/common/log'; import { ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration'; +import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings'; declare var __dirname: string; @@ -68,7 +69,7 @@ suite.skip('TextSearch performance (integration)', () => { [IEditorGroupsService, new TestEditorGroupsService()], [IEnvironmentService, TestEnvironmentService], [IUntitledEditorService, createSyncDescriptor(UntitledEditorService)], - [ISearchService, createSyncDescriptor(SearchService)], + [ISearchService, createSyncDescriptor(LocalSearchService)], [ILogService, new NullLogService()] )); @@ -165,6 +166,10 @@ class TestTelemetryService implements ITelemetryService { return Promise.resolve(); } + public publicLog2<E extends ClassifiedEvent<T> = never, T extends GDPRClassification<T> = never>(eventName: string, data?: StrictPropertyCheck<T, E>) { + return this.publicLog(eventName, data as any); + } + public getTelemetryInfo(): Promise<ITelemetryInfo> { return Promise.resolve({ instanceId: 'someValue.instanceId', diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index 1e0073648..48ebaf8e2 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -15,7 +15,7 @@ import { ConfirmResult, IEditorInputWithOptions, CloseDirection, IEditorIdentifi import { IEditorOpeningEvent, EditorServiceImpl, IEditorGroupView } from 'vs/workbench/browser/parts/editor/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'; +import { IBackupFileService, IResolvedBackup } from 'vs/workbench/services/backup/common/backup'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IWorkbenchLayoutService, Parts, Position as PartPosition } from 'vs/workbench/services/layout/browser/layoutService'; import { TextModelResolverService } from 'vs/workbench/services/textmodelResolver/common/textModelResolverService'; @@ -38,7 +38,7 @@ import { TestConfigurationService } from 'vs/platform/configuration/test/common/ import { IWindowsService, IWindowService, INativeOpenDialogOptions, IEnterWorkspaceResult, IMessageBoxResult, MenuBarVisibility, IURIToOpen, IOpenSettings, IWindowConfiguration } from 'vs/platform/windows/common/windows'; import { TestWorkspace } from 'vs/platform/workspace/test/common/testWorkspace'; import { createTextBufferFactoryFromStream } from 'vs/editor/common/model/textModel'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; +import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService'; import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; @@ -64,14 +64,14 @@ import { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser'; import { IDecorationRenderOptions } from 'vs/editor/common/editorCommon'; import { EditorGroup } from 'vs/workbench/common/editor/editorGroup'; import { Dimension } from 'vs/base/browser/dom'; -import { ILogService, LogLevel } from 'vs/platform/log/common/log'; +import { ILogService, NullLogService } from 'vs/platform/log/common/log'; import { ILabelService } from 'vs/platform/label/common/label'; import { timeout } from 'vs/base/common/async'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { ViewletDescriptor, Viewlet } from 'vs/workbench/browser/viewlet'; import { IViewlet } from 'vs/workbench/common/viewlet'; import { IStorageService, InMemoryStorageService } from 'vs/platform/storage/common/storage'; -import { isLinux, isMacintosh } from 'vs/base/common/platform'; +import { isLinux, isMacintosh, IProcessEnvironment } from 'vs/base/common/platform'; import { LabelService } from 'vs/workbench/services/label/common/labelService'; import { IDimension } from 'vs/platform/layout/browser/layoutService'; import { Part } from 'vs/workbench/browser/part'; @@ -82,10 +82,11 @@ import { ISharedProcessService } from 'vs/platform/ipc/electron-browser/sharedPr import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { WorkbenchEnvironmentService } from 'vs/workbench/services/environment/node/environmentService'; import { VSBuffer, VSBufferReadable } from 'vs/base/common/buffer'; -import { BrowserTextFileService } from 'vs/workbench/services/textfile/browser/textFileService'; +import { NodeTextFileService } from 'vs/workbench/services/textfile/node/textFileService'; +import { Schemas } from 'vs/base/common/network'; export function createFileInput(instantiationService: IInstantiationService, resource: URI): FileEditorInput { - return instantiationService.createInstance(FileEditorInput, resource, undefined); + return instantiationService.createInstance(FileEditorInput, resource, undefined, undefined); } export const TestEnvironmentService = new WorkbenchEnvironmentService(parseArgs(process.argv) as IWindowConfiguration, process.execPath); @@ -176,7 +177,7 @@ export class TestContextService implements IWorkspaceContextService { } } -export class TestTextFileService extends BrowserTextFileService { +export class TestTextFileService extends NodeTextFileService { public cleanupBackupsBeforeShutdownCalled: boolean; private promptPath: URI; @@ -310,7 +311,7 @@ export function workbenchInstantiationService(): IInstantiationService { instantiationService.stub(ITextFileService, <ITextFileService>instantiationService.createInstance(TestTextFileService)); instantiationService.stub(ITextModelService, <ITextModelService>instantiationService.createInstance(TextModelResolverService)); instantiationService.stub(IThemeService, new TestThemeService()); - instantiationService.stub(ILogService, new TestLogService()); + instantiationService.stub(ILogService, new NullLogService()); instantiationService.stub(IEditorGroupsService, new TestEditorGroupsService([new TestEditorGroup(0)])); instantiationService.stub(ILabelService, <ILabelService>instantiationService.createInstance(LabelService)); const editorService = new TestEditorService(); @@ -321,19 +322,6 @@ export function workbenchInstantiationService(): IInstantiationService { return instantiationService; } -export class TestLogService implements ILogService { - _serviceBrand: any; onDidChangeLogLevel: Event<LogLevel>; - getLevel(): LogLevel { return LogLevel.Info; } - setLevel(_level: LogLevel): void { } - trace(_message: string, ..._args: any[]): void { } - debug(_message: string, ..._args: any[]): void { } - info(_message: string, ..._args: any[]): void { } - warn(_message: string, ..._args: any[]): void { } - error(_message: string | Error, ..._args: any[]): void { } - critical(_message: string | Error, ..._args: any[]): void { } - dispose(): void { } -} - export class TestDecorationsService implements IDecorationsService { _serviceBrand: any; onDidChangeDecorations: Event<IResourceDecorationChangeEvent> = Event.None; @@ -438,6 +426,9 @@ export class TestFileDialogService implements IFileDialogService { public pickWorkspaceAndOpen(_options: IPickAndOpenOptions): Promise<any> { return Promise.resolve(0); } + public pickFileToSave(_options: ISaveDialogOptions): Promise<URI | undefined> { + return Promise.resolve(undefined); + } public showSaveDialog(_options: ISaveDialogOptions): Promise<URI | undefined> { return Promise.resolve(undefined); } @@ -455,6 +446,9 @@ export class TestLayoutService implements IWorkbenchLayoutService { container: HTMLElement = window.document.body; onZenModeChange: Event<boolean> = Event.None; + onCenteredLayoutChange: Event<boolean> = Event.None; + onFullscreenChange: Event<boolean> = Event.None; + onPanelPositionChange: Event<string> = Event.None; onLayout = Event.None; private _onTitleBarVisibilityChange = new Emitter<void>(); @@ -480,6 +474,10 @@ export class TestLayoutService implements IWorkbenchLayoutService { return true; } + getDimension(_part: Parts): Dimension { + return new Dimension(0, 0); + } + public getContainer(_part: Parts): HTMLElement { return null!; } @@ -540,6 +538,8 @@ export class TestLayoutService implements IWorkbenchLayoutService { public addClass(_clazz: string): void { } public removeClass(_clazz: string): void { } + + public getWorkbenchContainer(): HTMLElement { throw new Error('not implemented'); } public getWorkbenchElement(): HTMLElement { throw new Error('not implemented'); } public toggleZenMode(): void { } @@ -616,6 +616,10 @@ export class TestPanelService implements IPanelService { return null!; } + public getPanel(id: string): any { + return activeViewlet; + } + public getPanels(): any[] { return []; } @@ -637,6 +641,10 @@ export class TestPanelService implements IPanelService { throw new Error('Method not implemented.'); } + public getProgressIndicator(id: string) { + return null!; + } + public hideActivePanel(): void { } public getLastActivePanelId(): string { @@ -663,7 +671,7 @@ export class TestEditorGroupsService implements IEditorGroupsService { whenRestored: Promise<void> = Promise.resolve(undefined); willRestoreEditors = false; - dimension = { width: 800, height: 600 }; + contentDimension = { width: 800, height: 600 }; get activeGroup(): IEditorGroup { return this.groups[0]; @@ -699,11 +707,11 @@ export class TestEditorGroupsService implements IEditorGroupsService { throw new Error('not implemented'); } - getSize(_group: number | IEditorGroup): number { - return 100; + getSize(_group: number | IEditorGroup): { width: number, height: number } { + return { width: 100, height: 100 }; } - setSize(_group: number | IEditorGroup, _size: number): void { } + setSize(_group: number | IEditorGroup, _size: { width: number, height: number }): void { } arrangeGroups(_arrangement: GroupsArrangement): void { } @@ -1071,6 +1079,10 @@ export class TestBackupFileService implements IBackupFileService { return Promise.resolve(false); } + public hasBackupSync(resource: URI, versionId?: number): boolean { + return false; + } + public loadBackupResource(resource: URI): Promise<URI | undefined> { return this.hasBackup(resource).then(hasBackup => { if (hasBackup) { @@ -1093,7 +1105,7 @@ export class TestBackupFileService implements IBackupFileService { throw new Error('not implemented'); } - public backupResource(_resource: URI, _content: ITextSnapshot): Promise<void> { + public backupResource<T extends object>(_resource: URI, _content: ITextSnapshot, versionId?: number, meta?: T): Promise<void> { return Promise.resolve(); } @@ -1108,7 +1120,7 @@ export class TestBackupFileService implements IBackupFileService { return textBuffer.getValueInRange(range, EndOfLinePreference.TextDefined); } - public resolveBackupContent(_backup: URI): Promise<ITextBufferFactory> { + public resolveBackupContent<T extends object>(_backup: URI): Promise<IResolvedBackup<T>> { throw new Error('not implemented'); } @@ -1216,6 +1228,14 @@ export class TestWindowService implements IWindowService { }); } + addRecentlyOpened(_recents: IRecent[]): Promise<void> { + return Promise.resolve(); + } + + removeFromRecentlyOpened(_paths: URI[]): Promise<void> { + return Promise.resolve(); + } + focusWindow(): Promise<void> { return Promise.resolve(); } @@ -1445,6 +1465,10 @@ export class TestWindowsService implements IWindowsService { return Promise.resolve(); } + openExtensionDevelopmentHostWindow(args: ParsedArgs, env: IProcessEnvironment): Promise<void> { + return Promise.resolve(); + } + getWindows(): Promise<{ id: number; workspace?: IWorkspaceIdentifier; folderUri?: ISingleFolderWorkspaceIdentifier; title: string; filename?: string; }[]> { throw new Error('not implemented'); } @@ -1453,7 +1477,7 @@ export class TestWindowsService implements IWindowsService { return Promise.resolve(this.windowCount); } - log(_severity: string, ..._messages: string[]): Promise<void> { + log(_severity: string, _args: string[]): Promise<void> { return Promise.resolve(); } @@ -1575,26 +1599,31 @@ export class TestSharedProcessService implements ISharedProcessService { registerChannel(channelName: string, channel: any): void { } } -export class NullFileSystemProvider implements IFileSystemProvider { - - capabilities: FileSystemProviderCapabilities = FileSystemProviderCapabilities.Readonly; - - onDidChangeCapabilities: Event<void> = Event.None; - onDidChangeFile: Event<IFileChange[]> = Event.None; - - constructor(private disposableFactory: () => IDisposable = () => Disposable.None) { } - - watch(resource: URI, opts: IWatchOptions): IDisposable { return this.disposableFactory(); } - stat(resource: URI): Promise<IStat> { return Promise.resolve(undefined!); } - mkdir(resource: URI): Promise<void> { return Promise.resolve(undefined!); } - readdir(resource: URI): Promise<[string, FileType][]> { return Promise.resolve(undefined!); } - delete(resource: URI, opts: FileDeleteOptions): Promise<void> { return Promise.resolve(undefined!); } - rename(from: URI, to: URI, opts: FileOverwriteOptions): Promise<void> { return Promise.resolve(undefined!); } - copy?(from: URI, to: URI, opts: FileOverwriteOptions): Promise<void> { return Promise.resolve(undefined!); } - readFile?(resource: URI): Promise<Uint8Array> { return Promise.resolve(undefined!); } - writeFile?(resource: URI, content: Uint8Array, opts: FileWriteOptions): Promise<void> { return Promise.resolve(undefined!); } - open?(resource: URI, opts: FileOpenOptions): Promise<number> { return Promise.resolve(undefined!); } - close?(fd: number): Promise<void> { return Promise.resolve(undefined!); } - read?(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise<number> { return Promise.resolve(undefined!); } - write?(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise<number> { return Promise.resolve(undefined!); } -} \ No newline at end of file +export class RemoteFileSystemProvider implements IFileSystemProvider { + + constructor(private readonly diskFileSystemProvider: IFileSystemProvider, private readonly remoteAuthority: string) { } + + readonly capabilities: FileSystemProviderCapabilities = this.diskFileSystemProvider.capabilities; + readonly onDidChangeCapabilities: Event<void> = this.diskFileSystemProvider.onDidChangeCapabilities; + + readonly onDidChangeFile: Event<IFileChange[]> = Event.map(this.diskFileSystemProvider.onDidChangeFile, changes => changes.map(c => { c.resource = c.resource.with({ scheme: Schemas.vscodeRemote, authority: this.remoteAuthority }); return c; })); + watch(resource: URI, opts: IWatchOptions): IDisposable { return this.diskFileSystemProvider.watch(this.toFileResource(resource), opts); } + + stat(resource: URI): Promise<IStat> { return this.diskFileSystemProvider.stat(this.toFileResource(resource)); } + mkdir(resource: URI): Promise<void> { return this.diskFileSystemProvider.mkdir(this.toFileResource(resource)); } + readdir(resource: URI): Promise<[string, FileType][]> { return this.diskFileSystemProvider.readdir(this.toFileResource(resource)); } + delete(resource: URI, opts: FileDeleteOptions): Promise<void> { return this.diskFileSystemProvider.delete(this.toFileResource(resource), opts); } + + rename(from: URI, to: URI, opts: FileOverwriteOptions): Promise<void> { return this.diskFileSystemProvider.rename(this.toFileResource(from), this.toFileResource(to), opts); } + copy(from: URI, to: URI, opts: FileOverwriteOptions): Promise<void> { return this.diskFileSystemProvider.copy!(this.toFileResource(from), this.toFileResource(to), opts); } + + readFile(resource: URI): Promise<Uint8Array> { return this.diskFileSystemProvider.readFile!(this.toFileResource(resource)); } + writeFile(resource: URI, content: Uint8Array, opts: FileWriteOptions): Promise<void> { return this.diskFileSystemProvider.writeFile!(this.toFileResource(resource), content, opts); } + + open(resource: URI, opts: FileOpenOptions): Promise<number> { return this.diskFileSystemProvider.open!(this.toFileResource(resource), opts); } + close(fd: number): Promise<void> { return this.diskFileSystemProvider.close!(fd); } + read(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise<number> { return this.diskFileSystemProvider.read!(fd, pos, data, offset, length); } + write(fd: number, pos: number, data: Uint8Array, offset: number, length: number): Promise<number> { return this.diskFileSystemProvider.write!(fd, pos, data, offset, length); } + + private toFileResource(resource: URI): URI { return resource.with({ scheme: Schemas.file, authority: '' }); } +} diff --git a/src/vs/workbench/workbench.main.ts b/src/vs/workbench/workbench.main.ts index de7f0954e..ba1ea7a20 100644 --- a/src/vs/workbench/workbench.main.ts +++ b/src/vs/workbench/workbench.main.ts @@ -7,7 +7,7 @@ import 'vs/editor/editor.all'; -import 'vs/workbench/api/electron-browser/extensionHost.contribution'; +import 'vs/workbench/api/browser/extensionHost.contribution'; import 'vs/workbench/electron-browser/main.contribution'; import 'vs/workbench/browser/workbench.contribution'; @@ -20,6 +20,8 @@ import 'vs/workbench/electron-browser/main'; //#region --- workbench actions import 'vs/workbench/browser/actions/layoutActions'; +import 'vs/workbench/browser/actions/windowActions'; +import 'vs/workbench/browser/actions/developerActions'; import 'vs/workbench/browser/actions/listCommands'; import 'vs/workbench/browser/actions/navigationActions'; import 'vs/workbench/browser/parts/quickopen/quickOpenActions'; @@ -51,7 +53,7 @@ import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDeco import { IMarkerService } from 'vs/platform/markers/common/markers'; import { MarkerService } from 'vs/platform/markers/common/markerService'; import { IDownloadService } from 'vs/platform/download/common/download'; -import { DownloadService } from 'vs/platform/download/node/downloadService'; +import { DownloadService } from 'vs/platform/download/common/downloadService'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { ClipboardService } from 'vs/platform/clipboard/electron-browser/clipboardService'; import { ContextKeyService } from 'vs/platform/contextkey/browser/contextKeyService'; @@ -62,12 +64,12 @@ import { ITextResourceConfigurationService } from 'vs/editor/common/services/res import { TextResourceConfigurationService } from 'vs/editor/common/services/resourceConfigurationImpl'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; import { AccessibilityService } from 'vs/workbench/services/accessibility/node/accessibilityService'; -import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { IExtensionGalleryService, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { ContextViewService } from 'vs/platform/contextview/browser/contextViewService'; -import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; -import { IRequestService } from 'vs/platform/request/node/request'; -import { RequestService } from 'vs/platform/request/electron-browser/requestService'; +import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; +import { IRequestService } from 'vs/platform/request/common/request'; +import { RequestService } from 'vs/platform/request/browser/requestService'; import { LifecycleService } from 'vs/platform/lifecycle/electron-browser/lifecycleService'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; @@ -89,10 +91,8 @@ import { IURLService } from 'vs/platform/url/common/url'; import { RelayURLService } from 'vs/platform/url/electron-browser/urlService'; import { ITunnelService } from 'vs/platform/remote/common/tunnel'; import { TunnelService } from 'vs/workbench/services/remote/node/tunnelService'; -import { ConfigurationResolverService } from 'vs/workbench/services/configurationResolver/electron-browser/configurationResolverService'; -import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; - -import 'vs/platform/remote/node/tunnelService'; +import { ICredentialsService } from 'vs/platform/credentials/common/credentials'; +import { KeytarCredentialsService } from 'vs/platform/credentials/node/credentialsService'; import 'vs/workbench/services/bulkEdit/browser/bulkEditService'; import 'vs/workbench/services/integrity/node/integrityService'; @@ -102,9 +102,8 @@ import 'vs/workbench/services/workspace/electron-browser/workspaceEditingService import 'vs/workbench/services/extensions/common/inactiveExtensionUrlHandler'; import 'vs/workbench/services/decorations/browser/decorationsService'; import 'vs/workbench/services/search/node/searchService'; -import 'vs/workbench/services/progress/browser/progressService2'; +import 'vs/workbench/services/progress/browser/progressService'; import 'vs/workbench/services/editor/browser/codeEditorService'; -import 'vs/workbench/services/broadcast/electron-browser/broadcastService'; import 'vs/workbench/services/extensions/electron-browser/extensionHostDebugService'; import 'vs/workbench/services/preferences/browser/preferencesService'; import 'vs/workbench/services/output/node/outputChannelModelService'; @@ -113,29 +112,34 @@ import 'vs/workbench/services/textmodelResolver/common/textModelResolverService' import 'vs/workbench/services/textfile/node/textFileService'; import 'vs/workbench/services/dialogs/browser/fileDialogService'; import 'vs/workbench/services/dialogs/electron-browser/dialogService'; -import 'vs/workbench/services/backup/node/backupFileService'; import 'vs/workbench/services/editor/browser/editorService'; import 'vs/workbench/services/history/browser/history'; import 'vs/workbench/services/activity/browser/activityService'; import 'vs/workbench/browser/parts/views/views'; -import 'vs/workbench/services/keybinding/electron-browser/keybindingService'; +import 'vs/workbench/services/keybinding/electron-browser/nativeKeymapService'; +import 'vs/workbench/services/keybinding/electron-browser/keybinding.contribution'; +import 'vs/workbench/services/keybinding/browser/keybindingService'; import 'vs/workbench/services/untitled/common/untitledEditorService'; -import 'vs/workbench/services/textfile/node/textResourcePropertiesService'; +import 'vs/workbench/services/textfile/common/textResourcePropertiesService'; import 'vs/workbench/services/mode/common/workbenchModeService'; import 'vs/workbench/services/commands/common/commandService'; import 'vs/workbench/services/themes/browser/workbenchThemeService'; -import 'vs/workbench/services/extensionManagement/node/extensionEnablementService'; import 'vs/workbench/services/extensions/electron-browser/extensionService'; import 'vs/workbench/services/contextmenu/electron-browser/contextmenuService'; -import 'vs/workbench/services/extensions/node/multiExtensionManagement'; import 'vs/workbench/services/label/common/labelService'; -import 'vs/workbench/services/extensions/electron-browser/extensionManagementServerService'; +import 'vs/workbench/services/extensionManagement/electron-browser/extensionManagementServerService'; +import 'vs/workbench/services/extensionManagement/common/extensionEnablementService'; import 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl'; import 'vs/workbench/services/notification/common/notificationService'; -import 'vs/workbench/services/heap/node/heap'; import 'vs/workbench/services/window/electron-browser/windowService'; import 'vs/workbench/services/telemetry/electron-browser/telemetryService'; +import 'vs/workbench/services/configurationResolver/electron-browser/configurationResolverService'; +import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; +import { BackupFileService } from 'vs/workbench/services/backup/node/backupFileService'; +import { ExtensionManagementService } from 'vs/workbench/services/extensionManagement/node/extensionManagementService'; +registerSingleton(IExtensionManagementService, ExtensionManagementService); +registerSingleton(IBackupFileService, BackupFileService); registerSingleton(IMenuService, MenuService, true); registerSingleton(IListService, ListService, true); registerSingleton(IOpenerService, OpenerService, true); @@ -162,10 +166,12 @@ registerSingleton(IWorkspacesService, WorkspacesService); registerSingleton(IMenubarService, MenubarService); registerSingleton(IURLService, RelayURLService); registerSingleton(ITunnelService, TunnelService, true); -registerSingleton(IConfigurationResolverService, ConfigurationResolverService, true); +registerSingleton(ICredentialsService, KeytarCredentialsService, true); +registerSingleton(IWorkspaceStatsService, WorkspaceStatsService, true); //#endregion + //#region --- workbench parts import 'vs/workbench/browser/parts/quickinput/quickInput'; @@ -179,6 +185,7 @@ import 'vs/workbench/browser/parts/statusbar/statusbarPart'; //#endregion + //#region --- workbench contributions // Workspace File Watching @@ -191,11 +198,15 @@ import 'vs/workbench/contrib/telemetry/browser/telemetry.contribution'; import 'vs/workbench/contrib/localizations/browser/localizations.contribution'; // Preferences -import 'vs/workbench/contrib/preferences/electron-browser/preferences.contribution'; +import 'vs/workbench/contrib/preferences/browser/preferences.contribution'; import 'vs/workbench/contrib/preferences/browser/keybindingsEditorContribution'; +import { IPreferencesSearchService } from 'vs/workbench/contrib/preferences/common/preferences'; +import { PreferencesSearchService } from 'vs/workbench/contrib/preferences/browser/preferencesSearch'; +registerSingleton(IPreferencesSearchService, PreferencesSearchService, true); // Logs import 'vs/workbench/contrib/logs/common/logs.contribution'; +import 'vs/workbench/contrib/logs/electron-browser/logs.contribution'; // Quick Open Handlers import 'vs/workbench/contrib/quickopen/browser/quickopen.contribution'; @@ -209,7 +220,7 @@ import 'vs/workbench/contrib/files/browser/files.contribution'; import 'vs/workbench/contrib/backup/common/backup.contribution'; // Stats -import 'vs/workbench/contrib/stats/node/stats.contribution'; +import 'vs/workbench/contrib/stats/electron-browser/stats.contribution'; // Rapid Render Splash import 'vs/workbench/contrib/splash/electron-browser/partsSplash.contribution'; @@ -224,11 +235,12 @@ import 'vs/workbench/contrib/scm/browser/scm.contribution'; import 'vs/workbench/contrib/scm/browser/scmViewlet'; // Debug -import 'vs/workbench/contrib/debug/electron-browser/debug.contribution'; +import 'vs/workbench/contrib/debug/browser/debug.contribution'; import 'vs/workbench/contrib/debug/browser/debugQuickOpen'; import 'vs/workbench/contrib/debug/browser/debugEditorContribution'; import 'vs/workbench/contrib/debug/browser/repl'; import 'vs/workbench/contrib/debug/browser/debugViewlet'; +import 'vs/workbench/contrib/debug/node/debugHelperService'; // Markers import 'vs/workbench/contrib/markers/browser/markers.contribution'; @@ -244,9 +256,10 @@ import 'vs/workbench/contrib/webview/browser/webview.contribution'; import 'vs/workbench/contrib/webview/electron-browser/webview.contribution'; // Extensions Management +import 'vs/workbench/contrib/extensions/browser/extensions.contribution'; import 'vs/workbench/contrib/extensions/electron-browser/extensions.contribution'; import 'vs/workbench/contrib/extensions/browser/extensionsQuickOpen'; -import 'vs/workbench/contrib/extensions/electron-browser/extensionsViewlet'; +import 'vs/workbench/contrib/extensions/browser/extensionsViewlet'; // Output Panel import 'vs/workbench/contrib/output/browser/output.contribution'; @@ -262,7 +275,14 @@ import 'vs/workbench/contrib/terminal/browser/terminalPanel'; import 'vs/workbench/contrib/relauncher/electron-browser/relauncher.contribution'; // Tasks -import 'vs/workbench/contrib/tasks/electron-browser/task.contribution'; +import 'vs/workbench/contrib/tasks/browser/task.contribution'; +import { TaskService } from 'vs/workbench/contrib/tasks/electron-browser/taskService'; +import { ITaskService } from 'vs/workbench/contrib/tasks/common/taskService'; +registerSingleton(ITaskService, TaskService, true); + +// Remote +import 'vs/workbench/contrib/remote/common/remote.contribution'; +import 'vs/workbench/contrib/remote/electron-browser/remote.contribution'; // Emmet import 'vs/workbench/contrib/emmet/browser/emmet.contribution'; @@ -272,7 +292,8 @@ import 'vs/workbench/contrib/codeEditor/browser/codeEditor.contribution'; import 'vs/workbench/contrib/codeEditor/electron-browser/codeEditor.contribution'; // Execution -import 'vs/workbench/contrib/externalTerminal/electron-browser/externalTerminal.contribution'; +import 'vs/workbench/contrib/externalTerminal/node/externalTerminalService'; +import 'vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution'; // Snippets import 'vs/workbench/contrib/snippets/browser/snippets.contribution'; @@ -285,7 +306,7 @@ import 'vs/workbench/contrib/snippets/browser/tabCompletion'; import 'vs/workbench/contrib/format/browser/format.contribution'; // Send a Smile -import 'vs/workbench/contrib/feedback/electron-browser/feedback.contribution'; +import 'vs/workbench/contrib/feedback/browser/feedback.contribution'; // Update import 'vs/workbench/contrib/update/electron-browser/update.contribution'; @@ -322,10 +343,8 @@ import 'vs/workbench/contrib/outline/browser/outline.contribution'; // Experiments import 'vs/workbench/contrib/experiments/electron-browser/experiments.contribution'; -// Code Insets -import 'vs/workbench/contrib/codeinset/electron-browser/codeInset.contribution'; - // Issues import 'vs/workbench/contrib/issue/electron-browser/issue.contribution'; +import { IWorkspaceStatsService, WorkspaceStatsService } from 'vs/workbench/contrib/stats/electron-browser/workspaceStatsService'; //#endregion diff --git a/src/vs/workbench/workbench.nodeless.main.ts b/src/vs/workbench/workbench.nodeless.main.ts deleted file mode 100644 index 97cf1b80d..000000000 --- a/src/vs/workbench/workbench.nodeless.main.ts +++ /dev/null @@ -1,334 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -//#region --- workbench/editor core - -import 'vs/editor/editor.all'; - -// import 'vs/workbench/api/electron-browser/extensionHost.contribution'; - -// import 'vs/workbench/electron-browser/main.contribution'; -import 'vs/workbench/browser/workbench.contribution'; - -import 'vs/workbench/browser/nodeless.main'; - -//#endregion - - -//#region --- workbench actions - -import 'vs/workbench/browser/actions/layoutActions'; -import 'vs/workbench/browser/actions/listCommands'; -import 'vs/workbench/browser/actions/navigationActions'; -import 'vs/workbench/browser/parts/quickopen/quickOpenActions'; -import 'vs/workbench/browser/parts/quickinput/quickInputActions'; - -//#endregion - - -//#region --- API Extension Points - -import 'vs/workbench/api/common/menusExtensionPoint'; -import 'vs/workbench/api/common/configurationExtensionPoint'; -import 'vs/workbench/api/browser/viewsExtensionPoint'; - -//#endregion - - -//#region --- workbench services -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IMenuService } from 'vs/platform/actions/common/actions'; -import { MenuService } from 'vs/platform/actions/common/menuService'; -import { IListService, ListService } from 'vs/platform/list/browser/listService'; -import { OpenerService } from 'vs/editor/browser/services/openerService'; -import { IOpenerService } from 'vs/platform/opener/common/opener'; -import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService'; -import { EditorWorkerServiceImpl } from 'vs/editor/common/services/editorWorkerServiceImpl'; -import { MarkerDecorationsService } from 'vs/editor/common/services/markerDecorationsServiceImpl'; -import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDecorationService'; -import { IMarkerService } from 'vs/platform/markers/common/markers'; -import { MarkerService } from 'vs/platform/markers/common/markerService'; -// import { IDownloadService } from 'vs/platform/download/common/download'; -// import { DownloadService } from 'vs/platform/download/node/downloadService'; -// import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; -// import { ClipboardService } from 'vs/platform/clipboard/electron-browser/clipboardService'; -import { ContextKeyService } from 'vs/platform/contextkey/browser/contextKeyService'; -import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { IModelService } from 'vs/editor/common/services/modelService'; -import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; -import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; -import { TextResourceConfigurationService } from 'vs/editor/common/services/resourceConfigurationImpl'; -import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; -import { BrowserAccessibilityService } from 'vs/platform/accessibility/common/accessibilityService'; -import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { ContextMenuService } from 'vs/platform/contextview/browser/contextMenuService'; -import { ContextViewService } from 'vs/platform/contextview/browser/contextViewService'; -// import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; -// import { IRequestService } from 'vs/platform/request/node/request'; -// import { RequestService } from 'vs/platform/request/electron-browser/requestService'; -// import { LifecycleService } from 'vs/platform/lifecycle/electron-browser/lifecycleService'; -// import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; -// import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; -// import { LocalizationsService } from 'vs/platform/localizations/electron-browser/localizationsService'; -// import { ISharedProcessService, SharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; -// import { RemoteAuthorityResolverService } from 'vs/platform/remote/electron-browser/remoteAuthorityResolverService'; -// import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; -// import { IProductService } from 'vs/platform/product/common/product'; -// import { ProductService } from 'vs/platform/product/node/productService'; -// import { IWindowsService } from 'vs/platform/windows/common/windows'; -// import { WindowsService } from 'vs/platform/windows/electron-browser/windowsService'; -// import { IUpdateService } from 'vs/platform/update/common/update'; -// import { UpdateService } from 'vs/platform/update/electron-browser/updateService'; -// import { IIssueService } from 'vs/platform/issue/common/issue'; -// import { IssueService } from 'vs/platform/issue/electron-browser/issueService'; -// import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; -// import { WorkspacesService } from 'vs/platform/workspaces/electron-browser/workspacesService'; -// import { IMenubarService } from 'vs/platform/menubar/common/menubar'; -// import { MenubarService } from 'vs/platform/menubar/electron-browser/menubarService'; -// import { IURLService } from 'vs/platform/url/common/url'; -// import { RelayURLService } from 'vs/platform/url/electron-browser/urlService'; -import { IHeapService, NullHeapService } from 'vs/workbench/services/heap/common/heap'; -import { IBroadcastService, NullBroadcastService } from 'vs/workbench/services/broadcast/common/broadcast'; -import { ConfigurationResolverService } from 'vs/workbench/services/configurationResolver/browser/configurationResolverService'; -import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; - -import 'vs/workbench/browser/nodeless.simpleservices'; -import 'vs/platform/dialogs/browser/dialogService'; - - -import 'vs/workbench/services/bulkEdit/browser/bulkEditService'; -// import 'vs/workbench/services/integrity/node/integrityService'; -import 'vs/workbench/services/keybinding/common/keybindingEditing'; -// import 'vs/workbench/services/textMate/electron-browser/textMateService'; -// import 'vs/workbench/services/workspace/electron-browser/workspaceEditingService'; -// import 'vs/workbench/services/extensions/electron-browser/inactiveExtensionUrlHandler'; -import 'vs/workbench/services/decorations/browser/decorationsService'; -// import 'vs/workbench/services/search/node/searchService'; -import 'vs/workbench/services/progress/browser/progressService2'; -import 'vs/workbench/services/editor/browser/codeEditorService'; -// import 'vs/workbench/services/broadcast/electron-browser/broadcastService'; -import 'vs/workbench/services/preferences/browser/preferencesService'; -import 'vs/workbench/services/output/common/outputChannelModelService'; -import 'vs/workbench/services/configuration/common/jsonEditingService'; -import 'vs/workbench/services/textmodelResolver/common/textModelResolverService'; -import 'vs/workbench/services/textfile/browser/textFileService'; -import 'vs/workbench/services/dialogs/browser/fileDialogService'; -// import 'vs/workbench/services/dialogs/electron-browser/dialogService'; -// import 'vs/workbench/services/backup/node/backupFileService'; -import 'vs/workbench/services/editor/browser/editorService'; -import 'vs/workbench/services/history/browser/history'; -import 'vs/workbench/services/activity/browser/activityService'; -import 'vs/workbench/browser/parts/views/views'; -// import 'vs/workbench/services/keybinding/electron-browser/keybindingService'; -import 'vs/workbench/services/untitled/common/untitledEditorService'; -// import 'vs/workbench/services/textfile/node/textResourcePropertiesService'; -import 'vs/workbench/services/mode/common/workbenchModeService'; -import 'vs/workbench/services/commands/common/commandService'; -import 'vs/workbench/services/themes/browser/workbenchThemeService'; -// import 'vs/workbench/services/extensionManagement/node/extensionEnablementService'; -// import 'vs/workbench/services/extensions/electron-browser/extensionService'; -// import 'vs/workbench/services/contextmenu/electron-browser/contextmenuService'; -// import 'vs/workbench/services/extensionManagement/node/multiExtensionManagement'; -import 'vs/workbench/services/label/common/labelService'; -// import 'vs/workbench/services/extensions/electron-browser/extensionManagementServerService'; -// import 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl'; -import 'vs/workbench/services/notification/common/notificationService'; -// import 'vs/workbench/services/heap/node/heap'; -// import 'vs/workbench/services/window/electron-browser/windowService'; -// import 'vs/workbench/services/telemetry/electron-browser/telemetryService'; - - -registerSingleton(IMenuService, MenuService, true); -registerSingleton(IListService, ListService, true); -registerSingleton(IOpenerService, OpenerService, true); -registerSingleton(IEditorWorkerService, EditorWorkerServiceImpl); -registerSingleton(IMarkerDecorationsService, MarkerDecorationsService); -registerSingleton(IMarkerService, MarkerService, true); -// registerSingleton(IDownloadService, DownloadService, true); -// registerSingleton(IClipboardService, ClipboardService, true); -registerSingleton(IContextKeyService, ContextKeyService); -registerSingleton(IModelService, ModelServiceImpl, true); -registerSingleton(ITextResourceConfigurationService, TextResourceConfigurationService); -registerSingleton(IAccessibilityService, BrowserAccessibilityService, true); -registerSingleton(IContextViewService, ContextViewService, true); -// registerSingleton(IExtensionGalleryService, ExtensionGalleryService, true); -// registerSingleton(IRequestService, RequestService, true); -// registerSingleton(ILifecycleService, LifecycleService); -// registerSingleton(ILocalizationsService, LocalizationsService); -// registerSingleton(ISharedProcessService, SharedProcessService, true); -// registerSingleton(IProductService, ProductService, true); -// registerSingleton(IWindowsService, WindowsService); -// registerSingleton(IUpdateService, UpdateService); -// registerSingleton(IIssueService, IssueService); -// registerSingleton(IWorkspacesService, WorkspacesService); -// registerSingleton(IMenubarService, MenubarService); -// registerSingleton(IURLService, RelayURLService); -registerSingleton(IHeapService, NullHeapService); -registerSingleton(IBroadcastService, NullBroadcastService); -registerSingleton(IContextMenuService, ContextMenuService); -registerSingleton(IConfigurationResolverService, ConfigurationResolverService, true); - -//#endregion - -//#region --- workbench parts - -import 'vs/workbench/browser/parts/quickinput/quickInput'; -import 'vs/workbench/browser/parts/quickopen/quickOpenController'; -import 'vs/workbench/browser/parts/titlebar/titlebarPart'; -import 'vs/workbench/browser/parts/editor/editorPart'; -import 'vs/workbench/browser/parts/activitybar/activitybarPart'; -import 'vs/workbench/browser/parts/panel/panelPart'; -import 'vs/workbench/browser/parts/sidebar/sidebarPart'; -import 'vs/workbench/browser/parts/statusbar/statusbarPart'; - -//#endregion - -//#region --- workbench contributions - -// Workspace File Watching -import 'vs/workbench/services/files/common/workspaceWatcher'; - -// Telemetry -import 'vs/workbench/contrib/telemetry/browser/telemetry.contribution'; - -// Localizations -// import 'vs/workbench/contrib/localizations/browser/localizations.contribution'; - -// Preferences -// import 'vs/workbench/contrib/preferences/electron-browser/preferences.contribution'; -import 'vs/workbench/contrib/preferences/browser/keybindingsEditorContribution'; - -// Logs -import 'vs/workbench/contrib/logs/common/logs.contribution'; - -// Quick Open Handlers -import 'vs/workbench/contrib/quickopen/browser/quickopen.contribution'; - -// Explorer -import 'vs/workbench/contrib/files/browser/explorerViewlet'; -import 'vs/workbench/contrib/files/browser/fileActions.contribution'; -import 'vs/workbench/contrib/files/browser/files.contribution'; - -// Backup -import 'vs/workbench/contrib/backup/common/backup.contribution'; - -// Stats -// import 'vs/workbench/contrib/stats/node/stats.contribution'; - -// Rapid Render Splash -// import 'vs/workbench/contrib/splash/electron-browser/partsSplash.contribution'; - -// Search -import 'vs/workbench/contrib/search/browser/search.contribution'; -import 'vs/workbench/contrib/search/browser/searchView'; -import 'vs/workbench/contrib/search/browser/openAnythingHandler'; - -// SCM -import 'vs/workbench/contrib/scm/browser/scm.contribution'; -import 'vs/workbench/contrib/scm/browser/scmViewlet'; - -// Debug -// import 'vs/workbench/contrib/debug/electron-browser/debug.contribution'; -// import 'vs/workbench/contrib/debug/browser/debugQuickOpen'; -// import 'vs/workbench/contrib/debug/browser/debugEditorContribution'; -// import 'vs/workbench/contrib/debug/browser/repl'; -// import 'vs/workbench/contrib/debug/browser/debugViewlet'; -// import 'vs/workbench/services/extensions/electron-browser/extensionHostDebugService'; - -// Markers -import 'vs/workbench/contrib/markers/browser/markers.contribution'; - -// Comments -// import 'vs/workbench/contrib/comments/browser/comments.contribution'; - -// URL Support -import 'vs/workbench/contrib/url/common/url.contribution'; - -// Webview -// import 'vs/workbench/contrib/webview/electron-browser/webview.contribution'; - -// Extensions Management -// import 'vs/workbench/contrib/extensions/electron-browser/extensions.contribution'; -// import 'vs/workbench/contrib/extensions/browser/extensionsQuickOpen'; -// import 'vs/workbench/contrib/extensions/electron-browser/extensionsViewlet'; - -// Output Panel -import 'vs/workbench/contrib/output/browser/output.contribution'; -import 'vs/workbench/contrib/output/browser/outputPanel'; - -// Terminal -// import 'vs/workbench/contrib/terminal/browser/terminal.contribution'; -// import 'vs/workbench/contrib/terminal/electron-browser/terminal.contribution'; -// import 'vs/workbench/contrib/terminal/browser/terminalQuickOpen'; -// import 'vs/workbench/contrib/terminal/browser/terminalPanel'; - -// Relauncher -// import 'vs/workbench/contrib/relauncher/electron-browser/relauncher.contribution'; - -// Tasks -// import 'vs/workbench/contrib/tasks/electron-browser/task.contribution'; - -// Emmet -import 'vs/workbench/contrib/emmet/browser/emmet.contribution'; - -// CodeEditor Contributions -import 'vs/workbench/contrib/codeEditor/browser/codeEditor.contribution'; -// import 'vs/workbench/contrib/codeEditor/electron-browser/codeEditor.contribution'; - -// Execution -// import 'vs/workbench/contrib/externalTerminal/electron-browser/externalTerminal.contribution'; - -// Snippets -import 'vs/workbench/contrib/snippets/browser/snippets.contribution'; -import 'vs/workbench/contrib/snippets/browser/snippetsService'; -import 'vs/workbench/contrib/snippets/browser/insertSnippet'; -import 'vs/workbench/contrib/snippets/browser/configureSnippets'; -import 'vs/workbench/contrib/snippets/browser/tabCompletion'; - -// Formatter Help -import 'vs/workbench/contrib/format/browser/format.contribution'; - -// Send a Smile -// import 'vs/workbench/contrib/feedback/electron-browser/feedback.contribution'; - -// Update -// import 'vs/workbench/contrib/update/electron-browser/update.contribution'; - -// Surveys -// import 'vs/workbench/contrib/surveys/electron-browser/nps.contribution'; -// import 'vs/workbench/contrib/surveys/electron-browser/languageSurveys.contribution'; - -// Performance -// import 'vs/workbench/contrib/performance/electron-browser/performance.contribution'; - -// CLI -// import 'vs/workbench/contrib/cli/node/cli.contribution'; - -// Themes Support -import 'vs/workbench/contrib/themes/browser/themes.contribution'; -// import 'vs/workbench/contrib/themes/test/electron-browser/themes.test.contribution'; - -// Watermark -import 'vs/workbench/contrib/watermark/browser/watermark'; - -// Welcome -import 'vs/workbench/contrib/welcome/walkThrough/browser/walkThrough.contribution'; -// import 'vs/workbench/contrib/welcome/gettingStarted/electron-browser/gettingStarted.contribution'; -import 'vs/workbench/contrib/welcome/overlay/browser/welcomeOverlay'; -// import 'vs/workbench/contrib/welcome/page/browser/welcomePage.contribution'; - -// Outline -import 'vs/workbench/contrib/outline/browser/outline.contribution'; - -// Experiments -// import 'vs/workbench/contrib/experiments/electron-browser/experiments.contribution'; - -// Code Insets -// import 'vs/workbench/contrib/codeinset/electron-browser/codeInset.contribution'; - -// Issues -// import 'vs/workbench/contrib/issue/electron-browser/issue.contribution'; - -//#endregion diff --git a/src/vs/workbench/workbench.web.api.ts b/src/vs/workbench/workbench.web.api.ts new file mode 100644 index 000000000..b1be3bab9 --- /dev/null +++ b/src/vs/workbench/workbench.web.api.ts @@ -0,0 +1,72 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import 'vs/workbench/workbench.web.main'; +import { main } from 'vs/workbench/browser/web.main'; +import { UriComponents } from 'vs/base/common/uri'; +import { IFileSystemProvider } from 'vs/platform/files/common/files'; +import { IRequestOptions, IRequestContext } from 'vs/platform/request/common/request'; +import { IWebSocketFactory } from 'vs/platform/remote/browser/browserSocketFactory'; + +export interface IWorkbenchConstructionOptions { + + /** + * Experimental: the remote authority is the IP:PORT from where the workbench is served + * from. It is for example being used for the websocket connections as address. + */ + remoteAuthority: string; + + /** + * The connection token to send to the server. + */ + connectionToken?: string; + + /** + * Experimental: An endpoint to serve iframe content ("webview") from. This is required + * to provide full security isolation from the workbench host. + */ + webviewEndpoint?: string; + + /** + * Experimental: An optional folder that is set as workspace context for the workbench. + */ + folderUri?: UriComponents; + + /** + * Experimental: An optional workspace that is set as workspace context for the workbench. + */ + workspaceUri?: UriComponents; + + /** + * Experimental: The userDataProvider is used to handle user specific application + * state like settings, keybindings, UI state (e.g. opened editors) and snippets. + */ + userDataProvider?: IFileSystemProvider; + + /** + * Experimental: Optional request handler to handle http requests. + * In case not provided, workbench uses <code>XMLHttpRequest</code>. + */ + requestHandler?: (requestOptions: IRequestOptions) => Promise<IRequestContext>; + + /** + * A factory for web sockets. + */ + webSocketFactory?: IWebSocketFactory; +} + +/** + * Experimental: Creates the workbench with the provided options in the provided container. + * + * @param domElement the container to create the workbench in + * @param options for setting up the workbench + */ +function create(domElement: HTMLElement, options: IWorkbenchConstructionOptions): Promise<void> { + return main(domElement, options); +} + +export { + create +}; diff --git a/src/vs/workbench/workbench.nodeless.main.css b/src/vs/workbench/workbench.web.main.css similarity index 100% rename from src/vs/workbench/workbench.nodeless.main.css rename to src/vs/workbench/workbench.web.main.css diff --git a/src/vs/workbench/workbench.nodeless.main.nls.js b/src/vs/workbench/workbench.web.main.nls.js similarity index 100% rename from src/vs/workbench/workbench.nodeless.main.nls.js rename to src/vs/workbench/workbench.web.main.nls.js diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts new file mode 100644 index 000000000..4d5cf7bfb --- /dev/null +++ b/src/vs/workbench/workbench.web.main.ts @@ -0,0 +1,359 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +//#region --- workbench/editor core + +import 'vs/editor/editor.all'; + +import 'vs/workbench/api/browser/extensionHost.contribution'; + +import 'vs/workbench/browser/workbench.contribution'; + +import 'vs/workbench/browser/web.main'; + +//#endregion + + +//#region --- workbench actions + +import 'vs/workbench/browser/actions/layoutActions'; +import 'vs/workbench/browser/actions/windowActions'; +import 'vs/workbench/browser/actions/developerActions'; +import 'vs/workbench/browser/actions/listCommands'; +import 'vs/workbench/browser/actions/navigationActions'; +import 'vs/workbench/browser/parts/quickopen/quickOpenActions'; +import 'vs/workbench/browser/parts/quickinput/quickInputActions'; + +//#endregion + + +//#region --- API Extension Points + +import 'vs/workbench/api/common/menusExtensionPoint'; +import 'vs/workbench/api/common/configurationExtensionPoint'; +import 'vs/workbench/api/browser/viewsExtensionPoint'; + +//#endregion + + +//#region --- workbench services +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IMenuService } from 'vs/platform/actions/common/actions'; +import { MenuService } from 'vs/platform/actions/common/menuService'; +import { IListService, ListService } from 'vs/platform/list/browser/listService'; +import { OpenerService } from 'vs/editor/browser/services/openerService'; +import { IOpenerService } from 'vs/platform/opener/common/opener'; +import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService'; +import { EditorWorkerServiceImpl } from 'vs/editor/common/services/editorWorkerServiceImpl'; +import { MarkerDecorationsService } from 'vs/editor/common/services/markerDecorationsServiceImpl'; +import { IMarkerDecorationsService } from 'vs/editor/common/services/markersDecorationService'; +import { IMarkerService } from 'vs/platform/markers/common/markers'; +import { MarkerService } from 'vs/platform/markers/common/markerService'; +import { IDownloadService } from 'vs/platform/download/common/download'; +import { DownloadService } from 'vs/platform/download/common/downloadService'; +import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; +import { BrowserClipboardService } from 'vs/platform/clipboard/browser/clipboardService'; +import { ContextKeyService } from 'vs/platform/contextkey/browser/contextKeyService'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IModelService } from 'vs/editor/common/services/modelService'; +import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; +import { ITextResourceConfigurationService } from 'vs/editor/common/services/resourceConfiguration'; +import { TextResourceConfigurationService } from 'vs/editor/common/services/resourceConfigurationImpl'; +import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; +import { BrowserAccessibilityService } from 'vs/platform/accessibility/common/accessibilityService'; +import { IExtensionGalleryService, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { ContextViewService } from 'vs/platform/contextview/browser/contextViewService'; +import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService'; +import { BrowserLifecycleService } from 'vs/platform/lifecycle/browser/lifecycleService'; +import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; +import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { DialogService } from 'vs/platform/dialogs/browser/dialogService'; +// import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; +// import { LocalizationsService } from 'vs/platform/localizations/electron-browser/localizationsService'; +// import { ISharedProcessService, SharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; +// import { IWindowsService } from 'vs/platform/windows/common/windows'; +// import { WindowsService } from 'vs/platform/windows/electron-browser/windowsService'; +// import { IUpdateService } from 'vs/platform/update/common/update'; +// import { UpdateService } from 'vs/platform/update/electron-browser/updateService'; +// import { IIssueService } from 'vs/platform/issue/common/issue'; +// import { IssueService } from 'vs/platform/issue/electron-browser/issueService'; +// import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; +// import { WorkspacesService } from 'vs/platform/workspaces/electron-browser/workspacesService'; +// import { IMenubarService } from 'vs/platform/menubar/common/menubar'; +// import { MenubarService } from 'vs/platform/menubar/electron-browser/menubarService'; +// import { IURLService } from 'vs/platform/url/common/url'; +// import { RelayURLService } from 'vs/platform/url/electron-browser/urlService'; +// import { ITunnelService } from 'vs/platform/remote/common/tunnel'; +// import { TunnelService } from 'vs/workbench/services/remote/node/tunnelService'; +// import { ICredentialsService } from 'vs/platform/credentials/common/credentials'; +// import { KeytarCredentialsService } from 'vs/platform/credentials/node/credentialsService'; +import 'vs/workbench/services/bulkEdit/browser/bulkEditService'; +// import 'vs/workbench/services/integrity/node/integrityService'; +import 'vs/workbench/services/keybinding/common/keybindingEditing'; +import 'vs/workbench/services/textMate/browser/textMateService'; +// import 'vs/workbench/services/workspace/electron-browser/workspaceEditingService'; +// import 'vs/workbench/services/extensions/electron-browser/inactiveExtensionUrlHandler'; +import 'vs/workbench/services/decorations/browser/decorationsService'; +import 'vs/workbench/services/search/common/searchService'; +import 'vs/workbench/services/progress/browser/progressService'; +import 'vs/workbench/services/editor/browser/codeEditorService'; +// import 'vs/workbench/services/extensions/electron-browser/extensionHostDebugService'; +import 'vs/workbench/services/preferences/browser/preferencesService'; +import 'vs/workbench/services/output/common/outputChannelModelService'; +import 'vs/workbench/services/configuration/common/jsonEditingService'; +import 'vs/workbench/services/textmodelResolver/common/textModelResolverService'; +import 'vs/workbench/services/textfile/browser/textFileService'; +import 'vs/workbench/services/dialogs/browser/fileDialogService'; +// import 'vs/workbench/services/dialogs/electron-browser/dialogService'; +import 'vs/workbench/services/editor/browser/editorService'; +import 'vs/workbench/services/history/browser/history'; +import 'vs/workbench/services/activity/browser/activityService'; +import 'vs/workbench/browser/parts/views/views'; +import 'vs/workbench/services/keybinding/browser/keymapService'; +import 'vs/workbench/services/keybinding/browser/keybindingService'; +import 'vs/workbench/services/untitled/common/untitledEditorService'; +import 'vs/workbench/services/textfile/common/textResourcePropertiesService'; +import 'vs/workbench/services/mode/common/workbenchModeService'; +import 'vs/workbench/services/commands/common/commandService'; +import 'vs/workbench/services/themes/browser/workbenchThemeService'; +import 'vs/workbench/services/extensions/browser/extensionService'; +// import 'vs/workbench/services/contextmenu/electron-browser/contextmenuService'; +import 'vs/workbench/services/label/common/labelService'; +import 'vs/workbench/services/extensionManagement/common/extensionManagementServerService'; +import 'vs/workbench/services/extensionManagement/common/extensionEnablementService'; +// import 'vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl'; +import 'vs/workbench/services/notification/common/notificationService'; +// import 'vs/workbench/services/window/electron-browser/windowService'; +import 'vs/workbench/services/telemetry/browser/telemetryService'; +import 'vs/workbench/services/configurationResolver/browser/configurationResolverService'; +import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView'; +import { ContextMenuService } from 'vs/platform/contextview/browser/contextMenuService'; +import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; +import { BackupFileService } from 'vs/workbench/services/backup/common/backupFileService'; +import { ExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagementService'; + +import 'vs/workbench/browser/web.simpleservices'; + +registerSingleton(IExtensionManagementService, ExtensionManagementService); +registerSingleton(IBackupFileService, BackupFileService); +registerSingleton(IDialogService, DialogService, true); +registerSingleton(IMenuService, MenuService, true); +registerSingleton(IListService, ListService, true); +registerSingleton(IOpenerService, OpenerService, true); +registerSingleton(IEditorWorkerService, EditorWorkerServiceImpl); +registerSingleton(IMarkerDecorationsService, MarkerDecorationsService); +registerSingleton(IMarkerService, MarkerService, true); +registerSingleton(IDownloadService, DownloadService, true); +registerSingleton(IClipboardService, BrowserClipboardService, true); +registerSingleton(IContextKeyService, ContextKeyService); +registerSingleton(IModelService, ModelServiceImpl, true); +registerSingleton(ITextResourceConfigurationService, TextResourceConfigurationService); +registerSingleton(IAccessibilityService, BrowserAccessibilityService, true); +registerSingleton(IContextViewService, ContextViewService, true); +registerSingleton(IExtensionGalleryService, ExtensionGalleryService, true); +registerSingleton(ILifecycleService, BrowserLifecycleService); +// registerSingleton(ILocalizationsService, LocalizationsService); +// registerSingleton(ISharedProcessService, SharedProcessService, true); +// registerSingleton(IWindowsService, WindowsService); +// registerSingleton(IUpdateService, UpdateService); +// registerSingleton(IIssueService, IssueService); +// registerSingleton(IWorkspacesService, WorkspacesService); +// registerSingleton(IMenubarService, MenubarService); +// registerSingleton(IURLService, RelayURLService); +// registerSingleton(ITunnelService, TunnelService, true); +// registerSingleton(ICredentialsService, KeytarCredentialsService, true); +registerSingleton(IContextMenuService, ContextMenuService); + +//#endregion + + +//#region --- workbench parts + +import 'vs/workbench/browser/parts/quickinput/quickInput'; +import 'vs/workbench/browser/parts/quickopen/quickOpenController'; +import 'vs/workbench/browser/parts/titlebar/titlebarPart'; +import 'vs/workbench/browser/parts/editor/editorPart'; +import 'vs/workbench/browser/parts/activitybar/activitybarPart'; +import 'vs/workbench/browser/parts/panel/panelPart'; +import 'vs/workbench/browser/parts/sidebar/sidebarPart'; +import 'vs/workbench/browser/parts/statusbar/statusbarPart'; + +//#endregion + + +//#region --- workbench contributions + +// Resource Service Worker +import 'vs/workbench/contrib/resources/browser/resourceServiceWorkerClient'; + +// Workspace File Watching +import 'vs/workbench/services/files/common/workspaceWatcher'; + +// Telemetry +import 'vs/workbench/contrib/telemetry/browser/telemetry.contribution'; + +// Localizations +// import 'vs/workbench/contrib/localizations/browser/localizations.contribution'; + +// Preferences +import 'vs/workbench/contrib/preferences/browser/preferences.contribution'; +import 'vs/workbench/contrib/preferences/browser/keybindingsEditorContribution'; +import 'vs/workbench/contrib/preferences/browser/keyboardLayoutPicker'; +import { IPreferencesSearchService } from 'vs/workbench/contrib/preferences/common/preferences'; +import { PreferencesSearchService } from 'vs/workbench/contrib/preferences/browser/preferencesSearch'; +registerSingleton(IPreferencesSearchService, PreferencesSearchService, true); + +// Logs +import 'vs/workbench/contrib/logs/common/logs.contribution'; + +// Quick Open Handlers +import 'vs/workbench/contrib/quickopen/browser/quickopen.contribution'; + +// Explorer +import 'vs/workbench/contrib/files/browser/explorerViewlet'; +import 'vs/workbench/contrib/files/browser/fileActions.contribution'; +import 'vs/workbench/contrib/files/browser/files.contribution'; + +// Backup +import 'vs/workbench/contrib/backup/common/backup.contribution'; + +// Stats +// import 'vs/workbench/contrib/stats/electron-browser/stats.contribution'; + +// Rapid Render Splash +// import 'vs/workbench/contrib/splash/electron-browser/partsSplash.contribution'; + +// Search +import 'vs/workbench/contrib/search/browser/search.contribution'; +import 'vs/workbench/contrib/search/browser/searchView'; +import 'vs/workbench/contrib/search/browser/openAnythingHandler'; + +// SCM +import 'vs/workbench/contrib/scm/browser/scm.contribution'; +import 'vs/workbench/contrib/scm/browser/scmViewlet'; + +// Debug +import 'vs/workbench/contrib/debug/browser/debug.contribution'; +import 'vs/workbench/contrib/debug/browser/debugQuickOpen'; +import 'vs/workbench/contrib/debug/browser/debugEditorContribution'; +import 'vs/workbench/contrib/debug/browser/repl'; +import 'vs/workbench/contrib/debug/browser/debugViewlet'; +import 'vs/workbench/contrib/debug/browser/debugHelperService'; + +// Markers +import 'vs/workbench/contrib/markers/browser/markers.contribution'; + +// Comments +import 'vs/workbench/contrib/comments/browser/comments.contribution'; + +// URL Support +import 'vs/workbench/contrib/url/common/url.contribution'; + +// Webview +import 'vs/workbench/contrib/webview/browser/webview.contribution'; + +import { IWebviewService } from 'vs/workbench/contrib/webview/common/webview'; +import { WebviewService } from 'vs/workbench/contrib/webview/browser/webviewService'; +import { IWebviewEditorService, WebviewEditorService } from 'vs/workbench/contrib/webview/browser/webviewEditorService'; +registerSingleton(IWebviewService, WebviewService, true); +registerSingleton(IWebviewEditorService, WebviewEditorService, true); + +// Extensions Management +import 'vs/workbench/contrib/extensions/browser/extensions.contribution'; +import 'vs/workbench/contrib/extensions/browser/extensionsQuickOpen'; +import 'vs/workbench/contrib/extensions/browser/extensionsViewlet'; + +// Output Panel +import 'vs/workbench/contrib/output/browser/output.contribution'; +import 'vs/workbench/contrib/output/browser/outputPanel'; + +// Terminal +import 'vs/workbench/contrib/terminal/browser/terminal.contribution'; +// import 'vs/workbench/contrib/terminal/electron-browser/terminal.contribution'; +import 'vs/workbench/contrib/terminal/browser/terminalQuickOpen'; +import 'vs/workbench/contrib/terminal/browser/terminalPanel'; + +import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal'; +import { ITerminalNativeService } from 'vs/workbench/contrib/terminal/common/terminal'; +import { TerminalNativeService } from 'vs/workbench/contrib/terminal/browser/terminalNativeService'; +import { TerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminalInstanceService'; +registerSingleton(ITerminalNativeService, TerminalNativeService, true); +registerSingleton(ITerminalInstanceService, TerminalInstanceService, true); + +// Relauncher +// import 'vs/workbench/contrib/relauncher/electron-browser/relauncher.contribution'; + +// Tasks +import 'vs/workbench/contrib/tasks/browser/task.contribution'; +import { TaskService } from 'vs/workbench/contrib/tasks/browser/taskService'; +import { ITaskService } from 'vs/workbench/contrib/tasks/common/taskService'; +registerSingleton(ITaskService, TaskService, true); + +// Remote +import 'vs/workbench/contrib/remote/common/remote.contribution'; +// import 'vs/workbench/contrib/remote/electron-browser/remote.contribution'; + +// Emmet +import 'vs/workbench/contrib/emmet/browser/emmet.contribution'; + +// CodeEditor Contributions +import 'vs/workbench/contrib/codeEditor/browser/codeEditor.contribution'; +// import 'vs/workbench/contrib/codeEditor/electron-browser/codeEditor.contribution'; + +// External terminal +import 'vs/workbench/contrib/externalTerminal/browser/externalTerminal.contribution'; + +// Snippets +import 'vs/workbench/contrib/snippets/browser/snippets.contribution'; +import 'vs/workbench/contrib/snippets/browser/snippetsService'; +import 'vs/workbench/contrib/snippets/browser/insertSnippet'; +import 'vs/workbench/contrib/snippets/browser/configureSnippets'; +import 'vs/workbench/contrib/snippets/browser/tabCompletion'; + +// Formatter Help +import 'vs/workbench/contrib/format/browser/format.contribution'; + +// Send a Smile +// import 'vs/workbench/contrib/feedback/browser/feedback.contribution'; + +// Update +// import 'vs/workbench/contrib/update/electron-browser/update.contribution'; + +// Surveys +// import 'vs/workbench/contrib/surveys/electron-browser/nps.contribution'; +// import 'vs/workbench/contrib/surveys/electron-browser/languageSurveys.contribution'; + +// Performance +// import 'vs/workbench/contrib/performance/electron-browser/performance.contribution'; + +// CLI +// import 'vs/workbench/contrib/cli/node/cli.contribution'; + +// Themes Support +import 'vs/workbench/contrib/themes/browser/themes.contribution'; +// import 'vs/workbench/contrib/themes/test/electron-browser/themes.test.contribution'; + +// Watermark +import 'vs/workbench/contrib/watermark/browser/watermark'; + +// Welcome +import 'vs/workbench/contrib/welcome/walkThrough/browser/walkThrough.contribution'; +// import 'vs/workbench/contrib/welcome/gettingStarted/electron-browser/gettingStarted.contribution'; +import 'vs/workbench/contrib/welcome/overlay/browser/welcomeOverlay'; +// import 'vs/workbench/contrib/welcome/page/browser/welcomePage.contribution'; + +// Call Hierarchy +import 'vs/workbench/contrib/callHierarchy/browser/callHierarchy.contribution'; + +// Outline +import 'vs/workbench/contrib/outline/browser/outline.contribution'; + +// Experiments +// import 'vs/workbench/contrib/experiments/electron-browser/experiments.contribution'; + +// Issues +// import 'vs/workbench/contrib/issue/electron-browser/issue.contribution'; + +//#endregion diff --git a/test/all.js b/test/all.js index 350e86068..834d63250 100644 --- a/test/all.js +++ b/test/all.js @@ -6,16 +6,12 @@ /*eslint-env mocha*/ /*global define,run*/ -var assert = require('assert'); -var path = require('path'); -var glob = require('glob'); -var istanbul = require('istanbul'); -var i_remap = require('remap-istanbul/lib/remap'); -var jsdom = require('jsdom-no-contextify'); -var minimatch = require('minimatch'); -var fs = require('fs'); -var vm = require('vm'); -var TEST_GLOB = '**/test/**/*.test.js'; +const assert = require('assert'); +const path = require('path'); +const glob = require('glob'); +const jsdom = require('jsdom-no-contextify'); +const TEST_GLOB = '**/test/**/*.test.js'; +const coverage = require('./coverage'); var optimist = require('optimist') .usage('Run the Code tests. All mocha options apply.') @@ -23,7 +19,6 @@ var optimist = require('optimist') .describe('run', 'Run a single file').string('run') .describe('coverage', 'Generate a coverage report').boolean('coverage') .describe('only-monaco-editor', 'Run only monaco editor tests').boolean('only-monaco-editor') - .describe('forceLoad', 'Force loading').boolean('forceLoad') .describe('browser', 'Run tests in a browser').boolean('browser') .alias('h', 'help').boolean('h') .describe('h', 'Show help'); @@ -58,103 +53,13 @@ function main() { }; if (argv.coverage) { - var instrumenter = new istanbul.Instrumenter(); - - var seenSources = {}; - - loaderConfig.nodeInstrumenter = function (contents, source) { - seenSources[source] = true; - - if (minimatch(source, TEST_GLOB)) { - return contents; - } - - return instrumenter.instrumentSync(contents, source); - }; + coverage.initialize(loaderConfig); process.on('exit', function (code) { if (code !== 0) { return; } - - if (argv.forceLoad) { - var allFiles = glob.sync(out + '/vs/**/*.js'); - allFiles = allFiles.map(function (source) { - return path.join(__dirname, '..', source); - }); - allFiles = allFiles.filter(function (source) { - if (seenSources[source]) { - return false; - } - if (minimatch(source, TEST_GLOB)) { - return false; - } - if (/fixtures/.test(source)) { - return false; - } - return true; - }); - allFiles.forEach(function (source, index) { - var contents = fs.readFileSync(source).toString(); - contents = instrumenter.instrumentSync(contents, source); - var stopAt = contents.indexOf('}\n__cov'); - stopAt = contents.indexOf('}\n__cov', stopAt + 1); - - var str = '(function() {' + contents.substr(0, stopAt + 1) + '});'; - var r = vm.runInThisContext(str, source); - r.call(global); - }); - } - - let remapIgnores = /\b((marked)|(raw\.marked)|(nls)|(css))\.js$/; - - var remappedCoverage = i_remap(global.__coverage__, { exclude: remapIgnores }).getFinalCoverage(); - - // The remapped coverage comes out with broken paths - var toUpperDriveLetter = function (str) { - if (/^[a-z]:/.test(str)) { - return str.charAt(0).toUpperCase() + str.substr(1); - } - return str; - }; - var toLowerDriveLetter = function (str) { - if (/^[A-Z]:/.test(str)) { - return str.charAt(0).toLowerCase() + str.substr(1); - } - return str; - }; - - var REPO_PATH = toUpperDriveLetter(path.join(__dirname, '..')); - var fixPath = function (brokenPath) { - var startIndex = brokenPath.indexOf(REPO_PATH); - if (startIndex === -1) { - return toLowerDriveLetter(brokenPath); - } - return toLowerDriveLetter(brokenPath.substr(startIndex)); - }; - - var finalCoverage = {}; - for (var entryKey in remappedCoverage) { - var entry = remappedCoverage[entryKey]; - entry.path = fixPath(entry.path); - finalCoverage[fixPath(entryKey)] = entry; - } - - var collector = new istanbul.Collector(); - collector.add(finalCoverage); - - var coveragePath = path.join(path.dirname(__dirname), '.build', 'coverage'); - var reportTypes = []; - if (argv.run || argv.runGlob) { - // single file running - coveragePath += '-single'; - reportTypes = ['lcovonly']; - } else { - reportTypes = ['json', 'lcov', 'html']; - } - var reporter = new istanbul.Reporter(null, coveragePath); - reporter.addAll(reportTypes); - reporter.write(collector, true, function () { }); + coverage.createReport(argv.run || argv.runGlob); }); } diff --git a/test/coverage.js b/test/coverage.js new file mode 100644 index 000000000..bf7e7aa3f --- /dev/null +++ b/test/coverage.js @@ -0,0 +1,86 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +const minimatch = require('minimatch'); +const fs = require('fs'); +const path = require('path'); +const iLibInstrument = require('istanbul-lib-instrument'); +const iLibCoverage = require('istanbul-lib-coverage'); +const iLibSourceMaps = require('istanbul-lib-source-maps'); +const iLibReport = require('istanbul-lib-report'); +const iReports = require('istanbul-reports'); + +const REPO_PATH = toUpperDriveLetter(path.join(__dirname, '..')); + +exports.initialize = function (loaderConfig) { + const instrumenter = iLibInstrument.createInstrumenter(); + loaderConfig.nodeInstrumenter = function (contents, source) { + if (minimatch(source, '**/test/**/*.test.js')) { + // tests don't get instrumented + return contents; + } + // Try to find a .map file + let map = null; + try { + map = JSON.parse(fs.readFileSync(`${source}.map`).toString()); + } catch (err) { + // missing source map... + } + return instrumenter.instrumentSync(contents, source, map); + }; +}; + +exports.createReport = function (isSingle) { + const mapStore = iLibSourceMaps.createSourceMapStore(); + const coverageMap = iLibCoverage.createCoverageMap(global.__coverage__); + const transformed = mapStore.transformCoverage(coverageMap); + + // Paths come out all broken + let newData = Object.create(null); + Object.keys(transformed.map.data).forEach((file) => { + const entry = transformed.map.data[file]; + const fixedPath = fixPath(entry.path); + entry.data.path = fixedPath; + newData[fixedPath] = entry; + }); + transformed.map.data = newData; + + const tree = iLibReport.summarizers.flat(transformed.map); + const context = iLibReport.createContext({ + dir: path.join(__dirname, `../.build/coverage${isSingle ? '-single' : ''}`) + }); + + let reports = []; + if (isSingle) { + reports.push(iReports.create('lcovonly')); + } else { + reports.push(iReports.create('json')); + reports.push(iReports.create('lcov')); + reports.push(iReports.create('html')); + } + reports.forEach(report => tree.visit(report, context)); +}; + +function toUpperDriveLetter(str) { + if (/^[a-z]:/.test(str)) { + return str.charAt(0).toUpperCase() + str.substr(1); + } + return str; +} + +function toLowerDriveLetter(str) { + if (/^[A-Z]:/.test(str)) { + return str.charAt(0).toLowerCase() + str.substr(1); + } + return str; +} + +function fixPath(brokenPath) { + const startIndex = brokenPath.lastIndexOf(REPO_PATH); + if (startIndex === -1) { + return toLowerDriveLetter(brokenPath); + } + return toLowerDriveLetter(brokenPath.substr(startIndex)); +} diff --git a/test/electron/index.js b/test/electron/index.js index ebd97e3b9..f21b3615c 100644 --- a/test/electron/index.js +++ b/test/electron/index.js @@ -100,20 +100,29 @@ function parseReporterOption(value) { app.on('ready', () => { + ipcMain.on('error', (_, err) => { + if (!argv.debug) { + console.error(err); + app.exit(1); + } + }); + const win = new BrowserWindow({ height: 600, width: 800, show: false, webPreferences: { backgroundThrottling: false, - webSecurity: false + nodeIntegration: true, + webSecurity: false, + webviewTag: true } }); win.webContents.on('did-finish-load', () => { if (argv.debug) { win.show(); - win.webContents.openDevTools({ mode: 'right' }); + win.webContents.openDevTools(); } win.webContents.send('run', argv); }); diff --git a/test/electron/renderer.html b/test/electron/renderer.html index 1eb67318b..724543895 100644 --- a/test/electron/renderer.html +++ b/test/electron/renderer.html @@ -19,4 +19,4 @@ </script> </body> -</html> \ No newline at end of file +</html> diff --git a/test/electron/renderer.js b/test/electron/renderer.js index addb1f0b9..36668cd53 100644 --- a/test/electron/renderer.js +++ b/test/electron/renderer.js @@ -9,11 +9,9 @@ const { ipcRenderer } = require('electron'); const assert = require('assert'); const path = require('path'); const glob = require('glob'); -const minimatch = require('minimatch'); -const istanbul = require('istanbul'); -const i_remap = require('remap-istanbul/lib/remap'); const util = require('util'); const bootstrap = require('../../src/bootstrap'); +const coverage = require('../coverage'); // Disabled custom inspect. See #38847 if (util.inspect && util.inspect['defaultOptions']) { @@ -42,77 +40,19 @@ function initLoader(opts) { } }; - // nodeInstrumenter when coverage is requested if (opts.coverage) { - const instrumenter = new istanbul.Instrumenter(); - - loaderConfig.nodeInstrumenter = function (contents, source) { - return minimatch(source, _tests_glob) - ? contents // don't instrument tests itself - : instrumenter.instrumentSync(contents, source); - }; + // initialize coverage if requested + coverage.initialize(loaderConfig); } loader.require.config(loaderConfig); } function createCoverageReport(opts) { - return new Promise(resolve => { - - if (!opts.coverage) { - return resolve(undefined); - } - - const exclude = /\b((marked)|(raw\.marked)|(nls)|(css))\.js$/; - const remappedCoverage = i_remap(global.__coverage__, { exclude: exclude }).getFinalCoverage(); - - // The remapped coverage comes out with broken paths - function toUpperDriveLetter(str) { - if (/^[a-z]:/.test(str)) { - return str.charAt(0).toUpperCase() + str.substr(1); - } - return str; - } - function toLowerDriveLetter(str) { - if (/^[A-Z]:/.test(str)) { - return str.charAt(0).toLowerCase() + str.substr(1); - } - return str; - } - - const REPO_PATH = toUpperDriveLetter(path.join(__dirname, '../..')); - const fixPath = function (brokenPath) { - const startIndex = brokenPath.indexOf(REPO_PATH); - if (startIndex === -1) { - return toLowerDriveLetter(brokenPath); - } - return toLowerDriveLetter(brokenPath.substr(startIndex)); - }; - - const finalCoverage = Object.create(null); - for (const entryKey in remappedCoverage) { - const entry = remappedCoverage[entryKey]; - entry.path = fixPath(entry.path); - finalCoverage[fixPath(entryKey)] = entry; - } - - const collector = new istanbul.Collector(); - collector.add(finalCoverage); - - let coveragePath = path.join(path.dirname(__dirname), '../.build/coverage'); - let reportTypes = []; - if (opts.run || opts.runGlob) { - // single file running - coveragePath += '-single'; - reportTypes = ['lcovonly']; - } else { - reportTypes = ['json', 'lcov', 'html']; - } - - const reporter = new istanbul.Reporter(null, coveragePath); - reporter.addAll(reportTypes); - reporter.write(collector, true, resolve); - }); + if (opts.coverage) { + coverage.createReport(opts.run || opts.runGlob); + } + return Promise.resolve(undefined); } function loadTestModules(opts) { @@ -273,5 +213,12 @@ function runTests(opts) { ipcRenderer.on('run', (e, opts) => { initLoader(opts); - runTests(opts).catch(err => console.error(typeof err === 'string' ? err : JSON.stringify(err))); + runTests(opts).catch(err => { + if (typeof err !== 'string') { + err = JSON.stringify(err); + } + + console.error(err); + ipcRenderer.send('error', err); + }); }); diff --git a/test/smoke/.gitignore b/test/smoke/.gitignore index 6601bb4c5..d7ed700e6 100644 --- a/test/smoke/.gitignore +++ b/test/smoke/.gitignore @@ -5,4 +5,5 @@ node_modules/ out/ keybindings.*.json test_data/ -src/vscode/driver.d.ts \ No newline at end of file +src/vscode/driver.d.ts +vscode-server*/ \ No newline at end of file diff --git a/test/smoke/README.md b/test/smoke/README.md index b8b98a358..b5be966e5 100644 --- a/test/smoke/README.md +++ b/test/smoke/README.md @@ -15,19 +15,22 @@ yarn smoketest # Build yarn smoketest --build PATH_TO_NEW_BUILD_PARENT_FOLDER --stable-build PATH_TO_LAST_STABLE_BUILD_PARENT_FOLDER + +# Remote +yarn smoketest --build PATH_TO_NEW_BUILD_PARENT_FOLDER --remote ``` ### Run for a release -You must always run the smoketest version which matches the release you are testing. So, if you want to run the smoketest for a release build (eg `release/1.22`), you need that version of the smoke tests too: +You must always run the smoketest version which matches the release you are testing. So, if you want to run the smoketest for a release build (e.g. `release/1.22`), you need that version of the smoke tests too: ```bash git checkout release/1.22 yarn ``` -In addition to the new build to be released you will need the previous stable build so that the smoketest can test the data migration. -The recommended way to make these builds available for the smoketest is by downloading their archive version (\*.zip) and extracting +In addition to the new build to be released you will need the previous stable build so that the smoketest can test the data migration. +The recommended way to make these builds available for the smoketest is by downloading their archive version (\*.zip) and extracting them into two folders. Pass the folder paths to the smoketest as follows: ```bash diff --git a/test/smoke/package.json b/test/smoke/package.json index 00b04f845..11b5662b2 100644 --- a/test/smoke/package.json +++ b/test/smoke/package.json @@ -17,12 +17,12 @@ "@types/mkdirp": "0.5.1", "@types/mocha": "2.2.41", "@types/ncp": "2.0.1", - "@types/node": "8.0.33", + "@types/node": "^10.14.8", "@types/rimraf": "2.0.2", "@types/webdriverio": "4.6.1", "concurrently": "^3.5.1", "cpx": "^1.5.0", - "electron": "3.1.8", + "electron": "4.2.7", "htmlparser2": "^3.9.2", "mkdirp": "^0.5.1", "mocha": "^5.2.0", @@ -35,5 +35,8 @@ "tmp": "0.0.33", "typescript": "2.9.2", "watch": "^1.0.2" + }, + "dependencies": { + "vscode-uri": "^2.0.3" } } diff --git a/test/smoke/src/application.ts b/test/smoke/src/application.ts index 58e5b301a..472d081ec 100644 --- a/test/smoke/src/application.ts +++ b/test/smoke/src/application.ts @@ -47,6 +47,10 @@ export class Application { return this.options.logger; } + get remote(): boolean { + return !!this.options.remote; + } + private _workspacePathOrFolder: string; get workspacePathOrFolder(): string { return this._workspacePathOrFolder; @@ -135,8 +139,12 @@ export class Application { await this.code.waitForWindowIds(ids => ids.length > 0); await this.code.waitForElement('.monaco-workbench'); + if (this.remote) { + await this.code.waitForElement('.monaco-workbench .statusbar-item[title="Editing on TestResolver"]'); + } + // wait a bit, since focus might be stolen off widgets - // as soon as they open (eg quick open) + // as soon as they open (e.g. quick open) await new Promise(c => setTimeout(c, 1000)); } } diff --git a/test/smoke/src/areas/editor/peek.ts b/test/smoke/src/areas/editor/peek.ts index be1dcfe5b..dc2533662 100644 --- a/test/smoke/src/areas/editor/peek.ts +++ b/test/smoke/src/areas/editor/peek.ts @@ -10,7 +10,7 @@ export class References { private static readonly REFERENCES_WIDGET = '.monaco-editor .zone-widget .zone-widget-container.peekview-widget.reference-zone-widget.results-loaded'; private static readonly REFERENCES_TITLE_FILE_NAME = `${References.REFERENCES_WIDGET} .head .peekview-title .filename`; private static readonly REFERENCES_TITLE_COUNT = `${References.REFERENCES_WIDGET} .head .peekview-title .meta`; - private static readonly REFERENCES = `${References.REFERENCES_WIDGET} .body .ref-tree.inline .monaco-list-row .reference`; + private static readonly REFERENCES = `${References.REFERENCES_WIDGET} .body .ref-tree.inline .monaco-list-row .highlight`; constructor(private code: Code) { } diff --git a/test/smoke/src/areas/extensions/extensions.test.ts b/test/smoke/src/areas/extensions/extensions.test.ts index 4215a7fe2..1ff6dce2d 100644 --- a/test/smoke/src/areas/extensions/extensions.test.ts +++ b/test/smoke/src/areas/extensions/extensions.test.ts @@ -20,6 +20,10 @@ export function setup() { await app.workbench.extensions.installExtension('michelkaporin.vscode-smoketest-check', 'vscode-smoketest-check'); await app.workbench.extensions.waitForExtensionsViewlet(); + + if (app.remote) { + await app.reload(); + } await app.workbench.quickopen.runCommand('Smoke Test Check'); await app.workbench.statusbar.waitForStatusbarText('smoke test', 'VS Code Smoke Test Check'); }); diff --git a/test/smoke/src/areas/git/git.test.ts b/test/smoke/src/areas/git/git.test.ts index d04677eaf..11546f7d7 100644 --- a/test/smoke/src/areas/git/git.test.ts +++ b/test/smoke/src/areas/git/git.test.ts @@ -7,7 +7,7 @@ import * as cp from 'child_process'; import { Application } from '../../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"]'; +const SYNC_STATUSBAR = 'div[id="workbench.parts.statusbar"] .statusbar-item[title$="Synchronize Changes"]'; export function setup() { describe('Git', () => { diff --git a/test/smoke/src/areas/multiroot/multiroot.test.ts b/test/smoke/src/areas/multiroot/multiroot.test.ts index f3ca92b88..d6c656bc4 100644 --- a/test/smoke/src/areas/multiroot/multiroot.test.ts +++ b/test/smoke/src/areas/multiroot/multiroot.test.ts @@ -47,7 +47,8 @@ export function setup() { const app = this.app as Application; await app.workbench.quickopen.openQuickOpen('*.*'); - await app.workbench.quickopen.waitForQuickOpenElements(names => names.length === 6); + // TODO roblourens: Go to files finds welcome page: issue 74875 + await app.workbench.quickopen.waitForQuickOpenElements(names => names.length === 6 || names.length === 7); await app.workbench.quickopen.closeQuickOpen(); }); diff --git a/test/smoke/src/areas/problems/problems.ts b/test/smoke/src/areas/problems/problems.ts index c71b7d337..e0499151d 100644 --- a/test/smoke/src/areas/problems/problems.ts +++ b/test/smoke/src/areas/problems/problems.ts @@ -39,7 +39,7 @@ export class Problems { } public static getSelectorInProblemsView(problemType: ProblemSeverity): string { - let selector = problemType === ProblemSeverity.WARNING ? 'warning' : 'error'; + let selector = problemType === ProblemSeverity.WARNING ? 'severity-warning' : 'severity-error'; return `div[id="workbench.panel.markers"] .monaco-tl-contents .marker-icon.${selector}`; } diff --git a/test/smoke/src/areas/statusbar/statusbar.ts b/test/smoke/src/areas/statusbar/statusbar.ts index b36678ea7..66e1186fd 100644 --- a/test/smoke/src/areas/statusbar/statusbar.ts +++ b/test/smoke/src/areas/statusbar/statusbar.ts @@ -38,7 +38,7 @@ export class StatusBar { } async waitForStatusbarText(title: string, text: string): Promise<void> { - await this.code.waitForTextContent(`${this.mainSelector} span[title="${title}"]`, text); + await this.code.waitForTextContent(`${this.mainSelector} .statusbar-item[title="${title}"]`, text); } private getSelector(element: StatusBarElement): string { @@ -48,17 +48,17 @@ export class StatusBar { case StatusBarElement.SYNC_STATUS: return `${this.mainSelector} ${this.leftSelector} .octicon.octicon-sync`; case StatusBarElement.PROBLEMS_STATUS: - return `${this.mainSelector} ${this.leftSelector} .task-statusbar-item[title="Problems"]`; + return `${this.mainSelector} ${this.leftSelector} .octicon.octicon-error`; case StatusBarElement.SELECTION_STATUS: - return `${this.mainSelector} ${this.rightSelector} .editor-status-selection`; + return `${this.mainSelector} ${this.rightSelector}[title="Go to Line"]`; case StatusBarElement.INDENTATION_STATUS: - return `${this.mainSelector} ${this.rightSelector} .editor-status-indentation`; + return `${this.mainSelector} ${this.rightSelector}[title="Select Indentation"]`; case StatusBarElement.ENCODING_STATUS: - return `${this.mainSelector} ${this.rightSelector} .editor-status-encoding`; + return `${this.mainSelector} ${this.rightSelector}[title="Select Encoding"]`; case StatusBarElement.EOL_STATUS: - return `${this.mainSelector} ${this.rightSelector} .editor-status-eol`; + return `${this.mainSelector} ${this.rightSelector}[title="Select End of Line Sequence"]`; case StatusBarElement.LANGUAGE_STATUS: - return `${this.mainSelector} ${this.rightSelector} .editor-status-mode`; + return `${this.mainSelector} ${this.rightSelector}[title="Select Language Mode"]`; case StatusBarElement.FEEDBACK_ICON: return `${this.mainSelector} ${this.rightSelector} .monaco-dropdown.send-feedback`; default: diff --git a/test/smoke/src/areas/workbench/localization.test.ts b/test/smoke/src/areas/workbench/localization.test.ts index c0844c2c6..e9e0b44a4 100644 --- a/test/smoke/src/areas/workbench/localization.test.ts +++ b/test/smoke/src/areas/workbench/localization.test.ts @@ -37,7 +37,7 @@ export function setup() { await app.workbench.scm.waitForTitle(title => /quellcodeverwaltung/i.test(title)); await app.workbench.debug.openDebugViewlet(); - await app.workbench.debug.waitForTitle(title => /debuggen/i.test(title)); + await app.workbench.debug.waitForTitle(title => /debug/i.test(title)); await app.workbench.extensions.openExtensionsViewlet(); await app.workbench.extensions.waitForTitle(title => /erweiterungen/i.test(title)); diff --git a/test/smoke/src/main.ts b/test/smoke/src/main.ts index 21a0fe252..eefa5d358 100644 --- a/test/smoke/src/main.ts +++ b/test/smoke/src/main.ts @@ -156,7 +156,12 @@ async function setupRepository(): Promise<void> { console.log('*** Copying test project repository:', opts['test-repo']); rimraf.sync(workspacePath); // not platform friendly - cp.execSync(`cp -R "${opts['test-repo']}" "${workspacePath}"`); + if (process.platform === 'win32') { + cp.execSync(`xcopy /E "${opts['test-repo']}" "${workspacePath}"\\*`); + } else { + cp.execSync(`cp -R "${opts['test-repo']}" "${workspacePath}"`); + } + } else { if (!fs.existsSync(workspacePath)) { console.log('*** Cloning test project repository...'); diff --git a/test/smoke/src/vscode/code.ts b/test/smoke/src/vscode/code.ts index e657d0825..9f468fddd 100644 --- a/test/smoke/src/vscode/code.ts +++ b/test/smoke/src/vscode/code.ts @@ -6,9 +6,13 @@ import * as path from 'path'; import * as cp from 'child_process'; import * as os from 'os'; +import * as fs from 'fs'; +import * as mkdirp from 'mkdirp'; import { tmpName } from 'tmp'; import { IDriver, connect as connectDriver, IDisposable, IElement, Thenable } from './driver'; import { Logger } from '../logger'; +import { ncp } from 'ncp'; +import { URI } from 'vscode-uri'; const repoPath = path.join(__dirname, '../../../..'); @@ -121,13 +125,24 @@ export async function spawn(options: SpawnOptions): Promise<Code> { '--driver', handle ]; + const env = process.env; + if (options.remote) { // Replace workspace path with URI - args.shift(); - args.push( - `--${options.workspacePath.endsWith('.code-workspace') ? 'file' : 'folder'}-uri`, - `vscode-remote://test+test${options.workspacePath}`, - ); + args[0] = `--${options.workspacePath.endsWith('.code-workspace') ? 'file' : 'folder'}-uri=vscode-remote://test+test/${URI.file(options.workspacePath).path}`; + + if (codePath) { + // running against a build: copy the test resolver extension + const testResolverExtPath = path.join(options.extensionsPath, 'vscode-test-resolver'); + if (!fs.existsSync(testResolverExtPath)) { + const orig = path.join(repoPath, 'extensions', 'vscode-test-resolver'); + await new Promise((c, e) => ncp(orig, testResolverExtPath, err => err ? e(err) : c())); + } + } + args.push('--enable-proposed-api=vscode.vscode-test-resolver'); + const remoteDataDir = `${options.userDataDir}-server`; + mkdirp.sync(remoteDataDir); + env['TESTRESOLVER_DATA_FOLDER'] = remoteDataDir; } if (!codePath) { @@ -146,7 +161,7 @@ export async function spawn(options: SpawnOptions): Promise<Code> { args.push(...options.extraArgs); } - const spawnOptions: cp.SpawnOptions = {}; + const spawnOptions: cp.SpawnOptions = { env }; const child = cp.spawn(electronPath, args, spawnOptions); diff --git a/test/smoke/yarn.lock b/test/smoke/yarn.lock index 5e1fd36aa..b86356d3a 100644 --- a/test/smoke/yarn.lock +++ b/test/smoke/yarn.lock @@ -44,15 +44,15 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.51.tgz#b31d716fb8d58eeb95c068a039b9b6292817d5fb" integrity sha512-El3+WJk2D/ppWNd2X05aiP5l2k4EwF7KwheknQZls+I26eSICoWRhRIJ56jGgw2dqNGQ5LtNajmBU2ajS28EvQ== -"@types/node@8.0.33": - version "8.0.33" - resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.33.tgz#1126e94374014e54478092830704f6ea89df04cd" - integrity sha512-vmCdO8Bm1ExT+FWfC9sd9r4jwqM7o97gGy2WBshkkXbf/2nLAJQUrZfIhw27yVOtLUev6kSZc4cav/46KbDd8A== +"@types/node@^10.12.18": + version "10.12.18" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.18.tgz#1d3ca764718915584fcd9f6344621b7672665c67" + integrity sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ== -"@types/node@^8.0.24": - version "8.10.23" - resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.23.tgz#e5ccfdafff42af5397c29669b6d7d65f7d629a00" - integrity sha512-aEp5ZTLr4mYhR9S85cJ+sEYkcsgFY10N1Si5m49iTAVzanZXOwp/pgw6ibFLKXxpflqm71aSWZCRtnTXXO56gA== +"@types/node@^10.14.8": + version "10.14.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9" + integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw== "@types/rimraf@2.0.2": version "2.0.2" @@ -74,14 +74,6 @@ abbrev@1: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== -ajv@^4.9.1: - version "4.11.8" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" - integrity sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY= - dependencies: - co "^4.6.0" - json-stable-stringify "^1.0.1" - ajv@^5.1.0: version "5.3.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.3.0.tgz#4414ff74a50879c208ee5fdc826e32c303549eda" @@ -126,9 +118,9 @@ aproba@^1.0.3: integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== are-we-there-yet@~1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" - integrity sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0= + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== dependencies: delegates "^1.0.0" readable-stream "^2.0.6" @@ -140,11 +132,21 @@ arr-diff@^2.0.0: dependencies: arr-flatten "^1.0.1" -arr-flatten@^1.0.1: +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= + +arr-flatten@^1.0.1, arr-flatten@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= + array-filter@~0.0.0: version "0.0.1" resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-0.0.1.tgz#7da8cf2e26628ed732803581fd21f67cacd2eeec" @@ -170,6 +172,11 @@ array-unique@^0.2.1: resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" integrity sha1-odl8yvy8JiXMcPrc6zalDFiwGlM= +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= + asn1@~0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" @@ -180,36 +187,31 @@ assert-plus@1.0.0, assert-plus@^1.0.0: resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= -assert-plus@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" - integrity sha1-104bh+ev/A24qttwIfP+SBAasjQ= +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= async-each@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" - integrity sha1-GdOGodntxufByF04iu28xW0zYC0= + version "1.0.3" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" + integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= -aws-sign2@~0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" - integrity sha1-FDQt0428yU0OW4fXY81jYSwOeU8= +atob@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= -aws4@^1.2.1: - version "1.7.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.7.0.tgz#d4d0e9b9dbfca77bf08eeb0a8a471550fe39e289" - integrity sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w== - aws4@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" @@ -228,6 +230,19 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + bcrypt-pbkdf@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" @@ -236,29 +251,15 @@ bcrypt-pbkdf@^1.0.0: tweetnacl "^0.14.3" binary-extensions@^1.0.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" - integrity sha1-RqoXUftqL5PuXmibsQh9SxTGwgU= - -block-stream@*: - version "0.0.9" - resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" - integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo= - dependencies: - inherits "~2.0.0" + version "1.13.1" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" + integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== bluebird@^2.9.34: version "2.11.0" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" integrity sha1-U0uQM8AiyVecVro7Plpcqvu2UOE= -boom@2.x.x: - version "2.10.1" - resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" - integrity sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8= - dependencies: - hoek "2.x.x" - boom@4.x.x: version "4.3.1" resolved "https://registry.yarnpkg.com/boom/-/boom-4.3.1.tgz#4f8a3005cb4a7e3889f749030fd25b96e01d2e31" @@ -290,6 +291,22 @@ braces@^1.8.2: preserve "^0.2.0" repeat-element "^1.1.2" +braces@^2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + browser-stdout@1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" @@ -300,6 +317,21 @@ builtin-modules@^1.0.0: resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + camelcase-keys@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" @@ -350,6 +382,21 @@ chokidar@^1.6.0: optionalDependencies: fsevents "^1.0.0" +chownr@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" + integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g== + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -360,6 +407,14 @@ code-point-at@^1.0.0: resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + combined-stream@^1.0.5, combined-stream@~1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" @@ -382,6 +437,11 @@ commander@^2.8.1: resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" integrity sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ== +component-emitter@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -415,10 +475,15 @@ console-control-strings@^1.0.0, console-control-strings@~1.1.0: resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + core-js@^2.4.0: - version "2.5.1" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.1.tgz#ae6874dc66937789b80754ff5428df66819ca50b" - integrity sha1-rmh03GaTd4m4B1T/VCjfZoGcpQs= + version "2.6.9" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2" + integrity sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A== core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" @@ -447,13 +512,6 @@ crypt@~0.0.1: resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs= -cryptiles@2.x.x: - version "2.0.5" - resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" - integrity sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g= - dependencies: - boom "2.x.x" - cryptiles@3.x.x: version "3.1.2" resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-3.1.2.tgz#a89fbb220f5ce25ec56e8c4aa8a4fd7b5b0d29fe" @@ -480,7 +538,7 @@ date-fns@^1.23.0: resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.29.0.tgz#12e609cdcb935127311d04d33334e2960a2a54e6" integrity sha512-lbTXWZ6M20cWH8N9S6afb0SBm6tMk+uUg6z3MqHPKE9atmsY3kJkTm8vKe93izJ2B2+q5MV990sM2CHgtAZaOw== -debug@2.6.9, debug@^2.1.3, debug@^2.2.0: +debug@2.6.9, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -494,7 +552,7 @@ debug@3.1.0, debug@^3.1.0: dependencies: ms "2.0.0" -debug@^3.0.0: +debug@^3.0.0, debug@^3.2.6: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== @@ -506,15 +564,37 @@ decamelize@^1.1.2: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + deep-extend@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== -deep-extend@~0.4.0: - version "0.4.2" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" - integrity sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8= +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" delayed-stream@~1.0.0: version "1.0.0" @@ -596,12 +676,12 @@ electron-download@^4.1.0: semver "^5.4.1" sumchecker "^2.0.2" -electron@3.1.8: - version "3.1.8" - resolved "https://registry.yarnpkg.com/electron/-/electron-3.1.8.tgz#01b0b147dfcca47967ff07dbf72bf5e96125a2ac" - integrity sha512-1MiFoMzxGaR0wDfwFE5Ydnuk6ry/4lKgF0c+NFyEItxM/WyEHNZPNjJAeKJ+M/0sevmZ+6W4syNZnQL5M3GgsQ== +electron@4.2.7: + version "4.2.7" + resolved "https://registry.yarnpkg.com/electron/-/electron-4.2.7.tgz#bdd2dbf489a4a4255405bd8330cc8509831d29ba" + integrity sha512-Azpkw0OPzKVipSsN9/0DrBQhXOpG48Q1gTG7Akchtv37s8TijMe403TUgHxGGhw2ti117ek51kYf7NXLhjXqoA== dependencies: - "@types/node" "^8.0.24" + "@types/node" "^10.12.18" electron-download "^4.1.0" extract-zip "^1.0.3" @@ -641,6 +721,19 @@ expand-brackets@^0.1.4: dependencies: is-posix-bracket "^0.1.0" +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + expand-range@^1.8.1: version "1.8.2" resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" @@ -648,7 +741,22 @@ expand-range@^1.8.1: dependencies: fill-range "^2.1.0" -extend@~3.0.0, extend@~3.0.1: +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend@~3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" integrity sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ= @@ -660,6 +768,20 @@ extglob@^0.3.1: dependencies: is-extglob "^1.0.0" +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + extract-zip@^1.0.3: version "1.6.6" resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.6.tgz#1290ede8d20d0872b429fd3f351ca128ec5ef85c" @@ -698,16 +820,26 @@ filename-regex@^2.0.0: integrity sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY= fill-range@^2.1.0: - version "2.2.3" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" - integrity sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM= + version "2.2.4" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" + integrity sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q== dependencies: is-number "^2.1.0" isobject "^2.0.0" - randomatic "^1.1.3" + randomatic "^3.0.0" repeat-element "^1.1.2" repeat-string "^1.5.2" +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + find-index@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/find-index/-/find-index-0.1.1.tgz#675d358b2ca3892d795a1ab47232f8b6e2e0dde4" @@ -721,7 +853,7 @@ find-up@^1.0.0: path-exists "^2.0.0" pinkie-promise "^2.0.0" -for-in@^1.0.1: +for-in@^1.0.1, for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= @@ -738,15 +870,6 @@ forever-agent@~0.6.1: resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= -form-data@~2.1.1: - version "2.1.4" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" - integrity sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE= - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.5" - mime-types "^2.1.12" - form-data@~2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.1.tgz#6fb94fbd71885306d73d15cc497fe4cc4ecd44bf" @@ -756,6 +879,13 @@ form-data@~2.3.1: combined-stream "^1.0.5" mime-types "^2.1.12" +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= + dependencies: + map-cache "^0.2.2" + fs-extra@^4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" @@ -765,37 +895,25 @@ fs-extra@^4.0.1: jsonfile "^4.0.0" universalify "^0.1.0" +fs-minipass@^1.2.5: + version "1.2.6" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.6.tgz#2c5cc30ded81282bfe8a0d7c7c1853ddeb102c07" + integrity sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ== + dependencies: + minipass "^2.2.1" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= fsevents@^1.0.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.3.tgz#11f82318f5fe7bb2cd22965a108e9306208216d8" - integrity sha512-WIr7iDkdmdbxu/Gh6eKEZJL6KPE74/5MEsf2whTOFNxbIoIixogroLdKYqB6FDav4Wavh/lZdzzd3b2KxIXC5Q== + version "1.2.9" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.9.tgz#3f5ed66583ccd6f400b5a00db6f7e861363e388f" + integrity sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw== dependencies: - nan "^2.3.0" - node-pre-gyp "^0.6.39" - -fstream-ignore@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" - integrity sha1-nDHa40dnAY/h0kmyTa2mfQktoQU= - dependencies: - fstream "^1.0.0" - inherits "2" - minimatch "^3.0.0" - -fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: - version "1.0.11" - resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" - integrity sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE= - dependencies: - graceful-fs "^4.1.2" - inherits "~2.0.0" - mkdirp ">=0.5 0" - rimraf "2" + nan "^2.12.1" + node-pre-gyp "^0.12.0" gauge@~2.7.3: version "2.7.4" @@ -816,6 +934,11 @@ get-stdin@^4.0.1: resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4= +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= + getpass@^0.1.1: version "0.1.7" resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" @@ -857,6 +980,11 @@ glob@7.1.2, glob@^7.0.5: once "^1.3.0" path-is-absolute "^1.0.0" +graceful-fs@^4.1.11: + version "4.2.0" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.0.tgz#8d8fdc73977cb04104721cb53666c1ca64cd328b" + integrity sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg== + graceful-fs@^4.1.2, graceful-fs@^4.1.6: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" @@ -867,24 +995,11 @@ growl@1.10.5: resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== -har-schema@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" - integrity sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4= - har-schema@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= -har-validator@~4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" - integrity sha1-M0gdDxu/9gDdID11gSpqX7oALio= - dependencies: - ajv "^4.9.1" - har-schema "^1.0.5" - har-validator@~5.0.3: version "5.0.3" resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" @@ -915,15 +1030,36 @@ has-unicode@^2.0.0: resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= -hawk@3.1.3, hawk@~3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" - integrity sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ= +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= dependencies: - boom "2.x.x" - cryptiles "2.x.x" - hoek "2.x.x" - sntp "1.x.x" + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" hawk@~6.0.2: version "6.0.2" @@ -940,11 +1076,6 @@ he@1.1.1: resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0= -hoek@2.x.x: - version "2.16.3" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" - integrity sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0= - hoek@4.x.x: version "4.2.0" resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.0.tgz#72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d" @@ -967,15 +1098,6 @@ htmlparser2@^3.9.2: inherits "^2.0.1" readable-stream "^2.0.2" -http-signature@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" - integrity sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8= - dependencies: - assert-plus "^0.2.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - http-signature@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" @@ -985,6 +1107,20 @@ http-signature@~1.2.0: jsprim "^1.2.2" sshpk "^1.7.0" +iconv-lite@^0.4.4: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ignore-walk@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" + integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ== + dependencies: + minimatch "^3.0.4" + indent-string@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" @@ -1000,7 +1136,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= @@ -1010,6 +1146,20 @@ ini@~1.3.0: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" integrity sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4= +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== + dependencies: + kind-of "^6.0.0" + is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" @@ -1034,6 +1184,38 @@ is-builtin-module@^1.0.0: dependencies: builtin-modules "^1.0.0" +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== + dependencies: + kind-of "^6.0.0" + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + is-dotfile@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" @@ -1046,11 +1228,18 @@ is-equal-shallow@^0.1.3: dependencies: is-primitive "^2.0.0" -is-extendable@^0.1.1: +is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + is-extglob@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" @@ -1070,6 +1259,11 @@ is-fullwidth-code-point@^1.0.0: dependencies: number-is-nan "^1.0.0" +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + is-glob@^2.0.0, is-glob@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" @@ -1091,6 +1285,18 @@ is-number@^3.0.0: dependencies: kind-of "^3.0.2" +is-number@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" + integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ== + +is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + is-posix-bracket@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" @@ -1111,6 +1317,11 @@ is-utf8@^0.2.0: resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + isarray@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" @@ -1128,6 +1339,11 @@ isobject@^2.0.0: dependencies: isarray "1.0.0" +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" @@ -1148,13 +1364,6 @@ json-schema@0.2.3: resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= -json-stable-stringify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" - integrity sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8= - dependencies: - jsonify "~0.0.0" - json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" @@ -1182,7 +1391,7 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" -kind-of@^3.0.2: +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= @@ -1196,6 +1405,16 @@ kind-of@^4.0.0: dependencies: is-buffer "^1.1.5" +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== + load-json-file@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" @@ -1225,11 +1444,28 @@ loud-rejection@^1.0.0: currently-unhandled "^0.4.1" signal-exit "^3.0.0" +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= + map-obj@^1.0.0, map-obj@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= + dependencies: + object-visit "^1.0.0" + +math-random@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.4.tgz#5dd6943c938548267016d4e34f057583080c514c" + integrity sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A== + md5@^2.1.0: version "2.2.1" resolved "https://registry.yarnpkg.com/md5/-/md5-2.2.1.tgz#53ab38d5fe3c8891ba465329ea23fac0540126f9" @@ -1279,16 +1515,30 @@ micromatch@^2.1.5: parse-glob "^3.0.4" regex-cache "^0.4.2" +micromatch@^3.1.10: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + mime-db@~1.30.0: version "1.30.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" integrity sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE= -mime-db@~1.33.0: - version "1.33.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" - integrity sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ== - mime-types@^2.1.12, mime-types@~2.1.17: version "2.1.17" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a" @@ -1296,14 +1546,7 @@ mime-types@^2.1.12, mime-types@~2.1.17: dependencies: mime-db "~1.30.0" -mime-types@~2.1.7: - version "2.1.18" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" - integrity sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ== - dependencies: - mime-db "~1.33.0" - -minimatch@3.0.4, minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4: +minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== @@ -1320,6 +1563,29 @@ minimist@^1.1.0, minimist@^1.1.3, minimist@^1.2.0: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= +minipass@^2.2.1, minipass@^2.3.5: + version "2.3.5" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" + integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA== + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614" + integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA== + dependencies: + minipass "^2.2.1" + +mixin-deep@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + mkdirp@0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12" @@ -1327,7 +1593,7 @@ mkdirp@0.5.0: dependencies: minimist "0.0.8" -mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.1, mkdirp@~0.5.1: +mkdirp@0.5.1, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= @@ -1380,32 +1646,57 @@ ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== -nan@^2.3.0: - version "2.10.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" - integrity sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA== +nan@^2.12.1: + version "2.14.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" + integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" ncp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3" integrity sha1-GVoh1sRuNh0vsSgbo4uR6d9727M= -node-pre-gyp@^0.6.39: - version "0.6.39" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz#c00e96860b23c0e1420ac7befc5044e1d78d8649" - integrity sha512-OsJV74qxnvz/AMGgcfZoDaeDXKD3oY3QVIbBmwszTFkRisTSXbMQyn4UWzUMOtA5SVhrBZOTp0wcoSBgfMfMmQ== +needle@^2.2.1: + version "2.4.0" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c" + integrity sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg== + dependencies: + debug "^3.2.6" + iconv-lite "^0.4.4" + sax "^1.2.4" + +node-pre-gyp@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149" + integrity sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A== dependencies: detect-libc "^1.0.2" - hawk "3.1.3" mkdirp "^0.5.1" + needle "^2.2.1" nopt "^4.0.1" + npm-packlist "^1.1.6" npmlog "^4.0.2" - rc "^1.1.7" - request "2.81.0" + rc "^1.2.7" rimraf "^2.6.1" semver "^5.3.0" - tar "^2.2.1" - tar-pack "^3.4.0" + tar "^4" nopt@^4.0.1: version "4.0.1" @@ -1432,6 +1723,19 @@ normalize-path@^2.0.0, normalize-path@^2.0.1: dependencies: remove-trailing-separator "^1.0.1" +npm-bundled@^1.0.1: + version "1.0.6" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd" + integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g== + +npm-packlist@^1.1.6: + version "1.4.4" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.4.tgz#866224233850ac534b63d1a6e76050092b5d2f44" + integrity sha512-zTLo8UcVYtDU3gdeaFu2Xu0n0EvelfHDGuqtNIn5RO7yQj4H1TqNdBc/yZjxnWA0PVB8D3Woyp0i5B43JwQ6Vw== + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + npmlog@^4.0.2: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" @@ -1460,7 +1764,7 @@ number-is-nan@^1.0.0: resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= -oauth-sign@~0.8.1, oauth-sign@~0.8.2: +oauth-sign@~0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" integrity sha1-Rqarfwrq2N6unsBWV4C31O/rnUM= @@ -1470,11 +1774,27 @@ object-assign@^4.0.1, object-assign@^4.1.0: resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + object-keys@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336" integrity sha1-KKaq50KN0sOpLz2V8hM13SBOAzY= +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + dependencies: + isobject "^3.0.0" + object.omit@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" @@ -1483,7 +1803,14 @@ object.omit@^2.0.0: for-own "^0.1.4" is-extendable "^0.1.1" -once@^1.3.0, once@^1.3.3: +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + dependencies: + isobject "^3.0.1" + +once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= @@ -1525,6 +1852,11 @@ parse-json@^2.2.0: dependencies: error-ex "^1.2.0" +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + path-exists@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" @@ -1542,10 +1874,10 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= -path-parse@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" - integrity sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME= +path-parse@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== path-type@^1.0.0: version "1.1.0" @@ -1561,11 +1893,6 @@ pend@~1.2.0: resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= -performance-now@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" - integrity sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU= - performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" @@ -1597,6 +1924,11 @@ portastic@^1.0.1: commander "^2.8.1" debug "^2.2.0" +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" @@ -1616,9 +1948,9 @@ process-nextick-args@~1.0.6: integrity sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M= process-nextick-args@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" - integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== progress-stream@^1.1.0: version "1.2.0" @@ -1633,35 +1965,21 @@ punycode@^1.4.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= -qs@~6.4.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" - integrity sha1-E+JtKK1rD/qpExLNO/cI7TUecjM= - qs@~6.5.1: version "6.5.1" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" integrity sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A== -randomatic@^1.1.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" - integrity sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how== +randomatic@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed" + integrity sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw== dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" + is-number "^4.0.0" + kind-of "^6.0.0" + math-random "^1.0.1" -rc@^1.1.7: - version "1.2.6" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.6.tgz#eb18989c6d4f4f162c399f79ddd29f3835568092" - integrity sha1-6xiYnG1PTxYsOZ953dKfODVWgJI= - dependencies: - deep-extend "~0.4.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" - -rc@^1.2.1: +rc@^1.2.1, rc@^1.2.7: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== @@ -1701,7 +2019,7 @@ readable-stream@^2.0.2, readable-stream@^2.2.2: string_decoder "~1.0.3" util-deprecate "~1.0.1" -readable-stream@^2.0.6, readable-stream@^2.1.4: +readable-stream@^2.0.6: version "2.3.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== @@ -1725,14 +2043,13 @@ readable-stream@~1.1.9: string_decoder "~0.10.x" readdirp@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" - integrity sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg= + version "2.2.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== dependencies: - graceful-fs "^4.1.2" - minimatch "^3.0.2" + graceful-fs "^4.1.11" + micromatch "^3.1.10" readable-stream "^2.0.2" - set-immediate-shim "^1.0.1" redent@^1.0.0: version "1.0.0" @@ -1743,9 +2060,9 @@ redent@^1.0.0: strip-indent "^1.0.1" regenerator-runtime@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz#7e54fe5b5ccd5d6624ea6255c3473be090b802e1" - integrity sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A== + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" + integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== regex-cache@^0.4.2: version "0.4.4" @@ -1754,17 +2071,25 @@ regex-cache@^0.4.2: dependencies: is-equal-shallow "^0.1.3" +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + remove-trailing-separator@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= repeat-element@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" - integrity sha1-7wiaF40Ug7quTZPrmLT55OEdmQo= + version "1.1.3" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" + integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== -repeat-string@^1.5.2: +repeat-string@^1.5.2, repeat-string@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= @@ -1776,34 +2101,6 @@ repeating@^2.0.0: dependencies: is-finite "^1.0.0" -request@2.81.0: - version "2.81.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" - integrity sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA= - dependencies: - aws-sign2 "~0.6.0" - aws4 "^1.2.1" - caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.0" - forever-agent "~0.6.1" - form-data "~2.1.1" - har-validator "~4.2.1" - hawk "~3.1.3" - http-signature "~1.1.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.7" - oauth-sign "~0.8.1" - performance-now "^0.2.0" - qs "~6.4.0" - safe-buffer "^5.0.1" - stringstream "~0.0.4" - tough-cookie "~2.3.0" - tunnel-agent "^0.6.0" - uuid "^3.0.0" - request@^2.45.0: version "2.83.0" resolved "https://registry.yarnpkg.com/request/-/request-2.83.0.tgz#ca0b65da02ed62935887808e6f510381034e3356" @@ -1832,14 +2129,24 @@ request@^2.45.0: tunnel-agent "^0.6.0" uuid "^3.1.0" +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= + resolve@^1.1.7: - version "1.7.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.7.0.tgz#2bdf5374811207285df0df652b78f118ab8f3c5e" - integrity sha512-QdgZ5bjR1WAlpLaO5yHepFvC+o3rCr6wpfE2tpJNMkXdulf2jKomQBdNRQITF3ZKHNlT71syG98yQP03gasgnA== + version "1.11.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.1.tgz#ea10d8110376982fef578df8fc30b9ac30a07a3e" + integrity sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw== dependencies: - path-parse "^1.0.5" + path-parse "^1.0.6" -rimraf@2, rimraf@^2.5.1, rimraf@^2.6.1: +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + +rimraf@^2.6.1: version "2.6.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" integrity sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w== @@ -1856,11 +2163,38 @@ safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" integrity sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg== -"semver@2 || 3 || 4 || 5", semver@^5.3.0: +safe-buffer@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sax@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + +"semver@2 || 3 || 4 || 5": version "5.4.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" integrity sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg== +semver@^5.3.0: + version "5.7.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" + integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== + semver@^5.4.1: version "5.6.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" @@ -1871,10 +2205,15 @@ set-blocking@~2.0.0: resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= -set-immediate-shim@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" - integrity sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E= +set-value@^2.0.0, set-value@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" shell-quote@^1.6.1: version "1.6.1" @@ -1898,12 +2237,35 @@ single-line-log@^1.1.2: dependencies: string-width "^1.0.1" -sntp@1.x.x: - version "1.0.9" - resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" - integrity sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg= +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== dependencies: - hoek "2.x.x" + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" sntp@2.x.x: version "2.1.0" @@ -1912,6 +2274,27 @@ sntp@2.x.x: dependencies: hoek "4.x.x" +source-map-resolve@^0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" + integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== + dependencies: + atob "^2.1.1" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= + +source-map@^0.5.6: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + spawn-command@^0.0.2-1: version "0.0.2-1" resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2-1.tgz#62f5e9466981c1b796dc5929937e11c9c6921bd0" @@ -1939,6 +2322,13 @@ speedometer@~0.1.2: resolved "https://registry.yarnpkg.com/speedometer/-/speedometer-0.1.4.tgz#9876dbd2a169d3115402d48e6ea6329c8816a50d" integrity sha1-mHbb0qFp0xFUAtSObqYynIgWpQ0= +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + sshpk@^1.7.0: version "1.13.1" resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3" @@ -1954,7 +2344,15 @@ sshpk@^1.7.0: jsbn "~0.1.0" tweetnacl "~0.14.0" -string-width@^1.0.1, string-width@^1.0.2: +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +string-width@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= @@ -1963,6 +2361,14 @@ string-width@^1.0.1, string-width@^1.0.2: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" +"string-width@^1.0.2 || 2": + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + string_decoder@~0.10.x: version "0.10.31" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" @@ -1982,7 +2388,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -stringstream@~0.0.4, stringstream@~0.0.5: +stringstream@~0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" integrity sha1-TkhM1N5aC7vuGORjB3EKioFiGHg= @@ -2060,28 +2466,18 @@ supports-color@^3.2.3: dependencies: has-flag "^1.0.0" -tar-pack@^3.4.0: - version "3.4.1" - resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.1.tgz#e1dbc03a9b9d3ba07e896ad027317eb679a10a1f" - integrity sha512-PPRybI9+jM5tjtCbN2cxmmRU7YmqT3Zv/UDy48tAh2XRkLa9bAORtSWLkVc13+GJF+cdTh1yEnHEk3cpTaL5Kg== - dependencies: - debug "^2.2.0" - fstream "^1.0.10" - fstream-ignore "^1.0.5" - once "^1.3.3" - readable-stream "^2.1.4" - rimraf "^2.5.1" - tar "^2.2.1" - uid-number "^0.0.6" - -tar@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" - integrity sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE= +tar@^4: + version "4.4.10" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.10.tgz#946b2810b9a5e0b26140cf78bea6b0b0d689eba1" + integrity sha512-g2SVs5QIxvo6OLp0GudTqEf05maawKUxXru104iaayWA09551tFCTI8f1Asb4lPfkBr91k07iL4c11XO3/b0tA== dependencies: - block-stream "*" - fstream "^1.0.2" - inherits "2" + chownr "^1.1.1" + fs-minipass "^1.2.5" + minipass "^2.3.5" + minizlib "^1.2.1" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.3" throttleit@0.0.2: version "0.0.2" @@ -2103,12 +2499,30 @@ tmp@0.0.33: dependencies: os-tmpdir "~1.0.2" -tough-cookie@~2.3.0: - version "2.3.4" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655" - integrity sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA== +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= dependencies: - punycode "^1.4.1" + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" tough-cookie@~2.3.3: version "2.3.3" @@ -2149,26 +2563,44 @@ typescript@2.9.2: resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.9.2.tgz#1cbf61d05d6b96269244eb6a3bce4bd914e0f00c" integrity sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w== -uid-number@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" - integrity sha1-DqEOgDXo61uOREnwbaHHMGY7qoE= +union-value@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^2.0.1" universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== + util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= -uuid@^3.0.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" - integrity sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA== - uuid@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" @@ -2191,6 +2623,11 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" +vscode-uri@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.0.3.tgz#25e5f37f552fbee3cec7e5f80cef8469cefc6543" + integrity sha512-4D3DI3F4uRy09WNtDGD93H9q034OHImxiIcSq664Hq1Y1AScehlP3qqZyTkX/RWxeu0MRMHGkrxYqm2qlDF/aw== + watch@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/watch/-/watch-1.0.2.tgz#340a717bde765726fa0aa07d721e0147a551df0c" @@ -2200,11 +2637,11 @@ watch@^1.0.2: minimist "^1.2.0" wide-align@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" - integrity sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w== + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== dependencies: - string-width "^1.0.2" + string-width "^1.0.2 || 2" wrappy@1: version "1.0.2" @@ -2223,6 +2660,11 @@ xtend@~2.1.1: dependencies: object-keys "~0.4.0" +yallist@^3.0.0, yallist@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" + integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A== + yauzl@2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" diff --git a/test/splitview/package.json b/test/splitview/package.json new file mode 100644 index 000000000..d6ce0c373 --- /dev/null +++ b/test/splitview/package.json @@ -0,0 +1,13 @@ +{ + "name": "splitview", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "devDependencies": { + "koa": "^2.5.1", + "koa-mount": "^3.0.0", + "koa-route": "^3.2.0", + "koa-static": "^5.0.0", + "mz": "^2.7.0" + } +} \ No newline at end of file diff --git a/test/splitview/public/index.html b/test/splitview/public/index.html new file mode 100644 index 000000000..602682d6a --- /dev/null +++ b/test/splitview/public/index.html @@ -0,0 +1,138 @@ +<html> + +<head> + <meta charset="utf-8"> + <title>Splitview + + + + +
    +
    + + + + + + \ No newline at end of file diff --git a/test/splitview/server.js b/test/splitview/server.js new file mode 100644 index 000000000..67f253636 --- /dev/null +++ b/test/splitview/server.js @@ -0,0 +1,19 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +const fs = require('mz/fs'); +const path = require('path'); +const Koa = require('koa'); +const _ = require('koa-route'); +const serve = require('koa-static'); +const mount = require('koa-mount'); + +const app = new Koa(); + +app.use(serve('public')); +app.use(mount('/static', serve('../../out'))); + +app.listen(3000); +console.log('http://localhost:3000'); \ No newline at end of file diff --git a/test/splitview/yarn.lock b/test/splitview/yarn.lock new file mode 100644 index 000000000..237201a68 --- /dev/null +++ b/test/splitview/yarn.lock @@ -0,0 +1,341 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +accepts@^1.2.2: + version "1.3.5" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.5.tgz#eb777df6011723a3b14e8a72c0805c8e86746bd2" + integrity sha1-63d99gEXI6OxTopywIBcjoZ0a9I= + dependencies: + mime-types "~2.1.18" + negotiator "0.6.1" + +any-promise@^1.0.0, any-promise@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= + +content-disposition@~0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ= + +content-type@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +cookies@~0.7.0: + version "0.7.1" + resolved "https://registry.yarnpkg.com/cookies/-/cookies-0.7.1.tgz#7c8a615f5481c61ab9f16c833731bcb8f663b99b" + integrity sha1-fIphX1SBxhq58WyDNzG8uPZjuZs= + dependencies: + depd "~1.1.1" + keygrip "~1.0.2" + +debug@*, debug@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + +debug@^2.6.1: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +deep-equal@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" + integrity sha1-9dJgKStmDghO/0zbyfCK0yR0SLU= + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= + +depd@^1.1.0, depd@~1.1.1, depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +destroy@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +error-inject@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/error-inject/-/error-inject-1.0.0.tgz#e2b3d91b54aed672f309d950d154850fa11d4f37" + integrity sha1-4rPZG1Su1nLzCdlQ0VSFD6EdTzc= + +escape-html@~1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +fresh@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +http-assert@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/http-assert/-/http-assert-1.3.0.tgz#a31a5cf88c873ecbb5796907d4d6f132e8c01e4a" + integrity sha1-oxpc+IyHPsu1eWkH1NbxMujAHko= + dependencies: + deep-equal "~1.0.1" + http-errors "~1.6.1" + +http-errors@^1.2.8, http-errors@^1.6.3, http-errors@~1.6.1, http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +is-generator-function@^1.0.3: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.7.tgz#d2132e529bb0000a7f80794d4bdf5cd5e5813522" + integrity sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw== + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= + +keygrip@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.0.2.tgz#ad3297c557069dea8bcfe7a4fa491b75c5ddeb91" + integrity sha1-rTKXxVcGneqLz+ek+kkbdcXd65E= + +koa-compose@^3.0.0, koa-compose@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-3.2.1.tgz#a85ccb40b7d986d8e5a345b3a1ace8eabcf54de7" + integrity sha1-qFzLQLfZhtjlo0Wzoazo6rz1Tec= + dependencies: + any-promise "^1.1.0" + +koa-compose@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-4.1.0.tgz#507306b9371901db41121c812e923d0d67d3e877" + integrity sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw== + +koa-convert@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/koa-convert/-/koa-convert-1.2.0.tgz#da40875df49de0539098d1700b50820cebcd21d0" + integrity sha1-2kCHXfSd4FOQmNFwC1CCDOvNIdA= + dependencies: + co "^4.6.0" + koa-compose "^3.0.0" + +koa-is-json@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/koa-is-json/-/koa-is-json-1.0.0.tgz#273c07edcdcb8df6a2c1ab7d59ee76491451ec14" + integrity sha1-JzwH7c3Ljfaiwat9We52SRRR7BQ= + +koa-mount@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/koa-mount/-/koa-mount-3.0.0.tgz#08cab3b83d31442ed8b7e75c54b1abeb922ec197" + integrity sha1-CMqzuD0xRC7Yt+dcVLGr65IuwZc= + dependencies: + debug "^2.6.1" + koa-compose "^3.2.1" + +koa-route@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/koa-route/-/koa-route-3.2.0.tgz#76298b99a6bcfa9e38cab6fe5c79a8733e758bce" + integrity sha1-dimLmaa8+p44yrb+XHmocz51i84= + dependencies: + debug "*" + methods "~1.1.0" + path-to-regexp "^1.2.0" + +koa-send@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/koa-send/-/koa-send-5.0.0.tgz#5e8441e07ef55737734d7ced25b842e50646e7eb" + integrity sha512-90ZotV7t0p3uN9sRwW2D484rAaKIsD8tAVtypw/aBU+ryfV+fR2xrcAwhI8Wl6WRkojLUs/cB9SBSCuIb+IanQ== + dependencies: + debug "^3.1.0" + http-errors "^1.6.3" + mz "^2.7.0" + resolve-path "^1.4.0" + +koa-static@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/koa-static/-/koa-static-5.0.0.tgz#5e92fc96b537ad5219f425319c95b64772776943" + integrity sha512-UqyYyH5YEXaJrf9S8E23GoJFQZXkBVJ9zYYMPGz919MSX1KuvAcycIuS0ci150HCoPf4XQVhQ84Qf8xRPWxFaQ== + dependencies: + debug "^3.1.0" + koa-send "^5.0.0" + +koa@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/koa/-/koa-2.5.1.tgz#79f8b95f8d72d04fe9a58a8da5ebd6d341103f9c" + integrity sha512-cchwbMeG2dv3E2xTAmheDAuvR53tPgJZN/Hf1h7bTzJLSPcFZp8/t5+bNKJ6GaQZoydhZQ+1GNruhKdj3lIrug== + dependencies: + accepts "^1.2.2" + content-disposition "~0.5.0" + content-type "^1.0.0" + cookies "~0.7.0" + debug "*" + delegates "^1.0.0" + depd "^1.1.0" + destroy "^1.0.3" + error-inject "~1.0.0" + escape-html "~1.0.1" + fresh "^0.5.2" + http-assert "^1.1.0" + http-errors "^1.2.8" + is-generator-function "^1.0.3" + koa-compose "^4.0.0" + koa-convert "^1.2.0" + koa-is-json "^1.0.0" + mime-types "^2.0.7" + on-finished "^2.1.0" + only "0.0.2" + parseurl "^1.3.0" + statuses "^1.2.0" + type-is "^1.5.5" + vary "^1.0.0" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + +methods@~1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + +mime-db@~1.33.0: + version "1.33.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" + integrity sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ== + +mime-types@^2.0.7, mime-types@~2.1.18: + version "2.1.18" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" + integrity sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ== + dependencies: + mime-db "~1.33.0" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +mz@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + +negotiator@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + integrity sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk= + +object-assign@^4.0.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +on-finished@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +only@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/only/-/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4" + integrity sha1-Kv3oTQPlC5qO3EROMGEKcCle37Q= + +parseurl@^1.3.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.2.tgz#fc289d4ed8993119460c156253262cdc8de65bf3" + integrity sha1-/CidTtiZMRlGDBViUyYs3I3mW/M= + +path-is-absolute@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-to-regexp@^1.2.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d" + integrity sha1-Wf3g9DW62suhA6hOnTvGTpa5k30= + dependencies: + isarray "0.0.1" + +resolve-path@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/resolve-path/-/resolve-path-1.4.0.tgz#c4bda9f5efb2fce65247873ab36bb4d834fe16f7" + integrity sha1-xL2p9e+y/OZSR4c6s2u02DT+Fvc= + dependencies: + http-errors "~1.6.2" + path-is-absolute "1.0.1" + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== + +"statuses@>= 1.4.0 < 2", statuses@^1.2.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +thenify-all@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + integrity sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY= + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.3.0" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.0.tgz#e69e38a1babe969b0108207978b9f62b88604839" + integrity sha1-5p44obq+lpsBCCB5eLn2K4hgSDk= + dependencies: + any-promise "^1.0.0" + +type-is@^1.5.5: + version "1.6.16" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.16.tgz#f89ce341541c672b25ee7ae3c73dee3b2be50194" + integrity sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.18" + +vary@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= diff --git a/test/tree/public/compressed.json b/test/tree/public/compressed.json new file mode 100644 index 000000000..c0b5d4d71 --- /dev/null +++ b/test/tree/public/compressed.json @@ -0,0 +1,15620 @@ +[ + { + "element": { + "name": "eclipse.platform.debug" + }, + "children": [ + { + "element": { + "name": ".git" + }, + "children": [ + { + "element": { + "name": "HEAD" + }, + "incompressible": true + }, + { + "element": { + "name": "branches" + }, + "children": [] + }, + { + "element": { + "name": "config" + }, + "incompressible": true + }, + { + "element": { + "name": "description" + }, + "incompressible": true + }, + { + "element": { + "name": "hooks" + }, + "children": [ + { + "element": { + "name": "applypatch-msg.sample" + }, + "incompressible": true + }, + { + "element": { + "name": "commit-msg.sample" + }, + "incompressible": true + }, + { + "element": { + "name": "fsmonitor-watchman.sample" + }, + "incompressible": true + }, + { + "element": { + "name": "post-update.sample" + }, + "incompressible": true + }, + { + "element": { + "name": "pre-applypatch.sample" + }, + "incompressible": true + }, + { + "element": { + "name": "pre-commit.sample" + }, + "incompressible": true + }, + { + "element": { + "name": "pre-push.sample" + }, + "incompressible": true + }, + { + "element": { + "name": "pre-rebase.sample" + }, + "incompressible": true + }, + { + "element": { + "name": "pre-receive.sample" + }, + "incompressible": true + }, + { + "element": { + "name": "prepare-commit-msg.sample" + }, + "incompressible": true + }, + { + "element": { + "name": "update.sample" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "index" + }, + "incompressible": true + }, + { + "element": { + "name": "info" + }, + "children": [ + { + "element": { + "name": "exclude" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "logs" + }, + "children": [ + { + "element": { + "name": "HEAD" + }, + "incompressible": true + }, + { + "element": { + "name": "refs" + }, + "children": [ + { + "element": { + "name": "heads" + }, + "children": [ + { + "element": { + "name": "master" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "remotes" + }, + "children": [ + { + "element": { + "name": "origin" + }, + "children": [ + { + "element": { + "name": "HEAD" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "objects" + }, + "children": [ + { + "element": { + "name": "info" + }, + "children": [] + }, + { + "element": { + "name": "pack" + }, + "children": [ + { + "element": { + "name": "pack-2b1503bd0b85396d8596e9e99d956bfc3fbe497b.idx" + }, + "incompressible": true + }, + { + "element": { + "name": "pack-2b1503bd0b85396d8596e9e99d956bfc3fbe497b.pack" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "packed-refs" + }, + "incompressible": true + }, + { + "element": { + "name": "refs" + }, + "children": [ + { + "element": { + "name": "heads" + }, + "children": [ + { + "element": { + "name": "master" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "remotes" + }, + "children": [ + { + "element": { + "name": "origin" + }, + "children": [ + { + "element": { + "name": "HEAD" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "tags" + }, + "children": [ + { + "element": { + "name": "I20190722-1800" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "shallow" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": ".gitignore" + }, + "incompressible": true + }, + { + "element": { + "name": "CONTRIBUTING" + }, + "incompressible": true + }, + { + "element": { + "name": "LICENSE" + }, + "incompressible": true + }, + { + "element": { + "name": "NOTICE" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.externaltools" + }, + "children": [ + { + "element": { + "name": ".classpath" + }, + "incompressible": true + }, + { + "element": { + "name": ".project" + }, + "incompressible": true + }, + { + "element": { + "name": ".settings" + }, + "children": [ + { + "element": { + "name": "org.eclipse.core.resources.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.runtime.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.core.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.ui.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.api.tools.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.prefs" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "META-INF" + }, + "children": [ + { + "element": { + "name": "MANIFEST.MF" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "about.html" + }, + "incompressible": true + }, + { + "element": { + "name": "build.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "plugin.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "plugin.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "src" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "core" + }, + "children": [ + { + "element": { + "name": "externaltools" + }, + "children": [ + { + "element": { + "name": "internal" + }, + "children": [ + { + "element": { + "name": "ExternalToolsCore.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IExternalToolConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "launchConfigurations" + }, + "children": [ + { + "element": { + "name": "BackgroundResourceRefresher.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsCoreUtil.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsProgramMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsProgramMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "ProgramLaunchDelegate.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "model" + }, + "children": [ + { + "element": { + "name": "BuilderCoreUtils.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolBuilder.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsModelMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsModelMessages.properties" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "registry" + }, + "children": [ + { + "element": { + "name": "ExternalToolMigration.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsMigrationMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsMigrationMessages.properties" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "org.eclipse.core.variables" + }, + "children": [ + { + "element": { + "name": ".classpath" + }, + "incompressible": true + }, + { + "element": { + "name": ".project" + }, + "incompressible": true + }, + { + "element": { + "name": ".settings" + }, + "children": [ + { + "element": { + "name": "org.eclipse.core.resources.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.runtime.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.core.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.ui.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.api.tools.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.prefs" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "META-INF" + }, + "children": [ + { + "element": { + "name": "MANIFEST.MF" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "about.html" + }, + "incompressible": true + }, + { + "element": { + "name": "build.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "plugin.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "plugin.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "schema" + }, + "children": [ + { + "element": { + "name": "dynamicVariables.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "valueVariables.exsd" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "src" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "core" + }, + "children": [ + { + "element": { + "name": "internal" + }, + "children": [ + { + "element": { + "name": "variables" + }, + "children": [ + { + "element": { + "name": "ContributedValueVariable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DynamicVariable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EclipseHomeVariableResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StringSubstitutionEngine.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StringVariable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StringVariableManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ValueVariable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariablesMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariablesMessages.properties" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "variables" + }, + "children": [ + { + "element": { + "name": "IDynamicVariable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDynamicVariableResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStringVariable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStringVariableManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IValueVariable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IValueVariableInitializer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IValueVariableListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariablesPlugin.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "org.eclipse.debug.core" + }, + "children": [ + { + "element": { + "name": ".classpath" + }, + "incompressible": true + }, + { + "element": { + "name": ".options" + }, + "incompressible": true + }, + { + "element": { + "name": ".project" + }, + "incompressible": true + }, + { + "element": { + "name": ".settings" + }, + "children": [ + { + "element": { + "name": "org.eclipse.core.resources.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.runtime.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.core.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.ui.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.api.tools.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.prefs" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "META-INF" + }, + "children": [ + { + "element": { + "name": "MANIFEST.MF" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "about.html" + }, + "incompressible": true + }, + { + "element": { + "name": "build.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "core" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "debug" + }, + "children": [ + { + "element": { + "name": "core" + }, + "children": [ + { + "element": { + "name": "DebugEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugException.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugPlugin.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreakpointListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreakpointManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreakpointManagerListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreakpointsListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugEventFilter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugEventSetListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IExpressionListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IExpressionManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IExpressionsListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunch.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchConfiguration.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchConfigurationListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchConfigurationMigrationDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchConfigurationType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchConfigurationWorkingCopy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchMode.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchesListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchesListener2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILogicalStructureProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILogicalStructureType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryBlockListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryBlockManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IProcessFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IPrototypeAttributesLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IRequest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStatusHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStreamListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Launch.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RefreshUtil.java" + }, + "incompressible": true + }, + { + "element": { + "name": "commands" + }, + "children": [ + { + "element": { + "name": "AbstractDebugCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugCommandRequest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDisconnectHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDropToFrameHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IEnabledStateRequest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IRestartHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IResumeHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStepFiltersHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStepIntoHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStepOverHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStepReturnHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISuspendHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ITerminateHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "model" + }, + "children": [ + { + "element": { + "name": "Breakpoint.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugElement.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreakpoint.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreakpointImportParticipant.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugElement.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugModelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugTarget.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDisconnect.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDropToFrame.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IErrorReportingExpression.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IExpression.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IFilteredStep.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IFlushableStreamMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IIndexedValue.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchConfigurationDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchConfigurationDelegate2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILineBreakpoint.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILogicalStructureTypeDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILogicalStructureTypeDelegate2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryBlock.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryBlockExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryBlockRetrieval.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryBlockRetrievalExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IPersistableSourceLocator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IProcess.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IRegister.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IRegisterGroup.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourceLocator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStackFrame.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStep.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStepFilter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStepFilters.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStreamMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStreamsProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStreamsProxy2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISuspendResume.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ITerminate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IThread.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ITriggerPoint.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IValue.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IValueModification.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IVariable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IWatchExpression.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IWatchExpressionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IWatchExpressionListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IWatchExpressionResult.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IWatchpoint.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LineBreakpoint.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryByte.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RuntimeProcess.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + }, + { + "element": { + "name": "sourcelookup" + }, + "children": [ + { + "element": { + "name": "AbstractSourceLookupDirector.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractSourceLookupParticipant.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IPersistableSourceLocator2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourceContainerType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourceContainerTypeDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourceLookupDirector.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourceLookupParticipant.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourcePathComputer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourcePathComputerDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "containers" + }, + "children": [ + { + "element": { + "name": "AbstractSourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractSourceContainerTypeDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ArchiveSourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CompositeSourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ContainerSourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultSourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DirectorySourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalArchiveSourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FolderSourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LocalFileStorage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProjectSourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkspaceSourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ZipEntryStorage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "internal" + }, + "children": [ + { + "element": { + "name": "core" + }, + "children": [ + { + "element": { + "name": "BreakpointImportParticipantDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugCoreMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugCoreMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugOptions.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugPreferenceInitializer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EnvironmentVariableResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExpressionManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConfigurationElementConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IExpressionsListener2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IInternalDebugCoreConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMementoConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "InputStreamMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfiguration.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationComparator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationInfo.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationWorkingCopy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchMode.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchablePropertyTester.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LogicalStructureManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LogicalStructureProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LogicalStructureType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlockManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "NullStreamsProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "OutputStreamMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Preferences.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PreferredDelegateModifyListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RefreshScopeComparator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResourceFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepFilter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepFilterManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StreamsProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SystemPropertyResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SystemVariableResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WatchExpression.java" + }, + "incompressible": true + }, + { + "element": { + "name": "XMLMemento.java" + }, + "incompressible": true + }, + { + "element": { + "name": "commands" + }, + "children": [ + { + "element": { + "name": "CommandAdapterFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugCommandRequest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DisconnectCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DropToFrameCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ForEachCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Request.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResumeCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepFiltersCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepIntoCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepOverCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepReturnCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SuspendCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TerminateCommand.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "groups" + }, + "children": [ + { + "element": { + "name": "GroupLaunch.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GroupLaunchConfigurationDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GroupLaunchElement.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GroupMemberChangeListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "observer" + }, + "children": [ + { + "element": { + "name": "ProcessObserver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StreamObserver.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "sourcelookup" + }, + "children": [ + { + "element": { + "name": "SourceContainerType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLocatorMementoComparator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupUtils.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourcePathComputer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "containers" + }, + "children": [ + { + "element": { + "name": "ArchiveSourceContainerType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultSourceContainerType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DirectorySourceContainerType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalArchiveSourceContainerType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FolderSourceContainerType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProjectSourceContainerType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkspaceSourceContainerType.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "variables" + }, + "children": [ + { + "element": { + "name": "ContainerResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DateTimeResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Messages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Messages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "ProjectResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResourceResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkspaceResolver.java" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "plugin.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "plugin.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "schema" + }, + "children": [ + { + "element": { + "name": "breakpointImportParticipants.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "breakpoints.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "launchConfigurationComparators.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "launchConfigurationTypes.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "launchDelegates.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "launchModes.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "launchers.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "logicalStructureProviders.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "logicalStructureTypes.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "processFactories.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "sourceContainerTypes.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "sourceLocators.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "sourcePathComputers.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "statusHandlers.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "stepFilters.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "watchExpressionDelegates.exsd" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "scripts" + }, + "children": [ + { + "element": { + "name": "exportplugin.xml" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "org.eclipse.debug.examples.core" + }, + "children": [ + { + "element": { + "name": ".classpath" + }, + "incompressible": true + }, + { + "element": { + "name": ".project" + }, + "incompressible": true + }, + { + "element": { + "name": ".settings" + }, + "children": [ + { + "element": { + "name": "org.eclipse.core.resources.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.runtime.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.core.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.ui.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.api.tools.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.prefs" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "META-INF" + }, + "children": [ + { + "element": { + "name": "MANIFEST.MF" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "OSGI-INF" + }, + "children": [ + { + "element": { + "name": "l10n" + }, + "children": [ + { + "element": { + "name": "bundle.properties" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "about.html" + }, + "incompressible": true + }, + { + "element": { + "name": "build.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "forceQualifierUpdate.txt" + }, + "incompressible": true + }, + { + "element": { + "name": "pdavm" + }, + "children": [ + { + "element": { + "name": "src" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "debug" + }, + "children": [ + { + "element": { + "name": "examples" + }, + "children": [ + { + "element": { + "name": "pdavm" + }, + "children": [ + { + "element": { + "name": "PDAVirtualMachine.java" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "tests" + }, + "children": [ + { + "element": { + "name": "vmtest10.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "vmtest2.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "vmtest3.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "vmtest6.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "vmtest8.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "vmtest9.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "vmtest_children.pda" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "plugin.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "readme.html" + }, + "incompressible": true + }, + { + "element": { + "name": "samples" + }, + "children": [ + { + "element": { + "name": "counter.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "drop.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "example.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "fibonacci.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "registers.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "stack.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "structures.pda" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "scripts" + }, + "children": [ + { + "element": { + "name": "build.xml" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "src" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "debug" + }, + "children": [ + { + "element": { + "name": "examples" + }, + "children": [ + { + "element": { + "name": "core" + }, + "children": [ + { + "element": { + "name": "midi" + }, + "children": [ + { + "element": { + "name": "launcher" + }, + "children": [ + { + "element": { + "name": "ClockControl.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LengthControl.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MidiLaunch.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MidiLaunchDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SequencerControl.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TempoControl.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TimeControl.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "pda" + }, + "children": [ + { + "element": { + "name": "DebugCorePlugin.java" + }, + "incompressible": true + }, + { + "element": { + "name": "breakpoints" + }, + "children": [ + { + "element": { + "name": "PDALineBreakpoint.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDARunToLineBreakpoint.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAWatchpoint.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "launcher" + }, + "children": [ + { + "element": { + "name": "PDALaunchDelegate.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "model" + }, + "children": [ + { + "element": { + "name": "IPDAEventListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAArray.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAArrayEntry.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDADebugElement.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDADebugTarget.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAMemoryBlock.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAStackFrame.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAStackValue.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAThread.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAValue.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAVariable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WordStructureDelegate.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "protocol" + }, + "children": [ + { + "element": { + "name": "PDABitFieldData.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAChildrenCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAClearBreakpointCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDACommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDACommandResult.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDADataCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDADropFrameCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAEvalCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAEvalResultEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAEventStopCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAExitedEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAFrameCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAFrameCommandResult.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAFrameData.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAGroupsCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAListResult.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDANoSuchLabelEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAPopDataCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAPushDataCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDARegisterData.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDARegistersCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDARegistersCommandResult.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDARegistersEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDARestartCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAResumeCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAResumedEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDARunControlEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDASetBreakpointCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDASetDataCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDASetVarCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAStackCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAStackCommandResult.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAStackDepthCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAStackDepthCommandResult.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAStartedEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAStepCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAStepReturnCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDASuspendCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDASuspendedEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDATerminateCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDATerminatedEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAUnimplementedInstructionEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAVMResumeCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAVMResumedEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAVMStartedEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAVMSuspendCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAVMSuspendedEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAVMTerminatedEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAVarCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAWatchCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "sourcelookup" + }, + "children": [ + { + "element": { + "name": "PDASourceLookupDirector.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDASourceLookupParticipant.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDASourcePathComputerDelegate.java" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "src_ant" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "debug" + }, + "children": [ + { + "element": { + "name": "examples" + }, + "children": [ + { + "element": { + "name": "ant" + }, + "children": [ + { + "element": { + "name": "tasks" + }, + "children": [ + { + "element": { + "name": "PreProcessor.java" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "org.eclipse.debug.examples.memory" + }, + "children": [ + { + "element": { + "name": ".classpath" + }, + "incompressible": true + }, + { + "element": { + "name": ".project" + }, + "incompressible": true + }, + { + "element": { + "name": ".settings" + }, + "children": [ + { + "element": { + "name": "org.eclipse.core.resources.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.runtime.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.core.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.ui.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.api.tools.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.prefs" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "META-INF" + }, + "children": [ + { + "element": { + "name": "MANIFEST.MF" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "build.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "icons" + }, + "children": [ + { + "element": { + "name": "full" + }, + "children": [ + { + "element": { + "name": "obj16" + }, + "children": [ + { + "element": { + "name": "hex_tree.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "launch.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "memory_segment.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "memory_unit.gif" + }, + "incompressible": true + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "plugin.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "plugin.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "src" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "debug" + }, + "children": [ + { + "element": { + "name": "examples" + }, + "children": [ + { + "element": { + "name": "internal" + }, + "children": [ + { + "element": { + "name": "memory" + }, + "children": [ + { + "element": { + "name": "MemoryViewSamplePlugin.java" + }, + "incompressible": true + }, + { + "element": { + "name": "core" + }, + "children": [ + { + "element": { + "name": "Messages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SampleDebugTarget.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SampleMemoryBlock.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SampleRegister.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SampleRegisterGroup.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SampleStackFrame.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SampleThread.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SampleValue.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SampleVariable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "messages.properties" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "engine" + }, + "children": [ + { + "element": { + "name": "SampleEngine.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SampleMemoryUnit.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "launchconfig" + }, + "children": [ + { + "element": { + "name": "SampleLaunchConfigurationDelegateEx.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SampleLaunchTabGroup.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SampleModelPresentation.java" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "org.eclipse.debug.examples.mixedmode" + }, + "children": [ + { + "element": { + "name": ".classpath" + }, + "incompressible": true + }, + { + "element": { + "name": ".project" + }, + "incompressible": true + }, + { + "element": { + "name": ".settings" + }, + "children": [ + { + "element": { + "name": "org.eclipse.core.resources.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.runtime.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.core.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.ui.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.api.tools.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.prefs" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "META-INF" + }, + "children": [ + { + "element": { + "name": "MANIFEST.MF" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "OSGI-INF" + }, + "children": [ + { + "element": { + "name": "l10n" + }, + "children": [ + { + "element": { + "name": "bundle.properties" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "about.html" + }, + "incompressible": true + }, + { + "element": { + "name": "build.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "plugin.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "src" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "debug" + }, + "children": [ + { + "element": { + "name": "internal" + }, + "children": [ + { + "element": { + "name": "examples" + }, + "children": [ + { + "element": { + "name": "mixedmode" + }, + "children": [ + { + "element": { + "name": "Activator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AntExtraTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ClearPreferredDelegatesHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DoNothingLaunchConfigurationDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DoNothingMainTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Messages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "messages.properties" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "org.eclipse.debug.examples.ui" + }, + "children": [ + { + "element": { + "name": ".classpath" + }, + "incompressible": true + }, + { + "element": { + "name": ".project" + }, + "incompressible": true + }, + { + "element": { + "name": ".settings" + }, + "children": [ + { + "element": { + "name": "org.eclipse.core.resources.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.runtime.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.core.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.ui.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.api.tools.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.prefs" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "META-INF" + }, + "children": [ + { + "element": { + "name": "MANIFEST.MF" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "OSGI-INF" + }, + "children": [ + { + "element": { + "name": "l10n" + }, + "children": [ + { + "element": { + "name": "bundle.properties" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "about.html" + }, + "incompressible": true + }, + { + "element": { + "name": "build.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "icons" + }, + "children": [ + { + "element": { + "name": "full" + }, + "children": [ + { + "element": { + "name": "dlcl16" + }, + "children": [ + { + "element": { + "name": "pop.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "push.gif" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "elcl16" + }, + "children": [ + { + "element": { + "name": "pop.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "push.gif" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "obj16" + }, + "children": [ + { + "element": { + "name": "clef.png" + }, + "incompressible": true + }, + { + "element": { + "name": "note.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "pda.gif" + }, + "incompressible": true + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "plugin.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "src" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "debug" + }, + "children": [ + { + "element": { + "name": "examples" + }, + "children": [ + { + "element": { + "name": "ui" + }, + "children": [ + { + "element": { + "name": "midi" + }, + "children": [ + { + "element": { + "name": "adapters" + }, + "children": [ + { + "element": { + "name": "CheckboxModelProxyFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ControlCellModifier.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ControlEditor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ControlEventHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ControlLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ControlsMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MidiAdapterFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MidiEventLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MidiEventModelProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MidiStepOverHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SequencerColumnFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SequencerColumnPresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SequencerContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SequencerControlsModelProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SequencerModelProxyFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TrackColumnFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TrackColumnPresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TrackContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TrackLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TrackModelProxy.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "detailpanes" + }, + "children": [ + { + "element": { + "name": "ClockSliderDetailPane.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ControlDetailPaneFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TempoSliderDetailPane.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "launcher" + }, + "children": [ + { + "element": { + "name": "ExampleLaunchStatusHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MidiLaunchShortcut.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MidiMainTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MidiTabGroup.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "pda" + }, + "children": [ + { + "element": { + "name": "DebugUIPlugin.java" + }, + "incompressible": true + }, + { + "element": { + "name": "adapters" + }, + "children": [ + { + "element": { + "name": "AdapterFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AddPDAMemoryBlockAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CommandAdapterFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ModelProxyFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDADebugTargetContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDADebugTargetProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDARestartDebugCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAThreadEventHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAViewActionProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAVirtualFindAction.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "breakpoints" + }, + "children": [ + { + "element": { + "name": "PDABreakpointAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAEditorAdapterFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDARunToLineAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAToggleWatchpointsTarget.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAToggleWatchpointsTargetFactory.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "editor" + }, + "children": [ + { + "element": { + "name": "AnnotationHover.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAContentAssistProcessor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAContentAssistant.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAEditor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAEditorMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAScanner.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDASourceViewerConfiguration.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PopFrameActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TextHover.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WordFinder.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "launcher" + }, + "children": [ + { + "element": { + "name": "PDALaunchShortcut.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAMainTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDATabGroup.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "presentation" + }, + "children": [ + { + "element": { + "name": "PDAModelPresentation.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "views" + }, + "children": [ + { + "element": { + "name": "AbstractDataStackViewHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CanPushTester.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CheckboxView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DataStackView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PopHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PushHandler.java" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "org.eclipse.debug.tests" + }, + "children": [ + { + "element": { + "name": ".classpath" + }, + "incompressible": true + }, + { + "element": { + "name": ".project" + }, + "incompressible": true + }, + { + "element": { + "name": ".settings" + }, + "children": [ + { + "element": { + "name": "org.eclipse.core.resources.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.runtime.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.core.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.ui.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.prefs" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "META-INF" + }, + "children": [ + { + "element": { + "name": "MANIFEST.MF" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "Platform Debug Test Suite.launch" + }, + "incompressible": true + }, + { + "element": { + "name": "about.html" + }, + "incompressible": true + }, + { + "element": { + "name": "build.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "forceQualifierUpdate.txt" + }, + "incompressible": true + }, + { + "element": { + "name": "icons" + }, + "children": [ + { + "element": { + "name": "image1.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "image2.gif" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "plugin.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "plugin.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "src" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "debug" + }, + "children": [ + { + "element": { + "name": "tests" + }, + "children": [ + { + "element": { + "name": "AbstractDebugTest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AutomatedSuite.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LocalSuite.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PerformanceSuite.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TestUtil.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TestsPlugin.java" + }, + "incompressible": true + }, + { + "element": { + "name": "breakpoint" + }, + "children": [ + { + "element": { + "name": "BreakpointOrderingTests.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "console" + }, + "children": [ + { + "element": { + "name": "ConsoleDocumentAdapterTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleManagerTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IOConsoleTestUtil.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IOConsoleTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MockProcess.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProcessConsoleManagerTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProcessConsoleTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StreamsProxyTests.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "expressions" + }, + "children": [ + { + "element": { + "name": "ExpressionManagerTests.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "launching" + }, + "children": [ + { + "element": { + "name": "AbstractLaunchTest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AcceleratorSubstitutionTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ArgumentParsingTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ArgumentsPrinter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CancellingLaunchDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugFileStore.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugFileSystem.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchFavoriteTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchGroupTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchHistoryTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchManagerTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RefreshTabTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TestLaunchDelegate.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "sourcelookup" + }, + "children": [ + { + "element": { + "name": "SourceLookupFacilityTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TestLaunch.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TestSourceDirector.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TestSourceLocator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TestStackFrame.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "statushandlers" + }, + "children": [ + { + "element": { + "name": "StatusHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StatusHandlerTests.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "stepfilters" + }, + "children": [ + { + "element": { + "name": "StepFiltersTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TestStepFilter.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "view" + }, + "children": [ + { + "element": { + "name": "memory" + }, + "children": [ + { + "element": { + "name": "DynamicRenderingBindings.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlock.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlockDynamic.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlockOne.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlockThree.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlockTwo.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryRenderingTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RenderingTypeDelegate.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "viewer" + }, + "children": [ + { + "element": { + "name": "model" + }, + "children": [ + { + "element": { + "name": "AbstractViewerModelTest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CheckTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ChildrenUpdateTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ColumnPresentationTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ContentTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DeltaTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FilterTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FilterTransformTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ITestModelUpdatesListenerConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "JFaceViewerCheckTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "JFaceViewerContentTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "JFaceViewerDeltaTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "JFaceViewerFilterTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "JFaceViewerLazyTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "JFaceViewerPerformanceTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "JFaceViewerPopupTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "JFaceViewerSelectionTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "JFaceViewerStateTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "JFaceViewerTopIndexTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "JFaceViewerUpdateTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LazyTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PerformanceTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PopupTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PresentationContextTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectionTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StateTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TestModel.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TestModelUpdatesListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TreeModelViewerAutopopulateAgent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TreePathWrapper.java" + }, + "incompressible": true + }, + { + "element": { + "name": "UpdateTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualViewerContentTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualViewerDeltaTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualViewerFilterTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualViewerLazyModeTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualViewerPerformanceTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualViewerPopupTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualViewerSelectionTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualViewerStateTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualViewerUpdateTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VisibleVirtualItemValidator.java" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "test-import" + }, + "children": [ + { + "element": { + "name": "Import1.launch" + }, + "incompressible": true + }, + { + "element": { + "name": "Import2.launch" + }, + "incompressible": true + }, + { + "element": { + "name": "Import3.launch" + }, + "incompressible": true + }, + { + "element": { + "name": "Import4.launch" + }, + "incompressible": true + }, + { + "element": { + "name": "Import5.launch" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "test.xml" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "org.eclipse.debug.ui" + }, + "children": [ + { + "element": { + "name": ".classpath" + }, + "incompressible": true + }, + { + "element": { + "name": ".options" + }, + "incompressible": true + }, + { + "element": { + "name": ".project" + }, + "incompressible": true + }, + { + "element": { + "name": ".settings" + }, + "children": [ + { + "element": { + "name": ".api_filters" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.resources.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.runtime.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.core.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.ui.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.api.tools.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.prefs" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "META-INF" + }, + "children": [ + { + "element": { + "name": "MANIFEST.MF" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "about.html" + }, + "incompressible": true + }, + { + "element": { + "name": "build.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "css" + }, + "children": [ + { + "element": { + "name": "e4-dark_debug_prefstyle.css" + }, + "incompressible": true + }, + { + "element": { + "name": "e4-light_debug_prefstyle.css" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "forceQualifierUpdate.txt" + }, + "incompressible": true + }, + { + "element": { + "name": "icons" + }, + "children": [ + { + "element": { + "name": "full" + }, + "children": [ + { + "element": { + "name": "dlcl16" + }, + "children": [ + { + "element": { + "name": "changevariablevalue_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "changevariablevalue_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "clear_co.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "collapseall.png" + }, + "incompressible": true + }, + { + "element": { + "name": "collapseall@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "copy_edit_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "copy_edit_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "copyviewtoclipboard_tsk.png" + }, + "incompressible": true + }, + { + "element": { + "name": "copyviewtoclipboard_tsk@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_auto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_auto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_compact.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_compact@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_tree.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_tree@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debuglast_co.gif.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debuglast_co.gif@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debuglast_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debuglast_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "delete_config.png" + }, + "incompressible": true + }, + { + "element": { + "name": "delete_config@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_auto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_auto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_hide.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_hide@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_right.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_right@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_under.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_under@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "disabled_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "disabled_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "disconnect_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "disconnect_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "display_selected_mb.png" + }, + "incompressible": true + }, + { + "element": { + "name": "display_selected_mb@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "dissolve_group.png" + }, + "incompressible": true + }, + { + "element": { + "name": "dissolve_group@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "drop_to_frame.png" + }, + "incompressible": true + }, + { + "element": { + "name": "drop_to_frame@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "edtsrclkup_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "edtsrclkup_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "enabled_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "enabled_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "expandall.png" + }, + "incompressible": true + }, + { + "element": { + "name": "expandall@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_brkpts.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_brkpts@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_config.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_config@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "filter_ps.png" + }, + "incompressible": true + }, + { + "element": { + "name": "filter_ps@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "hierarchicalLayout.png" + }, + "incompressible": true + }, + { + "element": { + "name": "hierarchicalLayout@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "import_brkpts.png" + }, + "incompressible": true + }, + { + "element": { + "name": "import_brkpts@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "link_proto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "link_proto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lock_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lock_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memoryreset_tsk.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memoryreset_tsk@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "metharg_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "metharg_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "monitorexpression_tsk.png" + }, + "incompressible": true + }, + { + "element": { + "name": "monitorexpression_tsk@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_con.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_con@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_proto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_proto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "next_thread_nav.png" + }, + "incompressible": true + }, + { + "element": { + "name": "next_thread_nav@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "pin.png" + }, + "incompressible": true + }, + { + "element": { + "name": "pin@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prev_thread_nav.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prev_thread_nav@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "printview_tsk.png" + }, + "incompressible": true + }, + { + "element": { + "name": "printview_tsk@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prop_ps.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prop_ps@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_all_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_all_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_all_triggers.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "removememory_tsk.png" + }, + "incompressible": true + }, + { + "element": { + "name": "removememory_tsk@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "reset_proto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "reset_proto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "restart_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "restart_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "resume_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "resume_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "runlast_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "runlast_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "runtoline_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "runtoline_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "skip_brkp.png" + }, + "incompressible": true + }, + { + "element": { + "name": "skip_brkp@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepbystep_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepbystep_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepinto_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepinto_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepover_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepover_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepreturn_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepreturn_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "suspend_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "suspend_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "synced.png" + }, + "incompressible": true + }, + { + "element": { + "name": "synced@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_all_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_all_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_rem_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_rem_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "tnames_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "tnames_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "toggledetailpane_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "toggledetailpane_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "unlink_proto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "unlink_proto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "var_cntnt_prvdr.png" + }, + "incompressible": true + }, + { + "element": { + "name": "var_cntnt_prvdr@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "writeerr_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "writeerr_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "writeout_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "writeout_co@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "dtool16" + }, + "children": [ + { + "element": { + "name": "debug_exc.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_exc@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "environment_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "environment_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "profile_exc.png" + }, + "incompressible": true + }, + { + "element": { + "name": "profile_exc@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "run_exc.png" + }, + "incompressible": true + }, + { + "element": { + "name": "run_exc@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "term_restart.png" + }, + "incompressible": true + }, + { + "element": { + "name": "term_restart@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "watch_exp.png" + }, + "incompressible": true + }, + { + "element": { + "name": "watch_exp@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "dview16" + }, + "children": [ + { + "element": { + "name": "breakpoint_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "breakpoint_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_persp.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_persp@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "details_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "details_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memory_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memory_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "module_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "module_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "register_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "register_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "variable_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "variable_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "watchlist_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "watchlist_view@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "elcl16" + }, + "children": [ + { + "element": { + "name": "changevariablevalue_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "changevariablevalue_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "collapseall.png" + }, + "incompressible": true + }, + { + "element": { + "name": "collapseall@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "copy_edit_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "copy_edit_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "copyviewtoclipboard_tsk.png" + }, + "incompressible": true + }, + { + "element": { + "name": "copyviewtoclipboard_tsk@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_auto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_auto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_compact.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_compact@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_tree.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_tree@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debuglast_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debuglast_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "delete_config.png" + }, + "incompressible": true + }, + { + "element": { + "name": "delete_config@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_auto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_auto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_hide.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_hide@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_right.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_right@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_under.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_under@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "disabled_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "disabled_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "disconnect_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "disconnect_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "display_selected_mb.png" + }, + "incompressible": true + }, + { + "element": { + "name": "display_selected_mb@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "dissolve_group.png" + }, + "incompressible": true + }, + { + "element": { + "name": "dissolve_group@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "drop_to_frame.png" + }, + "incompressible": true + }, + { + "element": { + "name": "drop_to_frame@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "edtsrclkup_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "edtsrclkup_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "enabled_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "enabled_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "expandall.png" + }, + "incompressible": true + }, + { + "element": { + "name": "expandall@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_brkpts.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_brkpts@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_config.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_config@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "filter_ps.png" + }, + "incompressible": true + }, + { + "element": { + "name": "filter_ps@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "hierarchicalLayout.png" + }, + "incompressible": true + }, + { + "element": { + "name": "hierarchicalLayout@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "import_brkpts.png" + }, + "incompressible": true + }, + { + "element": { + "name": "import_brkpts@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "link_proto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "link_proto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lock_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lock_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memoryreset_tsk.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memoryreset_tsk@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "metharg_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "metharg_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "monitorexpression_tsk.png" + }, + "incompressible": true + }, + { + "element": { + "name": "monitorexpression_tsk@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_con.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_con@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_proto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_proto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "next_thread_nav.png" + }, + "incompressible": true + }, + { + "element": { + "name": "next_thread_nav@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "pin.png" + }, + "incompressible": true + }, + { + "element": { + "name": "pin@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prev_thread_nav.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prev_thread_nav@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "printview_tsk.png" + }, + "incompressible": true + }, + { + "element": { + "name": "printview_tsk@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prop_ps.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prop_ps@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_all_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_all_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_all_triggers.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "removememory_tsk.png" + }, + "incompressible": true + }, + { + "element": { + "name": "removememory_tsk@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "reset_proto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "reset_proto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "restart_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "restart_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "resume_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "resume_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "runlast_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "runlast_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "runtoline_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "runtoline_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "skip_brkp.png" + }, + "incompressible": true + }, + { + "element": { + "name": "skip_brkp@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepbystep_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepbystep_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepinto_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepinto_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepover_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepover_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepreturn_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepreturn_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "suspend_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "suspend_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "synced.png" + }, + "incompressible": true + }, + { + "element": { + "name": "synced@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_all_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_all_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_rem_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_rem_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "tnames_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "tnames_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "toggledetailpane_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "toggledetailpane_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "unlink_proto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "unlink_proto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "var_cntnt_prvdr.png" + }, + "incompressible": true + }, + { + "element": { + "name": "var_cntnt_prvdr@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "writeerr_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "writeerr_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "writeout_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "writeout_co@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "etool16" + }, + "children": [ + { + "element": { + "name": "debug_exc.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_exc@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "environment_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "environment_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "profile_exc.png" + }, + "incompressible": true + }, + { + "element": { + "name": "profile_exc@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "run_exc.png" + }, + "incompressible": true + }, + { + "element": { + "name": "run_exc@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "term_restart.png" + }, + "incompressible": true + }, + { + "element": { + "name": "term_restart@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "watch_exp.png" + }, + "incompressible": true + }, + { + "element": { + "name": "watch_exp@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "eview16" + }, + "children": [ + { + "element": { + "name": "breakpoint_view.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "breakpoint_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "breakpoint_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_persp.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_persp.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_persp@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "details_view.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "details_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "details_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memory_view.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "memory_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memory_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "module_view.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "module_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "module_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "register_view.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "register_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "register_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "variable_view.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "variable_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "variable_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "watchlist_view.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "watchlist_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "watchlist_view@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "obj16" + }, + "children": [ + { + "element": { + "name": "arraypartition_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "arraypartition_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "brkp_grp.png" + }, + "incompressible": true + }, + { + "element": { + "name": "brkp_grp@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "brkp_grp_disabled.png" + }, + "incompressible": true + }, + { + "element": { + "name": "brkp_grp_disabled@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "brkp_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "brkp_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "brkp_type.png" + }, + "incompressible": true + }, + { + "element": { + "name": "brkp_type@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "brkpd_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "brkpd_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "check.png" + }, + "incompressible": true + }, + { + "element": { + "name": "check@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "common_tab.png" + }, + "incompressible": true + }, + { + "element": { + "name": "common_tab@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debugt_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debugt_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debugts_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debugts_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debugtt_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debugtt_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "environment_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "environment_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "envvar_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "envvar_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_config_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_config_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "expression_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "expression_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "file_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "file_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "fldr_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "fldr_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "genericreggroup_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "genericreggroup_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "genericregister_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "genericregister_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "genericvariable_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "genericvariable_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "import_config_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "import_config_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "inst_ptr.png" + }, + "incompressible": true + }, + { + "element": { + "name": "inst_ptr@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "inst_ptr_top.png" + }, + "incompressible": true + }, + { + "element": { + "name": "inst_ptr_top@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "jar_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "jar_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "ldebug_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "ldebug_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lgroup_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lgroup_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lrun_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lrun_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memory_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memory_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memorychanged_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memorychanged_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "osprc_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "osprc_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "osprct_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "osprct_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "persp_tab.png" + }, + "incompressible": true + }, + { + "element": { + "name": "persp_tab@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prj_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prj_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "proto_tab.png" + }, + "incompressible": true + }, + { + "element": { + "name": "proto_tab@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "read_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "read_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "read_obj_disabled.png" + }, + "incompressible": true + }, + { + "element": { + "name": "read_obj_disabled@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "readwrite_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "readwrite_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "readwrite_obj_disabled.png" + }, + "incompressible": true + }, + { + "element": { + "name": "readwrite_obj_disabled@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "refresh_tab.png" + }, + "incompressible": true + }, + { + "element": { + "name": "refresh_tab@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rundebug.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rundebug@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stckframe_obj.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "stckframe_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stckframe_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stckframe_running_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stckframe_running_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminatedlaunch_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminatedlaunch_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "thread_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "thread_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "threads_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "threads_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "threadt_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "threadt_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "uncheck.png" + }, + "incompressible": true + }, + { + "element": { + "name": "uncheck@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "workset.png" + }, + "incompressible": true + }, + { + "element": { + "name": "workset@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "write_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "write_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "write_obj_disabled.png" + }, + "incompressible": true + }, + { + "element": { + "name": "write_obj_disabled@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "ovr16" + }, + "children": [ + { + "element": { + "name": "error.png" + }, + "incompressible": true + }, + { + "element": { + "name": "error@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prototype.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prototype@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "skip_breakpoint_ov.png" + }, + "incompressible": true + }, + { + "element": { + "name": "skip_breakpoint_ov@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stcksync_ov.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stcksync_ov@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "transparent.png" + }, + "incompressible": true + }, + { + "element": { + "name": "transparent@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "var_cntnt_prvdr_ov.png" + }, + "incompressible": true + }, + { + "element": { + "name": "var_cntnt_prvdr_ov@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "wizban" + }, + "children": [ + { + "element": { + "name": "adddir_wiz.png" + }, + "incompressible": true + }, + { + "element": { + "name": "addsrcloc_wiz.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_wiz.png" + }, + "incompressible": true + }, + { + "element": { + "name": "editdir_wiz.png" + }, + "incompressible": true + }, + { + "element": { + "name": "edtsrclkup_wiz.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_brkpts_wizban.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_config_wizban.png" + }, + "incompressible": true + }, + { + "element": { + "name": "import_brkpts_wizban.png" + }, + "incompressible": true + }, + { + "element": { + "name": "import_config_wizban.png" + }, + "incompressible": true + }, + { + "element": { + "name": "profile_wiz.png" + }, + "incompressible": true + }, + { + "element": { + "name": "run_wiz.png" + }, + "incompressible": true + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "plugin.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "plugin.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "schema" + }, + "children": [ + { + "element": { + "name": "breakpointOrganizers.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "consoleColorProviders.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "consoleLineTrackers.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "contextViewBindings.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "debugModelContextBindings.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "debugModelPresentations.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "detailPaneFactories.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "launchConfigurationTabGroups.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "launchConfigurationTabs.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "launchConfigurationTypeImages.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "launchGroups.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "launchShortcuts.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "memoryRenderings.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "sourceContainerPresentations.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "stringVariablePresentations.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "toggleBreakpointsTargetFactories.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "variableValueEditors.exsd" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "scripts" + }, + "children": [ + { + "element": { + "name": "exportplugin.xml" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "ui" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "debug" + }, + "children": [ + { + "element": { + "name": "internal" + }, + "children": [ + { + "element": { + "name": "ui" + }, + "children": [ + { + "element": { + "name": "AbstractDebugCheckboxSelectionDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractDebugListSelectionDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractDebugSelectionDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointImageProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BuildBeforeLaunchStatusHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ColorManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CompositeDebugImageDescriptor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugModelPropertyTester.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugPerspectiveFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugPluginImages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugUIAdapterFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugUIMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugUIMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugUIPlugin.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugUIPreferenceInitializer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DelegatingModelPresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DynamicInstructionPointerAnnotation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugHelpContextIds.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IInternalDebugUIConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchHistoryChangedListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchLabelChangedListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ImageDescriptorRegistry.java" + }, + "incompressible": true + }, + { + "element": { + "name": "InstructionPointerAnnotation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "InstructionPointerContext.java" + }, + "incompressible": true + }, + { + "element": { + "name": "InstructionPointerImageProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "InstructionPointerManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationTabExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LazyModelPresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MultipleInputDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Pair.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResourceExtender.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SWTFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TerminateToggleValue.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TextGetSetEditingSupport.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariableValueEditorManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariablesViewModelPresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkingDirectoryStatusHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "actions" + }, + "children": [ + { + "element": { + "name": "AbstractDebugActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractRemoveAllActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractSelectionActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ActionMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ActionMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "AddToFavoritesAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CollapseAllAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConfigureColumnsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugAsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugContextualLaunchAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugHistoryMenuAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugLastAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugToolbarAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EditLaunchConfigurationAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExecutionAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchShortcutAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchablePropertyTester.java" + }, + "incompressible": true + }, + { + "element": { + "name": "OpenDebugConfigurations.java" + }, + "incompressible": true + }, + { + "element": { + "name": "OpenProfileConfigurations.java" + }, + "incompressible": true + }, + { + "element": { + "name": "OpenRunConfigurations.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProfileAsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProfileContextualLaunchAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProfileHistoryMenuAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProfileLastAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProfileToolbarAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RelaunchActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RelaunchLastAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RemoveAllTerminatedAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RetargetAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RetargetRunToLineAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RunAsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RunContextualLaunchAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RunHistoryMenuAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RunLastAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RunToolbarAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectAllAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StatusInfo.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleBreakpointsTargetManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleFilterAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewManagementAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "breakpointGroups" + }, + "children": [ + { + "element": { + "name": "AbstractBreakpointsViewAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AdvancedGroupBreakpointsByAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointGroupMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointGroupMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointSelectionAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointWorkingSetAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ClearDefaultBreakpointGroupAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CopyBreakpointsActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EditBreakpointGroupAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GroupBreakpointsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GroupBreakpointsByAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GroupBreakpointsByDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PasteBreakpointsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RemoveFromWorkingSetAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectBreakpointWorkingsetDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SetDefaultBreakpointGroupAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleDefaultGroupAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkingSetsAction.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "breakpointSortBy" + }, + "children": [ + { + "element": { + "name": "Messages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Messages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "SortBreakpointsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SortBreakpointsByAction.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "breakpoints" + }, + "children": [ + { + "element": { + "name": "AccessWatchpointToggleAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointsCollapseAllAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointsExpandAllAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DeleteWorkingsetsMessageDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DisableBreakpointsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EnableBreakpointsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LinkBreakpointsWithDebugViewAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Messages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Messages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "ModificationWatchpointToggleAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ModifyWatchpointAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "OpenBreakpointMarkerAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RemoveAllBreakpointsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RemoveAllTriggerPointsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RemoveBreakpointAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RetargetBreakpointAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RetargetMethodBreakpointAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RetargetToggleBreakpointAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RetargetToggleLineBreakpointAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RetargetWatchpointAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RulerEnableDisableBreakpointAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectAllBreakpointsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ShowSupportedBreakpointsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ShowTargetBreakpointsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SkipAllBreakpointsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleBreakpointObjectActionDelegate.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "expressions" + }, + "children": [ + { + "element": { + "name": "AddWatchExpressionAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConvertToWatchExpressionAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CopyExpressionsToClipboardActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DisableWatchExpressionAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EditWatchExpressinInPlaceAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EditWatchExpressionAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EnableWatchExpressionAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PasteWatchExpressionsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ReevaluateWatchExpressionAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RemoveAllExpressionsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RemoveExpressionAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectAllExpressionsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WatchExpressionAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WatchExpressionDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WatchExpressionFactoryTester.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WatchHandler.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "variables" + }, + "children": [ + { + "element": { + "name": "ChangeVariableValueAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ChangeVariableValueInputDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectAllVariablesAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ShowTypesAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleDetailPaneAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "details" + }, + "children": [ + { + "element": { + "name": "DetailPaneAssignValueAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DetailPaneMaxLengthAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DetailPaneMaxLengthDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DetailPaneWordWrapAction.java" + }, + "incompressible": true + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "breakpoints" + }, + "children": [ + { + "element": { + "name": "provisional" + }, + "children": [ + { + "element": { + "name": "IBreakpointContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreakpointOrganizer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreakpointUIConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "OtherBreakpointCategory.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "commands" + }, + "children": [ + { + "element": { + "name": "actions" + }, + "children": [ + { + "element": { + "name": "AbstractRequestMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ActionsUpdater.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugActionHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugCommandActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugCommandService.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DisconnectCommandAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DisconnectCommandActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DisconnectCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DropToFrameCommandAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DropToFrameCommandActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DropToFrameCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExecuteActionRequest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ICommandParticipant.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IEnabledTarget.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RestartCommandAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RestartCommandActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RestartCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResumeCommandAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResumeCommandActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResumeCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepIntoCommandAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepIntoCommandActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepIntoCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepOverCommandAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepOverCommandActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepOverCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepReturnCommandAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepReturnCommandActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepReturnCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SuspendCommandAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SuspendCommandActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SuspendCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TerminateAllAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TerminateAllActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TerminateAndRelaunchAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TerminateAndRelaunchHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TerminateAndRemoveAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TerminateCommandAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TerminateCommandActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TerminateCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleStepFiltersAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleStepFiltersCommandActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleStepFiltersCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "UpdateActionsRequest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "UpdateHandlerRequest.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "contextlaunching" + }, + "children": [ + { + "element": { + "name": "ContextMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ContextMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "ContextRunner.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchingResourceManager.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "contexts" + }, + "children": [ + { + "element": { + "name": "DebugContextManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugContextSourceProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugModelContextBindingManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugWindowContextService.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchSuspendTrigger.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SuspendTriggerAdapterFactory.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "elements" + }, + "children": [ + { + "element": { + "name": "adapters" + }, + "children": [ + { + "element": { + "name": "AsynchronousDebugLabelAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultBreakpointsViewInput.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultVariableCellModifier.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultViewerInputProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlockContentAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlockLabelAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryRetrievalContentAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemorySegmentLabelAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Messages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Messages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "RegisterGroupProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StackFrameSourceDisplayAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StackFrameViewerInputProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariableColumnFactoryAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariableColumnPresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WatchExpressionCellModifier.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "groups" + }, + "children": [ + { + "element": { + "name": "CommonTabLite.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GroupCycleHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GroupElementLaunchedHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GroupLaunchConfigurationSelectionDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GroupLaunchConfigurationTabGroup.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GroupLaunchHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "UnsupportedModeHandler.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "hover" + }, + "children": [ + { + "element": { + "name": "DebugTextHover.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExpressionInformationControlCreator.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "importexport" + }, + "children": [ + { + "element": { + "name": "breakpoints" + }, + "children": [ + { + "element": { + "name": "BreakpointImportExport.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointsPathDecorator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EmbeddedBreakpointsViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExportBreakpoints.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IImportExportConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ImportBreakpoints.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ImportExportMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WizardExportBreakpoints.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WizardExportBreakpointsPage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WizardImportBreakpoints.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WizardImportBreakpointsPage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WizardImportBreakpointsSelectionPage.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "launchconfigurations" + }, + "children": [ + { + "element": { + "name": "ExportLaunchConfigurationsWizard.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExportLaunchConfigurationsWizardPage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ImportLaunchConfigurationsWizard.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ImportLaunchConfigurationsWizardPage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WizardMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WizardMessages.properties" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "launchConfigurations" + }, + "children": [ + { + "element": { + "name": "AbstractLaunchConfigurationAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ClosedProjectFilter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CollapseAllLaunchConfigurationAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CompileErrorProjectPromptStatusHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CompileErrorPromptStatusHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CreateLaunchConfigurationAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CreateLaunchConfigurationPrototypeAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugModePromptStatusHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DeleteLaunchConfigurationAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DeletedProjectFilter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DuplicateLaunchConfigurationAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DuplicateLaunchDelegatesStatusHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EnvironmentVariable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExportLaunchConfigurationAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FavoritesDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FilterDropDownMenuCreator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FilterLaunchConfigurationAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchCategoryFilter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationComparator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationEditDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationFilteredTree.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationPresentationManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationPropertiesDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationSelectionDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationTabGroupExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationTabGroupViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationTabGroupWrapper.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationTabImageDescriptor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationTreeContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationTypeContribution.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationTypeFilter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationsDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationsMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationsMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchDelegateContribution.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchDelegateNotAvailableHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchGroupExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchGroupFilter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchHistory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchShortcutExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchShortcutSelectionDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchTabContribution.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LinkPrototypeAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "OrganizeFavoritesAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PerspectiveManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResetWithPrototypeValuesAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SaveScopeResourcesHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectFavoritesDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectLaunchModesDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectLaunchersDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ShowCommandLineDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "UnlinkPrototypeAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkingSetComparator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkingSetsFilter.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "memory" + }, + "children": [ + { + "element": { + "name": "IMemoryBlockConnection.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryRenderingUpdater.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IPersistableDebugElement.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryRenderingManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryRenderingType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RenderingBindings.java" + }, + "incompressible": true + }, + { + "element": { + "name": "provisional" + }, + "children": [ + { + "element": { + "name": "AbstractAsyncTableRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractAsyncTextRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryViewPresentationContext.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "model" + }, + "children": [ + { + "element": { + "name": "elements" + }, + "children": [ + { + "element": { + "name": "BreakpointContainerLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointContainerMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointManagerContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointManagerInputMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugElementLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugElementMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugTargetContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ElementContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ElementLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ElementMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExpressionContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExpressionLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExpressionManagerContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExpressionManagerMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExpressionMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchManagerContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlockContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlockLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryRetrievalContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryViewElementMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProcessContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RegisterGroupContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RegisterGroupLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RegisterGroupMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StackFrameContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StackFrameMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ThreadContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariableContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariableEditor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariableLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariableMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewerInputProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WatchExpressionEditor.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "preferences" + }, + "children": [ + { + "element": { + "name": "BooleanFieldEditor2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsolePreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugPreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugPreferencesMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugPreferencesMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugPreferenceConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationsPreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchPerspectivePreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchersPreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchingPreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProcessPropertyPage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RunDebugPropertiesPage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StringVariablePreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewManagementPreferencePage.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "quickaccess" + }, + "children": [ + { + "element": { + "name": "AbstractLaunchQuickAccessComputer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugQuickAccessComputer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchQuickAccessElement.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProfileQuickAccessComputer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RunQuickAccessComputer.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "sourcelookup" + }, + "children": [ + { + "element": { + "name": "AddContainerAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AddSourceContainerDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BasicContainerContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DownAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EditContainerAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EditSourceLookupPathAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LookupSourceAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Prompter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RemoveAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResolveDuplicatesHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RestoreDefaultAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceContainerAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceContainerAdapterFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceContainerLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceContainerViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceContainerWorkbenchAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceElementAdapterFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceElementLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceElementWorkbenchAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupFacility.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupPanel.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupResult.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupService.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupUIMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupUIMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupUIUtils.java" + }, + "incompressible": true + }, + { + "element": { + "name": "UpAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkingSetSourceContainerType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "browsers" + }, + "children": [ + { + "element": { + "name": "ArchiveFilter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ArchiveSourceContainerBrowser.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DirectorySourceContainerBrowser.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DirectorySourceContainerDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalArchiveSourceContainerBrowser.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FolderSourceContainerBrowser.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FolderSourceContainerDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProjectSourceContainerBrowser.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProjectSourceContainerDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkingSetSourceContainerBrowser.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkspaceSourceContainerBrowser.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "stringsubstitution" + }, + "children": [ + { + "element": { + "name": "FilePrompt.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FolderPrompt.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IArgumentSelector.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PasswordPrompt.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PromptingResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResourceSelector.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectedResourceManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectedResourceResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectedTextResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StringPrompt.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StringSubstitutionMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StringSubstitutionMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "StringVariableLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StringVariablePresentationManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SystemPropertyArgumentSelector.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "viewers" + }, + "children": [ + { + "element": { + "name": "AbstractUpdatePolicy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsynchronousModel.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsynchronousRequestMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsynchronousSchedulingRuleFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsynchronousTableModel.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsynchronousTableViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsynchronousViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ChildrenRequestMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FindElementDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILabelResult.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LabelRequestMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LabelResult.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ModelNode.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PartPresentationContext.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableAddRequestMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableEditorImpl.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableInsertRequestMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRemoveRequestMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableReplaceRequestMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableUpdatePolicy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "breadcrumb" + }, + "children": [ + { + "element": { + "name": "AbstractBreadcrumb.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreadcrumbItem.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreadcrumbItemDetails.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreadcrumbItemDropDown.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreadcrumbMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreadcrumbMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "BreadcrumbViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreadcrumbDropDownSite.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TreeViewerDropDown.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "model" + }, + "children": [ + { + "element": { + "name": "ChildrenCountUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ChildrenUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ElementCompareRequest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ElementMementoRequest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FilterTransform.java" + }, + "incompressible": true + }, + { + "element": { + "name": "HasChildrenUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IInternalTreeModelViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILabelUpdateListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ITreeModelContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ITreeModelLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ITreeModelViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "InternalTreeModelViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "InternalVirtualTreeModelViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LabelUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MementoUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SubTreeModelViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TimeTriggeredProgressMonitorDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TreeModelContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TreeModelLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewerAdapterService.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewerInputUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewerStateTracker.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewerUpdateMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualCopyToClipboardActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualFindAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "provisional" + }, + "children": [ + { + "element": { + "name": "ICheckUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ICheckboxModelProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IChildrenCountUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IChildrenUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IColumnPresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IColumnPresentation2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IColumnPresentationFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IElementCompareRequest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IElementContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IElementEditor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IElementLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IElementMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IElementMementoRequest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IHasChildrenUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILabelUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IModelChangedListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IModelDelta.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IModelDeltaVisitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IModelProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IModelProxy2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IModelProxyFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IModelProxyFactory2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IModelSelectionPolicy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IModelSelectionPolicyFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IPresentationContext.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStateUpdateListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStatusMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ITreeModelViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IViewActionProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IViewerInputProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IViewerInputRequestor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IViewerInputUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IViewerUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IViewerUpdateListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IVirtualItemListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IVirtualItemValidator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ModelDelta.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PresentationContext.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TreeModelViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TreeModelViewerFilter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewerInputService.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualItem.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualTree.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualTreeModelViewer.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "provisional" + }, + "children": [ + { + "element": { + "name": "AbstractColumnPresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractModelProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsynchronousContentAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsynchronousLabelAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IAsynchronousContentAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IAsynchronousLabelAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IChildrenRequestMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IContainerRequestMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILabelRequestMonitor.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "update" + }, + "children": [ + { + "element": { + "name": "BreakpointContainerProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointManagerProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugEventHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugTargetEventHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugTargetProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultExpressionModelProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultModelProxyFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultModelSelectionPolicyFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultSelectionPolicy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultVariableViewModelProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultWatchExpressionModelProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EventHandlerModelProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExpressionEventHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExpressionManagerModelProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchManagerProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlockProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryRetrievalProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProcessProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StackFrameEventHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ThreadEventHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariablesViewEventHandler.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "views" + }, + "children": [ + { + "element": { + "name": "DebugModelPresentationContext.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugUIViewsMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugUIViewsMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugExceptionHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewContextManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewContextService.java" + }, + "incompressible": true + }, + { + "element": { + "name": "breakpoints" + }, + "children": [ + { + "element": { + "name": "BreakpointContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointContainerWorkbenchAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointOrganizerExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointOrganizerManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointPersistableElementAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointSetOrganizer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointTypeOrganizer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointWorkingSetCache.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointWorkingSetElementAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointWorkingSetPage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointsComparator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointsContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointsDragAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointsDropAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointsLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointsView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointsViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ElementComparator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FileBreakpointOrganizer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProjectBreakpointOrganizer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkingSetBreakpointOrganizer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkingSetCategory.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "console" + }, + "children": [ + { + "element": { + "name": "ConsoleLineNotifier.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleRemoveAllTerminatedAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleRemoveLaunchAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleShowPreferencesAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleTerminateAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProcessConsole.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProcessConsoleManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProcessConsolePageParticipant.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProcessTypePropertyTester.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ShowStandardErrorAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ShowStandardOutAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ShowWhenContentChangesAction.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "expression" + }, + "children": [ + { + "element": { + "name": "ExpressionDropAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExpressionView.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "launch" + }, + "children": [ + { + "element": { + "name": "BreadcrumbDropDownAutoExpandAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreadcrumbWorkbenchPart.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugElementAdapterFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugElementHelper.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugToolBarAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugViewModeAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Decoration.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DecorationManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ImageImageDescriptor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchViewBreadcrumb.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchViewCopyToClipboardActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchViewMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchViewMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceNotFoundEditor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceNotFoundEditorInput.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StandardDecoration.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TerminateAndRemoveHandler.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "memory" + }, + "children": [ + { + "element": { + "name": "AbstractMemoryViewPane.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AddMemoryBlockAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AddMemoryRenderingAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AddMemoryRenderingContextAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AddMemoryRenderingDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CodePagesPreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryViewPane.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryViewTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LinkRenderingPanesAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlocksTreeViewPane.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryViewIdRegistry.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryViewPrefAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryViewSynchronizationService.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryViewTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryViewTreeModelContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryViewTreeViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryViewUtil.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MonitorMemoryBlockDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "NewMemoryViewAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PinMemoryBlockAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PropertyChangeNotifier.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RemoveMemoryRenderingAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RemoveRenderingContextAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RenderingViewPane.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResetMemoryBlockAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResetMemoryBlockPreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RetargetAddMemoryBlockAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SetPaddedStringPreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SwitchMemoryBlockAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SynchronizeInfo.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleMemoryMonitorsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleSplitPaneAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleViewPaneAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewPaneOrientationAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewPaneRenderingMgr.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewPaneSelectionProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewTabEnablementManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "renderings" + }, + "children": [ + { + "element": { + "name": "ASCIIRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ASCIIRenderingTypeDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractBaseTableRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractIntegerRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractTableRenderingLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractVirtualContentTableModel.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsyncCopyTableRenderingAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsyncPrintTableRenderingAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsyncTableRenderingCellModifier.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsyncTableRenderingUpdatePolicy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsyncTableRenderingViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsyncVirtualContentTableViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BasicDebugViewContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BigEndianAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CopyTableRenderingToClipboardAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CreateRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultEndianessAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ErrorRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FormatTableRenderingAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FormatTableRenderingDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GoToAddressAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GoToAddressComposite.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GoToAddressDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "HexIntegerRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "HexIntegerRenderingDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "HexRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "HexRenderingTypeDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IContentChangeComputer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IPresentationErrorListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IVirtualContentListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LittleEndianAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemorySegment.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PendingPropertyChanges.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PrintTableRenderingAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ReformatAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RenderingsUtil.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResetToBaseAddressAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SignedIntegerRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SignedIntegerRenderingTypeDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRenderingCellModifier.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRenderingContentDescriptor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRenderingContentInput.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRenderingContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRenderingLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRenderingLabelProviderEx.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRenderingLine.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRenderingModel.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRenderingPrefAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRenderingPreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRenderingPropertiesPage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "UnsignedIntegerRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "UnsignedIntegerRenderingTypeDelegate.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "modules" + }, + "children": [ + { + "element": { + "name": "IHelpContextIdProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ModulesView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ModulesViewMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ModulesViewMessages.properties" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "registers" + }, + "children": [ + { + "element": { + "name": "RegistersView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RegistersViewMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RegistersViewMessages.properties" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "variables" + }, + "children": [ + { + "element": { + "name": "AvailableLogicalStructuresAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EditVariableLogicalStructureAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IndexedValuePartition.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IndexedVariablePartition.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LogicalStructureCache.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectLogicalStructureAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectionDragAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleLogicalStructureAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleShowColumnsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariableViewToggleAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariablesView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariablesViewMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariablesViewMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "VariablesViewResourceBundleMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "details" + }, + "children": [ + { + "element": { + "name": "AbstractDetailPane.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AvailableDetailPanesAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultDetailPane.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultDetailPaneFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DetailMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DetailMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "DetailPaneManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DetailPaneProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDetailPaneContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDetailPaneContainer2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MessageDetailPane.java" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "ui" + }, + "children": [ + { + "element": { + "name": "AbstractBreakpointOrganizerDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractDebugView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractLaunchConfigurationTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractLaunchConfigurationTabGroup.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointTypeCategory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CommonTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugElementWorkbenchAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugPopup.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugUITools.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DeferredDebugElementWorkbenchAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EnvironmentTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreakpointOrganizerDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreakpointOrganizerDelegateExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreakpointTypeCategory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugEditorPresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugModelPresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugModelPresentationExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugUIConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDetailPane.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDetailPane2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDetailPane3.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDetailPaneFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IInstructionPointerPresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchConfigurationDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchConfigurationTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchConfigurationTab2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchConfigurationTabGroup.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchGroup.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchShortcut.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchShortcut2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourcePresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IValueDetailListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "InspectPopupDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PrototypeDecorator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PrototypeTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RefreshTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StringVariableSelectionDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkingDirectoryBlock.java" + }, + "incompressible": true + }, + { + "element": { + "name": "actions" + }, + "children": [ + { + "element": { + "name": "AbstractLaunchHistoryAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractLaunchToolbarAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AddMemoryRenderingActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointTypesContribution.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ContextualLaunchAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugCommandAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExportBreakpointsOperation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IAddMemoryBlocksTarget.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IAddMemoryRenderingsTarget.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IRunToLineTarget.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IToggleBreakpointsTarget.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IToggleBreakpointsTargetExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IToggleBreakpointsTargetExtension2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IToggleBreakpointsTargetFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IToggleBreakpointsTargetManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IToggleBreakpointsTargetManagerListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IVariableValueEditor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IWatchExpressionFactoryAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IWatchExpressionFactoryAdapter2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IWatchExpressionFactoryAdapterExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ImportBreakpointsOperation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchAsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchShortcutsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "OpenLaunchDialogAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RelaunchLastAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RulerBreakpointAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RulerBreakpointTypesActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RulerEnableDisableBreakpointActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RulerRunToLineActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RulerToggleBreakpointActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RunAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RunToLineAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RunToLineActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RunToLineHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleBreakpointAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleMethodBreakpointActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleWatchpointActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "console" + }, + "children": [ + { + "element": { + "name": "ConsoleColorProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FileLink.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsole.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsoleColorProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsoleHyperlink.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsoleLineTracker.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsoleLineTrackerExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "contexts" + }, + "children": [ + { + "element": { + "name": "AbstractDebugContextProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugContextEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugContextListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugContextManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugContextProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugContextProvider2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugContextService.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISuspendTrigger.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISuspendTriggerListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "memory" + }, + "children": [ + { + "element": { + "name": "AbstractMemoryRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractMemoryRenderingBindingsProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractTableRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractTextRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryBlockTablePresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryRenderingBindingsListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryRenderingBindingsProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryRenderingContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryRenderingManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryRenderingSite.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryRenderingSite2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryRenderingSynchronizationService.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryRenderingType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryRenderingTypeDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IRepositionableMemoryRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IResettableMemoryRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryRenderingElement.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + }, + { + "element": { + "name": "sourcelookup" + }, + "children": [ + { + "element": { + "name": "AbstractSourceContainerBrowser.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CommonSourceNotFoundEditor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CommonSourceNotFoundEditorInput.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourceContainerBrowser.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourceDisplay.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourceLookupResult.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkingSetSourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "stringsubstitution" + }, + "children": [ + { + "element": { + "name": "IArgumentSelector.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "org.eclipse.ui.console" + }, + "children": [ + { + "element": { + "name": ".classpath" + }, + "incompressible": true + }, + { + "element": { + "name": ".project" + }, + "incompressible": true + }, + { + "element": { + "name": ".settings" + }, + "children": [ + { + "element": { + "name": "org.eclipse.core.resources.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.runtime.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.core.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.ui.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.api.tools.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.prefs" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "META-INF" + }, + "children": [ + { + "element": { + "name": "MANIFEST.MF" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "about.html" + }, + "incompressible": true + }, + { + "element": { + "name": "build.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "icons" + }, + "children": [ + { + "element": { + "name": "full" + }, + "children": [ + { + "element": { + "name": "clcl16" + }, + "children": [ + { + "element": { + "name": "clear_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "clear_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lock_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lock_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "pin.png" + }, + "incompressible": true + }, + { + "element": { + "name": "pin@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "wordwrap.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "cview16" + }, + "children": [ + { + "element": { + "name": "console_view.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "console_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "console_view@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "dlcl16" + }, + "children": [ + { + "element": { + "name": "clear_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "clear_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lock_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lock_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_con.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_con@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "pin.png" + }, + "incompressible": true + }, + { + "element": { + "name": "pin@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "wordwrap.png" + }, + "incompressible": true + }, + { + "element": { + "name": "wordwrap@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "dview16" + }, + "children": [ + { + "element": { + "name": "console_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "console_view@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "elcl16" + }, + "children": [ + { + "element": { + "name": "clear_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "clear_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lock_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lock_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_con.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_con@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "pin.png" + }, + "incompressible": true + }, + { + "element": { + "name": "pin@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "wordwrap.png" + }, + "incompressible": true + }, + { + "element": { + "name": "wordwrap@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "eview16" + }, + "children": [ + { + "element": { + "name": "console_view.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "console_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "console_view@2x.png" + }, + "incompressible": true + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "plugin.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "plugin.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "schema" + }, + "children": [ + { + "element": { + "name": "consoleFactories.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "consolePageParticipants.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "consolePatternMatchListeners.exsd" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "scripts" + }, + "children": [ + { + "element": { + "name": "exportplugin.xml" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "src" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "ui" + }, + "children": [ + { + "element": { + "name": "console" + }, + "children": [ + { + "element": { + "name": "AbstractConsole.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsolePlugin.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsole.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsoleConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsoleDocumentPartitioner.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsoleFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsoleListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsoleManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsolePageParticipant.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsoleView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IHyperlink.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IHyperlink2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IOConsole.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IOConsoleInputStream.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IOConsoleOutputStream.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IPatternMatchListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IPatternMatchListenerDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IScrollLockStateProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MessageConsole.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MessageConsoleStream.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PatternMatchEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TextConsole.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TextConsolePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TextConsoleViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "actions" + }, + "children": [ + { + "element": { + "name": "ClearOutputAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CloseConsoleAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TextViewerAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TextViewerGotoLineAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "internal" + }, + "children": [ + { + "element": { + "name": "console" + }, + "children": [ + { + "element": { + "name": "ConsoleDocument.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleDocumentAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleDropDownAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleFactoryExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleHyperlinkPosition.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsolePageParticipantExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsolePatternMatcher.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsolePluginImages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleResourceBundleMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleResourceBundleMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleTypePropertyTester.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleUIPreferenceInitializer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleViewConsoleFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleWorkbenchPart.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FollowHyperlinkAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "HyperlinkUpdater.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsoleHelpContextIds.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IInternalConsoleConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IOConsolePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IOConsolePartition.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IOConsolePartitioner.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IOConsoleViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "OpenConsoleAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PatternMatchListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PatternMatchListenerExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PinConsoleAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ScrollLockAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ShowConsoleAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StreamDecoder.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WordWrapAction.java" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "org.eclipse.ui.externaltools" + }, + "children": [ + { + "element": { + "name": ".classpath" + }, + "incompressible": true + }, + { + "element": { + "name": ".gitignore" + }, + "incompressible": true + }, + { + "element": { + "name": ".project" + }, + "incompressible": true + }, + { + "element": { + "name": ".settings" + }, + "children": [ + { + "element": { + "name": ".api_filters" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.resources.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.runtime.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.core.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.ui.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.api.tools.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.prefs" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "External Tools Base" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "ui" + }, + "children": [ + { + "element": { + "name": "externaltools" + }, + "children": [ + { + "element": { + "name": "internal" + }, + "children": [ + { + "element": { + "name": "launchConfigurations" + }, + "children": [ + { + "element": { + "name": "ExternalToolsBuildTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsBuilderTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsLaunchConfigurationMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsLaunchConfigurationMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsMainTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsUtil.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IgnoreWhiteSpaceComparator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkingSetComparator.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "menu" + }, + "children": [ + { + "element": { + "name": "ExternalToolMenuDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "OpenExternalToolsConfigurations.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "model" + }, + "children": [ + { + "element": { + "name": "BuilderUtils.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsImages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsModelMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsModelMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsPlugin.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsPreferenceInitializer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IExternalToolConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IExternalToolsHelpContextIds.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IPreferenceConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ImageDescriptorRegistry.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "ui" + }, + "children": [ + { + "element": { + "name": "BuilderLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BuilderPropertyPage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EditCommandDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsPreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsUIMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsUIMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "FileSelectionDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TreeAndListGroup.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "variables" + }, + "children": [ + { + "element": { + "name": "BuildFilesResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BuildProjectResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BuildTypeResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SystemPathResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariableMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariableMessages.properties" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "META-INF" + }, + "children": [ + { + "element": { + "name": "MANIFEST.MF" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "Program Tools Support" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "ui" + }, + "children": [ + { + "element": { + "name": "externaltools" + }, + "children": [ + { + "element": { + "name": "internal" + }, + "children": [ + { + "element": { + "name": "program" + }, + "children": [ + { + "element": { + "name": "launchConfigurations" + }, + "children": [ + { + "element": { + "name": "ExternalToolsProgramMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsProgramMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "ProgramBuilderTabGroup.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProgramMainTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProgramTabGroup.java" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "about.html" + }, + "incompressible": true + }, + { + "element": { + "name": "build.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "icons" + }, + "children": [ + { + "element": { + "name": "full" + }, + "children": [ + { + "element": { + "name": "dtool16" + }, + "children": [ + { + "element": { + "name": "external_tools.png" + }, + "incompressible": true + }, + { + "element": { + "name": "external_tools@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "etool16" + }, + "children": [ + { + "element": { + "name": "external_tools.png" + }, + "incompressible": true + }, + { + "element": { + "name": "external_tools@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "obj16" + }, + "children": [ + { + "element": { + "name": "build_tab.png" + }, + "incompressible": true + }, + { + "element": { + "name": "build_tab@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "builder.png" + }, + "incompressible": true + }, + { + "element": { + "name": "builder@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "classpath.png" + }, + "incompressible": true + }, + { + "element": { + "name": "classpath@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "external_tools.png" + }, + "incompressible": true + }, + { + "element": { + "name": "external_tools@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "invalid_build_tool.png" + }, + "incompressible": true + }, + { + "element": { + "name": "invalid_build_tool@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "main_tab.png" + }, + "incompressible": true + }, + { + "element": { + "name": "main_tab@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "wizban" + }, + "children": [ + { + "element": { + "name": "ext_tools_wiz.png" + }, + "incompressible": true + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "plugin.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "plugin.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "schema" + }, + "children": [ + { + "element": { + "name": "configurationDuplicationMaps.exsd" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + } + ] + } +] \ No newline at end of file diff --git a/test/tree/public/index.html b/test/tree/public/index.html index 7c83e9b04..17c88461c 100644 --- a/test/tree/public/index.html +++ b/test/tree/public/index.html @@ -44,7 +44,7 @@ require.config({ baseUrl: '/static' }); - require(['vs/base/browser/ui/tree/indexTree', 'vs/base/browser/ui/tree/asyncDataTree', 'vs/base/browser/ui/tree/dataTree', 'vs/base/browser/ui/tree/tree', 'vs/base/common/iterator'], ({ IndexTree }, { AsyncDataTree }, { DataTree }, { TreeVisibility }, { iter }) => { + require(['vs/base/browser/ui/tree/indexTree', 'vs/base/browser/ui/tree/compressedObjectTree', 'vs/base/browser/ui/tree/asyncDataTree', 'vs/base/browser/ui/tree/dataTree', 'vs/base/browser/ui/tree/tree', 'vs/base/common/iterator'], ({ IndexTree }, { CompressedObjectTree }, { AsyncDataTree }, { DataTree }, { TreeVisibility }, { iter }) => { function createIndexTree(opts) { opts = opts || {}; @@ -100,6 +100,57 @@ return { tree, treeFilter }; } + function createCompressedObjectTree(opts) { + opts = opts || {}; + + const delegate = { + getHeight() { return 22; }, + getTemplateId() { return 'template'; }, + hasDynamicHeight() { return true; } + }; + + const renderer = { + templateId: 'template', + renderTemplate(container) { return container; }, + renderElement(element, index, container) { + if (element.element.elements.length > 1) { + container.innerHTML = `🙈 ${element.element.elements.map(el => el.name).join('/')}`; + } else { + container.innerHTML = element.element.elements[0].name; + } + }, + disposeElement() { }, + disposeTemplate() { } + }; + + const treeFilter = new class { + constructor() { + this.pattern = null; + let timeout; + filter.oninput = () => { + clearTimeout(timeout); + timeout = setTimeout(() => this.updatePattern(), 300); + }; + } + updatePattern() { + if (!filter.value) { + this.pattern = null; + } else { + this.pattern = new RegExp(filter.value, 'i'); + } + + perf('refilter', () => tree.refilter()); + } + filter(el) { + return (this.pattern ? this.pattern.test(el) : true) ? TreeVisibility.Visible : TreeVisibility.Recurse; + } + }; + + const tree = new CompressedObjectTree(container, delegate, [renderer], { ...opts, filter: treeFilter, setRowLineHeight: false, collapseByDefault: true, setRowLineHeight: true }); + + return { tree, treeFilter }; + } + function createAsyncDataTree() { const delegate = { getHeight() { return 22; }, @@ -155,7 +206,7 @@ getChildren(element) { return new Promise((c, e) => { const xhr = new XMLHttpRequest(); - xhr.open('GET', element ? `/api/readdir?path=${element.element.path}` : '/api/readdir'); + xhr.open('GET', element ? `/ api / readdir ? path = ${element.element.path} ` : '/api/readdir'); xhr.send(); xhr.onreadystatechange = function () { if (this.readyState == 4 && this.status == 200) { @@ -258,7 +309,7 @@ const errors = []; for (let j = 1; j <= 3; j++) { - errors.push({ element: `error #${j}` }); + errors.push({ element: `error #${j} ` }); } files.push({ element: `file #${i}`, children: errors }); @@ -289,6 +340,23 @@ break; } + case '?compressed': { + const { tree, treeFilter } = createCompressedObjectTree(); + + expandall.onclick = () => perf('expand all', () => tree.expandAll()); + collapseall.onclick = () => perf('collapse all', () => tree.collapseAll()); + + const xhr = new XMLHttpRequest(); + xhr.open('GET', '/compressed.json'); + xhr.send(); + xhr.onreadystatechange = function () { + if (this.readyState == 4 && this.status == 200) { + tree.setChildren(null, JSON.parse(this.responseText)); + } + }; + + break; + } case '?height': { const { tree, treeFilter } = createIndexTree({ supportDynamicHeights: true }); diff --git a/test/tree/tree.js b/test/tree/tree.js new file mode 100644 index 000000000..4d5a9b5f2 --- /dev/null +++ b/test/tree/tree.js @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +const path = require('path'); +const fs = require('fs'); + +function collect(location) { + const element = { name: path.basename(location) }; + const stat = fs.statSync(location); + + if (!stat.isDirectory()) { + return { element, incompressible: true }; + } + + const children = fs.readdirSync(location) + .map(child => path.join(location, child)) + .map(collect); + + return { element, children }; +} + +console.log(JSON.stringify(collect(process.cwd()))); \ No newline at end of file diff --git a/tslint.json b/tslint.json index 311eec214..155bd9a41 100644 --- a/tslint.json +++ b/tslint.json @@ -364,6 +364,7 @@ "**/vs/platform/*/{common,browser}/**", "**/vs/editor/{common,browser}/**", "**/vs/editor/contrib/**", // editor/contrib is equivalent to /browser/ by convention + "**/vs/workbench/workbench.web.api", "**/vs/workbench/{common,browser}/**", "**/vs/workbench/services/*/{common,browser}/**", "assert" @@ -429,7 +430,8 @@ "**/vs/editor/common/**", "**/vs/workbench/common/**", "**/vs/workbench/services/**/common/**", - "**/vs/workbench/api/**/common/**" + "**/vs/workbench/api/**/common/**", + "vscode-textmate" ] }, { @@ -440,8 +442,11 @@ "**/vs/base/**/{common,browser}/**", "**/vs/platform/**/{common,browser}/**", "**/vs/editor/{common,browser}/**", + "**/vs/workbench/workbench.web.api", "**/vs/workbench/{common,browser}/**", - "**/vs/workbench/services/**/{common,browser}/**" + "**/vs/workbench/services/**/{common,browser}/**", + "vscode-textmate", + "onigasm-umd" ] }, { @@ -504,7 +509,16 @@ { "target": "**/vs/workbench/contrib/terminal/browser/**", "restrictions": [ - "vscode-xterm", + // xterm and its addons are strictly browser-only components + "xterm", + "xterm-addon-*", + "**/vs/**" + ] + }, + { + "target": "**/vs/workbench/contrib/extensions/browser/**", + "restrictions": [ + "semver-umd", "**/vs/**" ] }, @@ -539,12 +553,28 @@ "**/vs/base/parts/**/{common,browser,node,electron-main}/**", "**/vs/platform/**/{common,browser,node,electron-main}/**", "**/vs/code/**/{common,browser,node,electron-main}/**", - "**/vs/code/code.main", "*" // node modules ] }, { - "target": "**/{node,electron-browser,electron-main,extensions}/**", + "target": "**/vs/server/**", + "restrictions": [ + "vs/nls", + "**/vs/base/**/{common,node}/**", + "**/vs/base/parts/**/{common,node}/**", + "**/vs/platform/**/{common,node}/**", + "**/vs/workbench/**/{common,node}/**", + "**/vs/server/**", + "**/vs/code/**/{common,node}/**", + "*" // node modules + ] + }, + { + "target": "**/{node,electron-browser,electron-main}/**", + "restrictions": "**/*" + }, + { + "target": "**/extensions/**", "restrictions": "**/*" }, { diff --git a/yarn.lock b/yarn.lock index 1e8975e4d..f1c162556 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14,6 +14,40 @@ dependencies: "@babel/highlight" "^7.0.0" +"@babel/generator@^7.4.0", "@babel/generator@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.5.0.tgz#f20e4b7a91750ee8b63656073d843d2a736dca4a" + integrity sha512-1TTVrt7J9rcG5PMjvO7VEG3FrEoEJNHxumRq66GemPmzboLWtIjjcJgk8rokuAS7IiRSpgVSu5Vb9lc99iJkOA== + dependencies: + "@babel/types" "^7.5.0" + jsesc "^2.5.1" + lodash "^4.17.11" + source-map "^0.5.0" + trim-right "^1.0.1" + +"@babel/helper-function-name@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz#a0ceb01685f73355d4360c1247f582bfafc8ff53" + integrity sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw== + dependencies: + "@babel/helper-get-function-arity" "^7.0.0" + "@babel/template" "^7.1.0" + "@babel/types" "^7.0.0" + +"@babel/helper-get-function-arity@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3" + integrity sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ== + dependencies: + "@babel/types" "^7.0.0" + +"@babel/helper-split-export-declaration@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz#ff94894a340be78f53f06af038b205c49d993677" + integrity sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q== + dependencies: + "@babel/types" "^7.4.4" + "@babel/highlight@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0.tgz#f710c38c8d458e6dd9a201afb637fcb781ce99e4" @@ -23,6 +57,44 @@ esutils "^2.0.2" js-tokens "^4.0.0" +"@babel/parser@^7.4.3", "@babel/parser@^7.4.4", "@babel/parser@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.5.0.tgz#3e0713dff89ad6ae37faec3b29dcfc5c979770b7" + integrity sha512-I5nW8AhGpOXGCCNYGc+p7ExQIBxRFnS2fd/d862bNOKvmoEPjYPcfIjsfdy0ujagYOIYPczKgD9l3FsgTkAzKA== + +"@babel/template@^7.1.0", "@babel/template@^7.4.0": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.4.tgz#f4b88d1225689a08f5bc3a17483545be9e4ed237" + integrity sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.4.4" + "@babel/types" "^7.4.4" + +"@babel/traverse@^7.4.3": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.5.0.tgz#4216d6586854ef5c3c4592dab56ec7eb78485485" + integrity sha512-SnA9aLbyOCcnnbQEGwdfBggnc142h/rbqqsXcaATj2hZcegCl903pUD/lfpsNBlBSuWow/YDfRyJuWi2EPR5cg== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/generator" "^7.5.0" + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-split-export-declaration" "^7.4.4" + "@babel/parser" "^7.5.0" + "@babel/types" "^7.5.0" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.11" + +"@babel/types@^7.0.0", "@babel/types@^7.4.0", "@babel/types@^7.4.4", "@babel/types@^7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.5.0.tgz#e47d43840c2e7f9105bc4d3a2c371b4d0c7832ab" + integrity sha512-UFpDVqRABKsW01bvw7/wSUe56uy6RXM5+VJibVVAybDGxEW25jdwiFJEf7ASvSaC7sN7rbE/l3cLp2izav+CtQ== + dependencies: + esutils "^2.0.2" + lodash "^4.17.11" + to-fast-properties "^2.0.0" + "@types/commander@^2.11.0": version "2.12.2" resolved "https://registry.yarnpkg.com/@types/commander/-/commander-2.12.2.tgz#183041a23842d4281478fa5d23c5ca78e6fd08ae" @@ -35,10 +107,10 @@ resolved "https://registry.yarnpkg.com/@types/fancy-log/-/fancy-log-1.3.0.tgz#a61ab476e5e628cd07a846330df53b85e05c8ce0" integrity sha512-mQjDxyOM1Cpocd+vm1kZBP7smwKZ4TNokFeds9LV7OZibmPJFEzY3+xZMrKfUdNT71lv8GoCPD6upKwHxubClw== -"@types/keytar@^4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@types/keytar/-/keytar-4.0.1.tgz#e2cf6405dc33861424e59b67516c66d2cf7bc21b" - integrity sha512-loKBID6UL4QjhD2scuvv6oAPlQ/WAY7aYTDyKlKo7fIgriLS8EZExqT567cHL5CY6si51MRoX1+r3mitD3eYrA== +"@types/keytar@^4.4.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@types/keytar/-/keytar-4.4.0.tgz#ca24e6ee6d0df10c003aafe26e93113b8faf0d8e" + integrity sha512-cq/NkUUy6rpWD8n7PweNQQBpw2o0cf5v6fbkUVEpOB9VzzIvyPvSEId1/goIj+MciW2v1Lw5mRimKO01XgE9EA== "@types/minimist@^1.2.0": version "1.2.0" @@ -261,11 +333,6 @@ abbrev@1: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== -abbrev@1.0.x: - version "1.0.9" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" - integrity sha1-kbR5JYinc4wl813W9jdSovh3YTU= - accepts@~1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.4.tgz#86246758c7dd6d21a6474ff084a4740ec05eb21f" @@ -303,10 +370,10 @@ acorn@^5.0.0, acorn@^5.6.2: resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8" integrity sha512-d+nbxBUGKg7Arpsvbnlq61mc12ek3EY8EQldM3GPAhWJ1UVxC6TDGbIvUMNU6obBX3i1+ptCIzV4vq0gFPEGVQ== -acorn@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.2.1.tgz#317ac7821826c22c702d66189ab8359675f135d7" - integrity sha512-jG0u7c4Ly+3QkkW18V+NRDN+4bWHdln30NL1ZL2AvFZZmQe/BfopYCtghCKKVBUSetZ4QKcyA0pY6/4Gw8Pv8w== +acorn@^5.5.0: + version "5.7.3" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279" + integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw== acorn@^6.0.2: version "6.0.7" @@ -327,24 +394,16 @@ agent-base@~4.2.0: dependencies: es6-promisify "^5.0.0" -ajv-keywords@^1.0.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" - integrity sha1-MU3QpLM2j609/NxU7eYXG4htrzw= +ajv-keywords@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" + integrity sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I= ajv-keywords@^3.1.0: version "3.2.0" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.2.0.tgz#e86b819c602cf8821ad637413698f1dec021847a" integrity sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo= -ajv@^4.7.0: - version "4.11.8" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" - integrity sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY= - dependencies: - co "^4.6.0" - json-stable-stringify "^1.0.1" - ajv@^5.1.0: version "5.3.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.3.0.tgz#4414ff74a50879c208ee5fdc826e32c303549eda" @@ -355,7 +414,7 @@ ajv@^5.1.0: fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.3.0" -ajv@^5.3.0: +ajv@^5.2.3, ajv@^5.3.0: version "5.5.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" integrity sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU= @@ -385,15 +444,6 @@ ajv@^6.5.3, ajv@^6.6.1: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -align-text@^0.1.1, align-text@^0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" - integrity sha1-DNkKVhCT810KmSVsIrcGlDP60Rc= - dependencies: - kind-of "^3.0.2" - longest "^1.0.1" - repeat-string "^1.5.2" - alphanum-sort@^1.0.1, alphanum-sort@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" @@ -423,11 +473,6 @@ ansi-cyan@^0.1.1: dependencies: ansi-wrap "0.1.0" -ansi-escapes@^1.1.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" - integrity sha1-06ioOzGapneTZisT52HHkRQiMG4= - ansi-escapes@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.1.0.tgz#f73207bb81207d75fd6c83f125af26eea378ca30" @@ -467,6 +512,11 @@ ansi-regex@^4.0.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.0.0.tgz#70de791edf021404c3fd615aa89118ae0432e5a9" integrity sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w== +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" @@ -757,7 +807,7 @@ async-settle@^1.0.0: dependencies: async-done "^1.2.2" -async@1.x, async@^1.4.0: +async@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= @@ -828,7 +878,7 @@ azure-storage@^2.10.2: xml2js "0.2.8" xmlbuilder "^9.0.7" -babel-code-frame@^6.16.0, babel-code-frame@^6.22.0: +babel-code-frame@^6.22.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s= @@ -920,11 +970,18 @@ binaryextensions@~1.0.0: resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-1.0.1.tgz#1e637488b35b58bda5f4774bf96a5212a8c90755" integrity sha1-HmN0iLNbWL2l9HdL+WpSEqjJB1U= -bindings@^1.2.1, bindings@^1.3.0: +bindings@^1.2.1: version "1.3.0" resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.3.0.tgz#b346f6ecf6a95f5a815c5839fc7cdb22502f1ed7" integrity sha512-DpLh5EzMR2kzvX1KIlVC0VkC3iZtHKTgdtZ0a3pglBZdaQFjt5S9g9xd1lE+YvXyfd6mtCeRnrUfOLYiTMlNSw== +bindings@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + bl@^1.0.0: version "1.2.2" resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c" @@ -992,7 +1049,7 @@ boom@5.x.x: dependencies: hoek "4.x.x" -brace-expansion@^1.0.0, brace-expansion@^1.1.7: +brace-expansion@^1.1.7: version "1.1.8" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" integrity sha1-wHshHHyVLsH479Uad+8NHTmQopI= @@ -1233,11 +1290,6 @@ camelcase-keys@^2.0.0: camelcase "^2.0.0" map-obj "^1.0.0" -camelcase@^1.0.2: - version "1.2.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" - integrity sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk= - camelcase@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" @@ -1253,6 +1305,11 @@ camelcase@^4.1.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= +camelcase@^5.0.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + caniuse-api@^1.5.2: version "1.6.1" resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.6.1.tgz#b534e7c734c4f81ec5fbe8aca2ad24354b962c6c" @@ -1278,14 +1335,6 @@ caseless@~0.12.0: resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= -center-align@^0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" - integrity sha1-qg0yYptu6XIgBBHL1EYckHvCt60= - dependencies: - align-text "^0.1.3" - lazy-cache "^1.0.3" - chainsaw@~0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/chainsaw/-/chainsaw-0.1.0.tgz#5eab50b28afe58074d0d58291388828b5e5fbc98" @@ -1302,7 +1351,7 @@ chalk@2.3.1: escape-string-regexp "^1.0.5" supports-color "^5.2.0" -chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: +chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= @@ -1340,6 +1389,11 @@ chalk@^2.3.0: escape-string-regexp "^1.0.5" supports-color "^4.0.0" +chardet@^0.4.0: + version "0.4.2" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" + integrity sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I= + chardet@^0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.5.0.tgz#fe3ac73c00c3d865ffcc02a0682e2c20b6a06029" @@ -1466,21 +1520,6 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" -clean-css@3.4.6: - version "3.4.6" - resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-3.4.6.tgz#fcb4f17057ddb7f8721616f70b07b294d95ffc45" - integrity sha1-/LTxcFfdt/hyFhb3CweylNlf/EU= - dependencies: - commander "2.8.x" - source-map "0.4.x" - -cli-cursor@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" - integrity sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc= - dependencies: - restore-cursor "^1.0.1" - cli-cursor@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" @@ -1493,15 +1532,6 @@ cli-width@^2.0.0: resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= -cliui@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" - integrity sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE= - dependencies: - center-align "^0.1.1" - right-align "^0.1.1" - wordwrap "0.0.2" - cliui@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" @@ -1520,6 +1550,15 @@ cliui@^4.0.0: strip-ansi "^4.0.0" wrap-ansi "^2.0.0" +cliui@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" + integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== + dependencies: + string-width "^3.1.0" + strip-ansi "^5.2.0" + wrap-ansi "^5.1.0" + clone-buffer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58" @@ -1635,6 +1674,11 @@ colormin@^1.0.5: css-color-names "0.0.4" has "^1.0.1" +colors@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" + integrity sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs= + colors@^1.1.2: version "1.2.1" resolved "https://registry.yarnpkg.com/colors/-/colors-1.2.1.tgz#f4a3d302976aaf042356ba1ade3b1a2c62d9d794" @@ -1686,13 +1730,6 @@ commander@2.3.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873" integrity sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM= -commander@2.8.x: - version "2.8.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" - integrity sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ= - dependencies: - graceful-readlink ">= 1.0.0" - commander@^2.12.1, commander@~2.13.0: version "2.13.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" @@ -1703,6 +1740,11 @@ commander@^2.19.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== +commander@~2.20.0: + version "2.20.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" + integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== + commandpost@^1.0.0: version "1.2.1" resolved "https://registry.yarnpkg.com/commandpost/-/commandpost-1.2.1.tgz#2e9c4c7508b9dc704afefaa91cab92ee6054cc68" @@ -1723,7 +1765,7 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -concat-stream@1.6.0, concat-stream@^1.5.2: +concat-stream@1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" integrity sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc= @@ -1850,6 +1892,11 @@ core-util-is@1.0.2, core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= +corser@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/corser/-/corser-2.0.1.tgz#8eda252ecaab5840dcd975ceb90d9370c819ff87" + integrity sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c= + coveralls@^2.11.11: version "2.13.3" resolved "https://registry.yarnpkg.com/coveralls/-/coveralls-2.13.3.tgz#9ad7c2ae527417f361e8b626483f48ee92dd2bc7" @@ -1892,7 +1939,7 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: safe-buffer "^5.0.1" sha.js "^2.4.8" -cross-spawn@^5.0.1: +cross-spawn@^5.0.1, cross-spawn@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= @@ -1901,7 +1948,7 @@ cross-spawn@^5.0.1: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^6.0.5: +cross-spawn@^6.0.0, cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== @@ -2081,7 +2128,7 @@ debug@2.2.0: dependencies: ms "0.7.1" -debug@2.6.9, debug@^2.1.1, debug@^2.1.2, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3: +debug@2.6.9, debug@^2.1.2, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -2095,14 +2142,21 @@ debug@3.1.0, debug@^3.1.0: dependencies: ms "2.0.0" -debug@^4.0.1: +debug@^3.2.6: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + +debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== dependencies: ms "^2.1.1" -decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2: +decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= @@ -2149,7 +2203,7 @@ deep-extend@~0.4.0: resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" integrity sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8= -deep-is@~0.1.2, deep-is@~0.1.3: +deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= @@ -2310,14 +2364,6 @@ dir-glob@^2.0.0: arrify "^1.0.1" path-type "^3.0.0" -doctrine@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.0.0.tgz#c73d8d2909d22291e1a007a395804da8b665fe63" - integrity sha1-xz2NKQnSIpHhoAejlYBNqLZl/mM= - dependencies: - esutils "^2.0.2" - isarray "^1.0.0" - doctrine@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" @@ -2416,14 +2462,6 @@ each-props@^1.3.0: is-plain-object "^2.0.1" object.defaults "^1.1.0" -eachr@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/eachr/-/eachr-3.2.0.tgz#2c35e43ea086516f7997cf80b7aa64d55a4a4484" - integrity sha1-LDXkPqCGUW95l8+At6pk1VpKRIQ= - dependencies: - editions "^1.1.1" - typechecker "^4.3.0" - ecc-jsbn@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" @@ -2431,10 +2469,15 @@ ecc-jsbn@~0.1.1: dependencies: jsbn "~0.1.0" -editions@^1.1.1, editions@^1.3.4: - version "1.3.4" - resolved "https://registry.yarnpkg.com/editions/-/editions-1.3.4.tgz#3662cb592347c3168eb8e498a0ff73271d67f50b" - integrity sha512-gzao+mxnYDzIysXKMQi/+M1mjy/rjestjg6OPoYTtI+3Izp23oiGZitsl9lPDPiTGXbcSIk1iJWhliSaglxnUg== +ecstatic@^3.0.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/ecstatic/-/ecstatic-3.3.1.tgz#b15b5b036c2233defc78d7bacbd8765226c95577" + integrity sha512-/rrctvxZ78HMI/tPIsqdvFKHHscxR3IJuKrZI2ZoUgkt2SiufyLFBmcco+aqQBIu6P1qBsUNG3drAAGLx80vTQ== + dependencies: + he "^1.1.1" + mime "^1.6.0" + minimist "^1.1.0" + url-join "^2.0.5" editorconfig@^0.15.0: version "0.15.0" @@ -2506,6 +2549,11 @@ elliptic@^6.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.0" +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + emojis-list@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" @@ -2573,18 +2621,6 @@ es6-iterator@^2.0.1, es6-iterator@~2.0.1: es5-ext "^0.10.35" es6-symbol "^3.1.1" -es6-map@^0.1.3: - version "0.1.5" - resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" - integrity sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA= - dependencies: - d "1" - es5-ext "~0.10.14" - es6-iterator "~2.0.1" - es6-set "~0.1.5" - es6-symbol "~3.1.1" - event-emitter "~0.3.5" - es6-promise@^4.0.3: version "4.2.4" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29" @@ -2597,18 +2633,7 @@ es6-promisify@^5.0.0: dependencies: es6-promise "^4.0.3" -es6-set@~0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" - integrity sha1-0rPsXU2ADO2BjbU40ol02wpzzLE= - dependencies: - d "1" - es5-ext "~0.10.14" - es6-iterator "~2.0.1" - es6-symbol "3.1.1" - event-emitter "~0.3.5" - -es6-symbol@3.1.1, es6-symbol@^3.1.1, es6-symbol@~3.1.1: +es6-symbol@^3.1.1, es6-symbol@~3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" integrity sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc= @@ -2641,37 +2666,11 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.3, escape-string-regexp@^ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= -escodegen@1.7.x: - version "1.7.1" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.7.1.tgz#30ecfcf66ca98dc67cd2fd162abeb6eafa8ce6fc" - integrity sha1-MOz89mypjcZ80v0WKr626vqM5vw= - dependencies: - esprima "^1.2.2" - estraverse "^1.9.1" - esutils "^2.0.2" - optionator "^0.5.0" - optionalDependencies: - source-map "~0.2.0" - -escodegen@1.8.x: - version "1.8.1" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018" - integrity sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg= - dependencies: - esprima "^2.7.1" - estraverse "^1.9.1" - esutils "^2.0.2" - optionator "^0.8.1" - optionalDependencies: - source-map "~0.2.0" - -escope@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" - integrity sha1-4Bl16BJ4GhY6ba392AOY3GTIicM= +eslint-scope@^3.7.1: + version "3.7.3" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.3.tgz#bb507200d3d17f60247636160b4826284b108535" + integrity sha512-W+B0SvF4gamyCTmUc+uITPY0989iXVfKvhwtmJocTaYoc/3khEHmEmvfY/Gn9HA9VV75jrQECsHizkNw1b68FA== dependencies: - es6-map "^0.1.3" - es6-weak-map "^2.0.1" esrecurse "^4.1.0" estraverse "^4.1.1" @@ -2693,46 +2692,49 @@ eslint-visitor-keys@^1.0.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" integrity sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ== -eslint@^3.4.0: - version "3.19.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.19.0.tgz#c8fc6201c7f40dd08941b87c085767386a679acc" - integrity sha1-yPxiAcf0DdCJQbh8CFdnOGpnmsw= +eslint@^4.18.2: + version "4.19.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.19.1.tgz#32d1d653e1d90408854bfb296f076ec7e186a300" + integrity sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ== dependencies: - babel-code-frame "^6.16.0" - chalk "^1.1.3" - concat-stream "^1.5.2" - debug "^2.1.1" - doctrine "^2.0.0" - escope "^3.6.0" - espree "^3.4.0" + ajv "^5.3.0" + babel-code-frame "^6.22.0" + chalk "^2.1.0" + concat-stream "^1.6.0" + cross-spawn "^5.1.0" + debug "^3.1.0" + doctrine "^2.1.0" + eslint-scope "^3.7.1" + eslint-visitor-keys "^1.0.0" + espree "^3.5.4" esquery "^1.0.0" - estraverse "^4.2.0" esutils "^2.0.2" file-entry-cache "^2.0.0" - glob "^7.0.3" - globals "^9.14.0" - ignore "^3.2.0" + functional-red-black-tree "^1.0.1" + glob "^7.1.2" + globals "^11.0.1" + ignore "^3.3.3" imurmurhash "^0.1.4" - inquirer "^0.12.0" - is-my-json-valid "^2.10.0" + inquirer "^3.0.6" is-resolvable "^1.0.0" - js-yaml "^3.5.1" - json-stable-stringify "^1.0.0" + js-yaml "^3.9.1" + json-stable-stringify-without-jsonify "^1.0.1" levn "^0.3.0" - lodash "^4.0.0" - mkdirp "^0.5.0" + lodash "^4.17.4" + minimatch "^3.0.2" + mkdirp "^0.5.1" natural-compare "^1.4.0" optionator "^0.8.2" - path-is-inside "^1.0.1" - pluralize "^1.2.1" - progress "^1.1.8" - require-uncached "^1.0.2" - shelljs "^0.7.5" - strip-bom "^3.0.0" + path-is-inside "^1.0.2" + pluralize "^7.0.0" + progress "^2.0.0" + regexpp "^1.0.1" + require-uncached "^1.0.3" + semver "^5.3.0" + strip-ansi "^4.0.0" strip-json-comments "~2.0.1" - table "^3.7.8" + table "4.0.2" text-table "~0.2.0" - user-home "^2.0.0" eslint@^5.0.1: version "5.13.0" @@ -2776,12 +2778,12 @@ eslint@^5.0.1: table "^5.0.2" text-table "^0.2.0" -espree@^3.4.0: - version "3.5.2" - resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.2.tgz#756ada8b979e9dcfcdb30aad8d1a9304a905e1ca" - integrity sha512-sadKeYwaR/aJ3stC2CdvgXu1T16TdYN+qwCpcWbMnGJ8s0zNWemzrvb2GbD4OhmJ/fwpJjudThAlLobGbWZbCQ== +espree@^3.5.4: + version "3.5.4" + resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7" + integrity sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A== dependencies: - acorn "^5.2.1" + acorn "^5.5.0" acorn-jsx "^3.0.0" espree@^5.0.0: @@ -2793,21 +2795,11 @@ espree@^5.0.0: acorn-jsx "^5.0.0" eslint-visitor-keys "^1.0.0" -esprima@2.5.x: - version "2.5.0" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.5.0.tgz#f387a46fd344c1b1a39baf8c20bfb43b6d0058cc" - integrity sha1-84ekb9NEwbGjm6+MIL+0O20AWMw= - -esprima@2.7.x, esprima@^2.6.0, esprima@^2.7.1: +esprima@^2.6.0: version "2.7.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" integrity sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE= -esprima@^1.2.2: - version "1.2.5" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.2.5.tgz#0993502feaf668138325756f30f9a51feeec11e9" - integrity sha1-CZNQL+r2aBODJXVvMPmlH+7sEek= - esprima@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" @@ -2835,12 +2827,7 @@ esrecurse@^4.1.0: estraverse "^4.1.0" object-assign "^4.0.1" -estraverse@^1.9.1: - version "1.9.3" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44" - integrity sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q= - -estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: +estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: version "4.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= @@ -2855,14 +2842,6 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= -event-emitter@~0.3.5: - version "0.3.5" - resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" - integrity sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk= - dependencies: - d "1" - es5-ext "~0.10.14" - event-stream@3.3.4, event-stream@^3.3.4: version "3.3.4" resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" @@ -2889,6 +2868,11 @@ event-stream@~3.3.4: stream-combiner "^0.2.2" through "^2.3.8" +eventemitter3@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7" + integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q== + events@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" @@ -2915,10 +2899,18 @@ execa@^0.7.0: signal-exit "^3.0.0" strip-eof "^1.0.0" -exit-hook@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" - integrity sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g= +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" expand-brackets@^0.1.4: version "0.1.5" @@ -2947,10 +2939,10 @@ expand-range@^1.8.1: dependencies: fill-range "^2.1.0" -expand-template@^1.0.2: - version "1.1.1" - resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-1.1.1.tgz#981f188c0c3a87d2e28f559bc541426ff94f21dd" - integrity sha512-cebqLtV8KOZfw0UI8TEFWxtczxxC1jvyUvx6H4fyp1K1FN7A4Q+uggVUlOsI1K8AGU0rwOGqP8nCapdrw8CYQg== +expand-template@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" + integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== expand-tilde@^2.0.0, expand-tilde@^2.0.2: version "2.0.2" @@ -3027,6 +3019,15 @@ extend@^3.0.2, extend@~3.0.2: resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== +external-editor@^2.0.4: + version "2.2.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" + integrity sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A== + dependencies: + chardet "^0.4.0" + iconv-lite "^0.4.17" + tmp "^0.0.33" + external-editor@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.0.0.tgz#dc35c48c6f98a30ca27a20e9687d7f3c77704bb6" @@ -3066,15 +3067,6 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" -extract-opts@^3.2.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/extract-opts/-/extract-opts-3.3.1.tgz#5abbedc98c0d5202e3278727f9192d7e086c6be1" - integrity sha1-WrvtyYwNUgLjJ4cn+Rktfghsa+E= - dependencies: - eachr "^3.2.0" - editions "^1.1.1" - typechecker "^4.3.0" - extract-zip@^1.6.5: version "1.6.6" resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.6.tgz#1290ede8d20d0872b429fd3f351ca128ec5ef85c" @@ -3124,11 +3116,6 @@ fast-json-stable-stringify@^2.0.0: resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= -fast-levenshtein@~1.0.0: - version "1.0.7" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz#0178dcdee023b92905193af0959e8a7639cfdcb9" - integrity sha1-AXjc3uAjuSkFGTrwlZ6KdjnP3Lk= - fast-levenshtein@~2.0.4: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" @@ -3146,13 +3133,12 @@ fd-slicer@~1.0.1: dependencies: pend "~1.2.0" -figures@^1.3.5: - version "1.7.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" - integrity sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4= +fd-slicer@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" + integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4= dependencies: - escape-string-regexp "^1.0.5" - object-assign "^4.1.0" + pend "~1.2.0" figures@^2.0.0: version "2.0.0" @@ -3169,19 +3155,16 @@ file-entry-cache@^2.0.0: flat-cache "^1.2.1" object-assign "^4.0.1" +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + filename-regex@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775" integrity sha1-mW4+gEebmLmJfxWopYs9CE6SZ3U= -fileset@0.2.x: - version "0.2.1" - resolved "https://registry.yarnpkg.com/fileset/-/fileset-0.2.1.tgz#588ef8973c6623b2a76df465105696b96aac8067" - integrity sha1-WI74lzxmI7KnbfRlEFaWuWqsgGc= - dependencies: - glob "5.x" - minimatch "2.x" - fill-range@^2.1.0: version "2.2.3" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" @@ -3306,6 +3289,13 @@ flush-write-stream@^1.0.0, flush-write-stream@^1.0.2: inherits "^2.0.1" readable-stream "^2.0.4" +follow-redirects@^1.0.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.7.0.tgz#489ebc198dc0e7f64167bd23b03c4c19b5784c76" + integrity sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ== + dependencies: + debug "^3.2.6" + for-in@^0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.5.tgz#007374e2b6d5c67420a1479bdb75a04872b738c4" @@ -3424,9 +3414,9 @@ fs-extra@^2.0.0: jsonfile "^2.1.0" fs-extra@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.0.tgz#8cc3f47ce07ef7b3593a11b9fb245f7e34c041d6" - integrity sha512-EglNDLRpmaTWiD/qraZn6HREAEAHJcJOmxNEYwq6xeMKnVMAy3GUcFB+wXt2C6k4CNvB/mP1y/U3dzvKKj5OtQ== + version "7.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" + integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== dependencies: graceful-fs "^4.1.2" jsonfile "^4.0.0" @@ -3512,11 +3502,6 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" -gc-signals@^0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/gc-signals/-/gc-signals-0.0.2.tgz#1cfa8a00adecaeeb93ea0dda72dad9e9f333e62f" - integrity sha512-Ghj4Co6x5bd3dvbAFuiDc6gN+BVK8ic8CBn70dXjzrtbC5hq4a+s4S6acEvftMP7LcQuHKN5v+30PGXhkCLoCQ== - generate-function@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" @@ -3534,6 +3519,11 @@ get-caller-file@^1.0.1: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" integrity sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U= +get-caller-file@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + get-stdin@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" @@ -3544,19 +3534,18 @@ get-stream@^3.0.0: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= +get-stream@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= -getmac@1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/getmac/-/getmac-1.4.1.tgz#cfefcb3ee7d7a73cba5292129cb100c19afbe17a" - integrity sha512-mQp+8D+grQX0gG8EJn6VfH0PxE56ZKNsTguOMxPShAiVk9lvH8Ey36eXepG705Ac1HCsvaSrQ/6bPHZ0++F/Mg== - dependencies: - editions "^1.3.4" - extract-opts "^3.2.0" - getpass@^0.1.1: version "0.1.7" resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" @@ -3652,7 +3641,7 @@ glob@3.2.11: inherits "2" minimatch "0.3" -glob@5.x, glob@^5.0.13, glob@^5.0.15, glob@^5.0.3: +glob@^5.0.13, glob@^5.0.3: version "5.0.15" resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" integrity sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E= @@ -3674,7 +3663,7 @@ glob@^6.0.4: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1, glob@^7.1.2: +glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1, glob@^7.1.2: version "7.1.2" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" integrity sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ== @@ -3723,16 +3712,16 @@ global-prefix@^1.0.1: is-windows "^1.0.1" which "^1.2.14" +globals@^11.0.1, globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + globals@^11.7.0: version "11.10.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.10.0.tgz#1e09776dffda5e01816b3bb4077c8b59c24eaa50" integrity sha512-0GZF1RiPKU97IHUO5TORo9w1PwrH/NBPl+fS7oMLdaTRiYmYbwK4NWoZWrAdd0/abG9R2BU+OiwyQpTpE6pdfQ== -globals@^9.14.0: - version "9.18.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" - integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ== - globby@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" @@ -3769,20 +3758,15 @@ graceful-fs@4.1.11, graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" integrity sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg= -"graceful-readlink@>= 1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" - integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU= - growl@1.9.2: version "1.9.2" resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f" integrity sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8= -gulp-atom-electron@^1.20.0: - version "1.20.0" - resolved "https://registry.yarnpkg.com/gulp-atom-electron/-/gulp-atom-electron-1.20.0.tgz#10b01f6a4c0257a8468c4da4ec9c67ecb28a32ed" - integrity sha512-gs7xvZvq8Mq60+DmbfCeXZnhqhOaJa/wrctix0RP/lCfSgusJnBTBssC6er1JIiqdHmQ8zFiYaYZh41mdG36kQ== +gulp-atom-electron@^1.21.1: + version "1.21.1" + resolved "https://registry.yarnpkg.com/gulp-atom-electron/-/gulp-atom-electron-1.21.1.tgz#4017144bf659fbbf7d0644664fcc47c64efac0f0" + integrity sha512-UHEf2pZrJD/u+AAzKCbhdPXaKrReFDa+OEJjBCAdN2SHnD+dfZqSJAz/u2OD6YR/eREuUbQOCw+VWUwex20klQ== dependencies: event-stream "3.3.4" github-releases-ms "^0.5.0" @@ -3923,14 +3907,15 @@ gulp-plumber@^1.2.0: plugin-error "^0.1.2" through2 "^2.0.3" -gulp-remote-src@^0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/gulp-remote-src/-/gulp-remote-src-0.4.4.tgz#4a4d18fac0ffedde94a7855953de90db00a1d1b1" - integrity sha512-mo7lGgZmNXyTbcUzfjSnUVkx1pnqqiwv/pPaIrYdTO77hq0WNTxXLAzQdoYOnyJ0mfVLNmNl9AGqWLiAzTPMMA== +gulp-remote-retry-src@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/gulp-remote-retry-src/-/gulp-remote-retry-src-0.6.0.tgz#fdcb5d5c9e67c31ae378a2a886ddad3d47913bb1" + integrity sha512-lFxpwwbM/GEIdYiNumxiUcPHZUROFJaF1zTBne1H8b3Pwx6Te6O9uEYp++JZPP62jdheOWcHUTBREiMkpdbm4Q== dependencies: event-stream "3.3.4" node.extend "~1.1.2" request "^2.88.0" + requestretry "^4.0.0" through2 "~2.0.3" vinyl "~2.0.1" @@ -4058,16 +4043,16 @@ gulplog@^1.0.0: dependencies: glogg "^1.0.0" -handlebars@^4.0.1: - version "4.0.11" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc" - integrity sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw= +handlebars@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.1.2.tgz#b6b37c1ced0306b221e094fc7aca3ec23b131b67" + integrity sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw== dependencies: - async "^1.4.0" + neo-async "^2.6.0" optimist "^0.6.1" - source-map "^0.4.4" + source-map "^0.6.1" optionalDependencies: - uglify-js "^2.6" + uglify-js "^3.1.4" har-schema@^2.0.0: version "2.0.0" @@ -4177,6 +4162,13 @@ has@^1.0.1: dependencies: function-bind "^1.0.2" +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + hash-base@^3.0.0: version "3.0.4" resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" @@ -4213,6 +4205,11 @@ hawk@~6.0.2: hoek "4.x.x" sntp "2.x.x" +he@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + hmac-drbg@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -4279,6 +4276,29 @@ http-proxy-agent@2.1.0, http-proxy-agent@^2.1.0: agent-base "4" debug "3.1.0" +http-proxy@^1.8.1: + version "1.17.0" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.17.0.tgz#7ad38494658f84605e2f6db4436df410f4e5be9a" + integrity sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g== + dependencies: + eventemitter3 "^3.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + +http-server@^0.11.1: + version "0.11.1" + resolved "https://registry.yarnpkg.com/http-server/-/http-server-0.11.1.tgz#2302a56a6ffef7f9abea0147d838a5e9b6b6a79b" + integrity sha512-6JeGDGoujJLmhjiRGlt8yK8Z9Kl0vnl/dQoQZlc4oeqaUoAKQg94NILLfrY3oWzSyFaQCVNTcKE5PZ3cH8VP9w== + dependencies: + colors "1.0.3" + corser "~2.0.0" + ecstatic "^3.0.0" + http-proxy "^1.8.1" + opener "~1.4.0" + optimist "0.6.x" + portfinder "^1.0.13" + union "~0.4.3" + http-signature@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" @@ -4325,20 +4345,27 @@ iconv-lite@0.4.19, iconv-lite@^0.4.19: resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" integrity sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ== -iconv-lite@0.4.23, iconv-lite@^0.4.22, iconv-lite@^0.4.4: - version "0.4.23" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" - integrity sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA== +iconv-lite@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.5.0.tgz#59cdde0a2a297cc2aeb0c6445a195ee89f127550" + integrity sha512-NnEhI9hIEKHOzJ4f697DMz9IQEXr/MMJ5w64vN2/4Ai+wRnvV7SBrL0KLoRlwaKVghOc7LQ5YkPLuX146b6Ydw== dependencies: safer-buffer ">= 2.1.2 < 3" -iconv-lite@^0.4.24: +iconv-lite@^0.4.17, iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== dependencies: safer-buffer ">= 2.1.2 < 3" +iconv-lite@^0.4.22, iconv-lite@^0.4.4: + version "0.4.23" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63" + integrity sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + ieee754@^1.1.11, ieee754@^1.1.4: version "1.1.12" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.12.tgz#50bf24e5b9c8bb98af4964c941cdb0918da7b60b" @@ -4356,12 +4383,7 @@ ignore-walk@^3.0.1: dependencies: minimatch "^3.0.4" -ignore@^3.2.0: - version "3.3.7" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.7.tgz#612289bfb3c220e186a58118618d5be8c1bab021" - integrity sha512-YGG3ejvBNHRqu0559EOxxNFihD0AjpvHlC/pdGKd3X3ofe+CoJkYazwNJYTNebqpPKN+VVQbh4ZFn1DivMNuHA== - -ignore@^3.3.5: +ignore@^3.3.3, ignore@^3.3.5: version "3.3.10" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== @@ -4432,28 +4454,29 @@ ini@^1.3.4, ini@~1.3.0: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" integrity sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4= -innosetup-compiler@^5.5.60: - version "5.5.62" - resolved "https://registry.yarnpkg.com/innosetup-compiler/-/innosetup-compiler-5.5.62.tgz#fc12cd8d17cf75a2e3833b2754a5c2bc4f26cc4e" - integrity sha1-/BLNjRfPdaLjgzsnVKXCvE8mzE4= +innosetup@5.6.1: + version "5.6.1" + resolved "https://registry.yarnpkg.com/innosetup/-/innosetup-5.6.1.tgz#6e7031ba35b23e716e4f29686bc994052e0c278c" + integrity sha512-Eit24N3JR8O0Wpuq/dMWCl2r550eiNP2124SbdbwOob43x89WPGL/SGpZG5EPHu20kV2N+4TwvHwFIM8pFUJ0g== -inquirer@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" - integrity sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34= +inquirer@^3.0.6: + version "3.3.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" + integrity sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ== dependencies: - ansi-escapes "^1.1.0" - ansi-regex "^2.0.0" - chalk "^1.0.0" - cli-cursor "^1.0.1" + ansi-escapes "^3.0.0" + chalk "^2.0.0" + cli-cursor "^2.1.0" cli-width "^2.0.0" - figures "^1.3.5" + external-editor "^2.0.4" + figures "^2.0.0" lodash "^4.3.0" - readline2 "^1.0.1" - run-async "^0.1.0" - rx-lite "^3.1.2" - string-width "^1.0.1" - strip-ansi "^3.0.0" + mute-stream "0.0.7" + run-async "^2.2.0" + rx-lite "^4.0.8" + rx-lite-aggregates "^4.0.8" + string-width "^2.1.0" + strip-ansi "^4.0.0" through "^2.3.6" inquirer@^6.0.0: @@ -4499,11 +4522,6 @@ int64-buffer@^0.1.9: resolved "https://registry.yarnpkg.com/int64-buffer/-/int64-buffer-0.1.9.tgz#9e039da043b24f78b196b283e04653ef5e990f61" integrity sha1-ngOdoEOyT3ixlrKD4EZT716ZD2E= -interpret@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.4.tgz#820cdd588b868ffb191a809506d6c9c8f212b1b0" - integrity sha1-ggzdWIuGj/sZGoCVBtbJyPISsbA= - interpret@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614" @@ -4514,6 +4532,11 @@ invert-kv@^1.0.0: resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= +invert-kv@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" + integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== + ip@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" @@ -4701,7 +4724,7 @@ is-glob@^4.0.0: dependencies: is-extglob "^2.1.1" -is-my-json-valid@^2.10.0, is-my-json-valid@^2.12.4: +is-my-json-valid@^2.12.4: version "2.16.1" resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.16.1.tgz#5a846777e2c2620d1e69104e5d3a03b1f6088f11" integrity sha512-ochPsqWS1WXj8ZnMIV0vnNXooaMhp7cyL4FMSIPKTtnV0Ha/T19G2b9kkhcNsabV9bxYkze7/aLZJb/bYuFduQ== @@ -4863,6 +4886,11 @@ is-windows@^1.0.1, is-windows@^1.0.2: resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== +is-wsl@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" + integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= + is@^3.1.0, is@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/is/-/is-3.2.1.tgz#d0ac2ad55eb7b0bec926a5266f6c662aaa83dca5" @@ -4900,45 +4928,50 @@ isstream@~0.1.2: resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= -istanbul@0.4.5: - version "0.4.5" - resolved "https://registry.yarnpkg.com/istanbul/-/istanbul-0.4.5.tgz#65c7d73d4c4da84d4f3ac310b918fb0b8033733b" - integrity sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs= - dependencies: - abbrev "1.0.x" - async "1.x" - escodegen "1.8.x" - esprima "2.7.x" - glob "^5.0.15" - handlebars "^4.0.1" - js-yaml "3.x" - mkdirp "0.5.x" - nopt "3.x" - once "1.x" - resolve "1.1.x" - supports-color "^3.1.0" - which "^1.1.1" - wordwrap "^1.0.0" - -istanbul@^0.3.17: - version "0.3.22" - resolved "https://registry.yarnpkg.com/istanbul/-/istanbul-0.3.22.tgz#3e164d85021fe19c985d1f0e7ef0c3e22d012eb6" - integrity sha1-PhZNhQIf4ZyYXR8OfvDD4i0BLrY= - dependencies: - abbrev "1.0.x" - async "1.x" - escodegen "1.7.x" - esprima "2.5.x" - fileset "0.2.x" - handlebars "^4.0.1" - js-yaml "3.x" - mkdirp "0.5.x" - nopt "3.x" - once "1.x" - resolve "1.1.x" - supports-color "^3.1.0" - which "^1.1.1" - wordwrap "^1.0.0" +istanbul-lib-coverage@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz#675f0ab69503fad4b1d849f736baaca803344f49" + integrity sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA== + +istanbul-lib-instrument@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz#a5f63d91f0bbc0c3e479ef4c5de027335ec6d630" + integrity sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA== + dependencies: + "@babel/generator" "^7.4.0" + "@babel/parser" "^7.4.3" + "@babel/template" "^7.4.0" + "@babel/traverse" "^7.4.3" + "@babel/types" "^7.4.0" + istanbul-lib-coverage "^2.0.5" + semver "^6.0.0" + +istanbul-lib-report@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz#5a8113cd746d43c4889eba36ab10e7d50c9b4f33" + integrity sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ== + dependencies: + istanbul-lib-coverage "^2.0.5" + make-dir "^2.1.0" + supports-color "^6.1.0" + +istanbul-lib-source-maps@^3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz#284997c48211752ec486253da97e3879defba8c8" + integrity sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^2.0.5" + make-dir "^2.1.0" + rimraf "^2.6.3" + source-map "^0.6.1" + +istanbul-reports@^2.2.6: + version "2.2.6" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-2.2.6.tgz#7b4f2660d82b29303a8fe6091f8ca4bf058da1af" + integrity sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA== + dependencies: + handlebars "^4.1.2" istextorbinary@1.0.2: version "1.0.2" @@ -4990,14 +5023,6 @@ js-yaml@3.6.1: argparse "^1.0.7" esprima "^2.6.0" -js-yaml@3.x, js-yaml@^3.5.1, js-yaml@^3.7.0: - version "3.10.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc" - integrity sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - js-yaml@^3.12.0: version "3.12.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.1.tgz#295c8632a18a23e054cf5c9d3cecafe678167600" @@ -5006,8 +5031,16 @@ js-yaml@^3.12.0: argparse "^1.0.7" esprima "^4.0.0" -js-yaml@~3.7.0: - version "3.7.0" +js-yaml@^3.13.0, js-yaml@^3.9.1: + version "3.13.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" + integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@~3.7.0: + version "3.7.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80" integrity sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A= dependencies: @@ -5039,6 +5072,11 @@ jsdom-no-contextify@^3.1.0: xml-name-validator "^1.0.0" xmlhttprequest ">= 1.6.0 < 2.0.0" +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + json-edm-parser@0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/json-edm-parser/-/json-edm-parser-0.1.2.tgz#1e60b0fef1bc0af67bc0d146dfdde5486cd615b4" @@ -5071,7 +5109,7 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= -json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: +json-stable-stringify@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" integrity sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8= @@ -5132,13 +5170,13 @@ just-debounce@^1.0.0: resolved "https://registry.yarnpkg.com/just-debounce/-/just-debounce-1.0.0.tgz#87fccfaeffc0b68cd19d55f6722943f929ea35ea" integrity sha1-h/zPrv/AtozRnVX2cilD+SnqNeo= -keytar@4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/keytar/-/keytar-4.2.1.tgz#8a06a6577fdf6373e0aa6b112277e63dec77fd12" - integrity sha1-igamV3/fY3PgqmsRInfmPex3/RI= +keytar@^4.11.0: + version "4.11.0" + resolved "https://registry.yarnpkg.com/keytar/-/keytar-4.11.0.tgz#891569045b287a0dabe69320e2381e059b02363f" + integrity sha512-cGn2xd4NY0yCBrU5zQ/lwIagP1UBOhUEemi6iSJU2gshN1RHkxHekSdLUji9IWNo5B1Va/iwXXWzGD2p8ziqfQ== dependencies: - nan "2.8.0" - prebuild-install "^2.4.1" + nan "2.14.0" + prebuild-install "5.3.0" kind-of@^1.1.0: version "1.1.0" @@ -5191,11 +5229,6 @@ last-run@^1.1.0: default-resolution "^2.0.0" es6-weak-map "^2.0.1" -lazy-cache@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" - integrity sha1-odePw6UEdMuAhF07O24dpJpEbo4= - lazy.js@^0.4.2: version "0.4.3" resolved "https://registry.yarnpkg.com/lazy.js/-/lazy.js-0.4.3.tgz#87f67a07ad36555121e4fff1520df31be66786d8" @@ -5215,6 +5248,13 @@ lcid@^1.0.0: dependencies: invert-kv "^1.0.0" +lcid@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" + integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA== + dependencies: + invert-kv "^2.0.0" + lcov-parse@0.0.10: version "0.0.10" resolved "https://registry.yarnpkg.com/lcov-parse/-/lcov-parse-0.0.10.tgz#1b0b8ff9ac9c7889250582b70b71315d9da6d9a3" @@ -5235,14 +5275,6 @@ levn@^0.3.0, levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" -levn@~0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.2.5.tgz#ba8d339d0ca4a610e3a3f145b9caf48807155054" - integrity sha1-uo0znQykphDjo/FFucr0iAcVUFQ= - dependencies: - prelude-ls "~1.1.0" - type-check "~0.3.1" - liftoff@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-2.5.0.tgz#2009291bb31cea861bbf10a7c15a28caf75c31ec" @@ -5365,7 +5397,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@^4.0.0, lodash@^4.13.1, lodash@^4.15.0, lodash@^4.3.0: +lodash@^4.13.1, lodash@^4.15.0, lodash@^4.3.0: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" integrity sha1-eCA6TRwyiuHYbcpkYONptX9AVa4= @@ -5400,11 +5432,6 @@ long@^3.2.0: resolved "https://registry.yarnpkg.com/long/-/long-3.2.0.tgz#d821b7138ca1cb581c172990ef14db200b5c474b" integrity sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s= -longest@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" - integrity sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc= - loud-rejection@^1.0.0: version "1.6.0" resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" @@ -5454,6 +5481,14 @@ make-dir@^1.0.0: dependencies: pify "^3.0.0" +make-dir@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== + dependencies: + pify "^4.0.1" + semver "^5.6.0" + make-error-cause@^1.1.1: version "1.2.2" resolved "https://registry.yarnpkg.com/make-error-cause/-/make-error-cause-1.2.2.tgz#df0388fcd0b37816dff0a5fb8108939777dcbc9d" @@ -5478,6 +5513,13 @@ mamacro@^0.0.3: resolved "https://registry.yarnpkg.com/mamacro/-/mamacro-0.0.3.tgz#ad2c9576197c9f1abf308d0787865bd975a3f3e4" integrity sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA== +map-age-cleaner@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" + integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w== + dependencies: + p-defer "^1.0.0" + map-cache@^0.2.0, map-cache@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" @@ -5565,6 +5607,15 @@ mem@^1.1.0: dependencies: mimic-fn "^1.0.0" +mem@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" + integrity sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w== + dependencies: + map-age-cleaner "^0.1.1" + mimic-fn "^2.0.0" + p-is-promise "^2.0.0" + memory-fs@^0.4.0, memory-fs@^0.4.1, memory-fs@~0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" @@ -5613,7 +5664,7 @@ methods@~1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= -micromatch@^2.1.5, micromatch@^2.3.7: +micromatch@^2.3.7: version "2.3.11" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" integrity sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU= @@ -5688,7 +5739,7 @@ mime@1.4.1, mime@^1.3.4: resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ== -mime@^1.4.1: +mime@^1.4.1, mime@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== @@ -5698,6 +5749,11 @@ mimic-fn@^1.0.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18" integrity sha1-5md4PZLonb00KBi1IwudYqZyrRg= +mimic-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + mimic-response@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.0.tgz#df3d3652a73fded6b9b0b24146e6fd052353458e" @@ -5728,13 +5784,6 @@ minimatch@0.3: dependencies: brace-expansion "^1.1.7" -minimatch@2.x: - version "2.0.10" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7" - integrity sha1-jQh8OcazjAAbl/ynzm0OHoCvusc= - dependencies: - brace-expansion "^1.0.0" - minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" @@ -5891,32 +5940,22 @@ mute-stdout@^1.0.0: resolved "https://registry.yarnpkg.com/mute-stdout/-/mute-stdout-1.0.1.tgz#acb0300eb4de23a7ddeec014e3e96044b3472331" integrity sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg== -mute-stream@0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" - integrity sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA= - mute-stream@0.0.7, mute-stream@~0.0.4: version "0.0.7" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= -nan@2.12.1, nan@^2.12.1: +nan@2.14.0, nan@^2.0.0, nan@^2.13.2, nan@^2.14.0: + version "2.14.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" + integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== + +nan@^2.12.1: version "2.12.1" resolved "https://registry.yarnpkg.com/nan/-/nan-2.12.1.tgz#7b1aa193e9aa86057e3c7bbd0ac448e770925552" integrity sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw== -nan@2.8.0, nan@^2.8.0: - version "2.8.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.8.0.tgz#ed715f3fe9de02b57a5e6252d90a96675e1f085a" - integrity sha1-7XFfP+neArV6XmJS2QqWZ14fCFo= - -nan@^2.10.0: - version "2.11.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.11.0.tgz#574e360e4d954ab16966ec102c0c049fd961a099" - integrity sha512-F4miItu2rGnV2ySkXOQoA8FKz/SR2Q2sWP0sbTxNxz/tuokeC8WxOhPMcwi0qIyGtVn/rrSeLbvVkznqCdwYnw== - -nan@^2.9.2, nan@~2.10.0: +nan@^2.9.2: version "2.10.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" integrity sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA== @@ -5938,15 +5977,20 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" +napi-build-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.1.tgz#1381a0f92c39d66bf19852e7873432fc2123e508" + integrity sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA== + native-is-elevated@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/native-is-elevated/-/native-is-elevated-0.2.1.tgz#70a2123a8575b9f624a3ef465d98cb74ae017385" integrity sha1-cKISOoV1ufYko+9GXZjLdK4Bc4U= -native-keymap@1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/native-keymap/-/native-keymap-1.2.5.tgz#1035a9417b9a9340cf8097763a43c76d588165a5" - integrity sha1-EDWpQXuak0DPgJd2OkPHbViBZaU= +native-keymap@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/native-keymap/-/native-keymap-2.0.0.tgz#7491ba8f9cc75bd6ada7e754dadb7716c793a3e3" + integrity sha512-KIlDZp0yKaHaGIkEVdlYN3QIaZICXwG1qh/oeBeQdM8TwAi90IAZlAD57qsNDkEvIJIzerCzb5jYYQAdHGBgYg== native-watchdog@1.0.0: version "1.0.0" @@ -5977,15 +6021,20 @@ neo-async@^2.5.0: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.5.1.tgz#acb909e327b1e87ec9ef15f41b8a269512ad41ee" integrity sha512-3KL3fvuRkZ7s4IFOMfztb7zJp3QaVWnBeGoJlgB38XnCRPj/0tLzzLG5IB8NYOHbJ8g8UGrgZv44GLDk6CxTxA== +neo-async@^2.6.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" + integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw== + nice-try@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4" integrity sha512-2NpiFHqC87y/zFke0fC0spBXL3bBsoh/p5H1EFhshxjCR5+0g2d6BiXbUFz9v1sAcxsk2htp2eQnNIci2dIYcA== -node-abi@^2.2.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.4.1.tgz#7628c4d4ec4e9cd3764ceb3652f36b2e7f8d4923" - integrity sha512-pUlswqpHQ7zGPI9lGjZ4XDNIEUDbHxsltfIRb7dTnYdhgHWHOcB0MLZKLoCz6UMcGzSPG5wGl1HODZVQAUsH6w== +node-abi@^2.7.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.9.0.tgz#ae4075b298dab2d92dd1e22c48ccc7ffd7f06200" + integrity sha512-jmEOvv0eanWjhX8dX1pmjb7oJl1U1oR4FOh0b2GnvALwSYoOdU7sj+kLDSAyjo4pfC9aj/IxkloxdLJQhSSQBA== dependencies: semver "^5.4.1" @@ -6039,26 +6088,27 @@ node-pre-gyp@^0.10.0: semver "^5.3.0" tar "^4" -node-pty@0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.8.1.tgz#94b457bec013e7a09b8d9141f63b0787fa25c23f" - integrity sha512-j+/g0Q5dR+vkELclpJpz32HcS3O/3EdPSGPvDXJZVJQLCvgG0toEbfmymxAEyQyZEpaoKHAcoL+PvKM+4N9nlw== +node-pty@0.9.0-beta19: + version "0.9.0-beta19" + resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.9.0-beta19.tgz#0fd381b2006f4665c4c2ee0509219e591842371a" + integrity sha512-MkKEvBnauGnzgXNr/oaoWQLVXm1gheIKZs4YQp8883ZiETmbEnpSvD0FU3bELcPXG5VFPRqIGsQJ4KUMBLzkPA== dependencies: - nan "2.12.1" + nan "^2.13.2" node.extend@~1.1.2: - version "1.1.6" - resolved "https://registry.yarnpkg.com/node.extend/-/node.extend-1.1.6.tgz#a7b882c82d6c93a4863a5504bd5de8ec86258b96" - integrity sha1-p7iCyC1sk6SGOlUEvV3o7IYli5Y= + version "1.1.8" + resolved "https://registry.yarnpkg.com/node.extend/-/node.extend-1.1.8.tgz#0aab3e63789f4e6d68b42bc00073ad1881243cf0" + integrity sha512-L/dvEBwyg3UowwqOUTyDsGBU6kjBQOpOhshio9V3i3BMPv5YUb9+mWNN8MK0IbWqT0AqaTSONZf0aTuMMahWgA== dependencies: - is "^3.1.0" + has "^1.0.3" + is "^3.2.1" noop-logger@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2" integrity sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI= -nopt@3.x, nopt@^3.0.1: +nopt@^3.0.1: version "3.0.6" resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k= @@ -6095,18 +6145,18 @@ normalize-path@^1.0.0: resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-1.0.0.tgz#32d0e472f91ff345701c15a8311018d3b0a90379" integrity sha1-MtDkcvkf80VwHBWoMRAY07CpA3k= -normalize-path@^2.0.0, normalize-path@^2.1.1: +normalize-path@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.0.1.tgz#47886ac1662760d4261b7d979d241709d3ce3f7a" + integrity sha1-R4hqwWYnYNQmG32XnSQXCdPOP3o= + +normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= dependencies: remove-trailing-separator "^1.0.1" -normalize-path@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.0.1.tgz#47886ac1662760d4261b7d979d241709d3ce3f7a" - integrity sha1-R4hqwWYnYNQmG32XnSQXCdPOP3o= - normalize-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" @@ -6164,6 +6214,16 @@ npmlog@^4.0.1, npmlog@^4.0.2: gauge "~2.7.3" set-blocking "~2.0.0" +nsfw@1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/nsfw/-/nsfw-1.2.5.tgz#febe581af616f7b042f89df133abe62416c4c803" + integrity sha512-m3mwZUKXiCR69PDMLfAmKmiNzy0Oe9LhFE0DYZC5cc1htNj5Hyb1sAgglXhuaDkibFy22AVvPC5cCFB3A6mYIw== + dependencies: + fs-extra "^7.0.0" + lodash.isinteger "^4.0.4" + lodash.isundefined "^3.0.1" + nan "^2.0.0" + nth-check@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.1.tgz#9929acdf628fc2c41098deab82ac580cf149aae4" @@ -6298,18 +6358,13 @@ on-finished@~2.3.0: dependencies: ee-first "1.1.1" -once@1.x, once@^1.3.0, once@^1.3.1, once@^1.3.2, once@^1.4.0: +once@^1.3.0, once@^1.3.1, once@^1.3.2, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= dependencies: wrappy "1" -onetime@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" - integrity sha1-ofeDj4MUxRbwXs78vEzP4EtO14k= - onetime@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" @@ -6317,12 +6372,29 @@ onetime@^2.0.0: dependencies: mimic-fn "^1.0.0" -oniguruma@^7.0.0: - version "7.0.2" - resolved "https://registry.yarnpkg.com/oniguruma/-/oniguruma-7.0.2.tgz#a5c922cf7066da1dbcc60f6385a90437a83f8d0b" - integrity sha512-zCsdNxTrrB4yVPMxhcIODGv1p4NVBu9WvsWnIGhMpu5djO4MQWXrC7YKjtza+OyoRqqgy27CqYWa1h5e2DDbig== +onigasm-umd@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/onigasm-umd/-/onigasm-umd-2.2.2.tgz#b989d762df61f899a3052ac794a50bd93fe20257" + integrity sha512-v2eMOJu7iE444L2iJN+U6s6s5S0y7oj/N0DAkrd6wokRtTVoq/v/yaDI1lIqFrTeJbNtqNzYvguDF5yNzW3Rvw== + +oniguruma@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/oniguruma/-/oniguruma-7.2.0.tgz#c9a59c1ea7b9fe67e237a02e02139b638856f3af" + integrity sha512-bh+ZLdykY1sdIx8jBp2zpLbVFDBc3XmKH4Ceo2lijNaN1WhEqtnpqFlmtCbRuDB17nJ58RAUStVwfW8e8uEbnA== dependencies: - nan "^2.10.0" + nan "^2.14.0" + +opener@~1.4.0: + version "1.4.3" + resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8" + integrity sha1-XG2ixdflgx6P+jlklQ+NZnSskLg= + +opn@^5.4.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc" + integrity sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA== + dependencies: + is-wsl "^1.1.0" optimist@0.3.5: version "0.3.5" @@ -6331,7 +6403,7 @@ optimist@0.3.5: dependencies: wordwrap "~0.0.2" -optimist@^0.6.1: +optimist@0.6.x, optimist@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" integrity sha1-2j6nRob6IaGaERwybpDrFaAZZoY= @@ -6339,19 +6411,7 @@ optimist@^0.6.1: minimist "~0.0.1" wordwrap "~0.0.2" -optionator@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.5.0.tgz#b75a8995a2d417df25b6e4e3862f50aa88651368" - integrity sha1-t1qJlaLUF98ltuTjhi9QqohlE2g= - dependencies: - deep-is "~0.1.2" - fast-levenshtein "~1.0.0" - levn "~0.2.5" - prelude-ls "~1.1.1" - type-check "~0.3.1" - wordwrap "~0.0.2" - -optionator@^0.8.1, optionator@^0.8.2: +optionator@^0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q= @@ -6404,6 +6464,15 @@ os-locale@^2.0.0: lcid "^1.0.0" mem "^1.1.0" +os-locale@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" + integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== + dependencies: + execa "^1.0.0" + lcid "^2.0.0" + mem "^4.0.0" + os-tmpdir@^1.0.0, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" @@ -6432,11 +6501,21 @@ p-all@^1.0.0: dependencies: p-map "^1.0.0" +p-defer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" + integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= + p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= +p-is-promise@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" + integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg== + p-limit@^1.0.0: version "1.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" @@ -6692,6 +6771,11 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= +picomatch@^2.0.4: + version "2.0.7" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.0.7.tgz#514169d8c7cd0bdbeecc8a2609e34a7163de69f6" + integrity sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA== + pify@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -6702,6 +6786,11 @@ pify@^3.0.0: resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + pinkie-promise@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" @@ -6751,10 +6840,19 @@ plugin-error@1.0.1, plugin-error@^1.0.1: arr-union "^3.1.0" extend-shallow "^3.0.2" -pluralize@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" - integrity sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU= +pluralize@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" + integrity sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow== + +portfinder@^1.0.13: + version "1.0.20" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.20.tgz#bea68632e54b2e13ab7b0c4775e9b41bf270e44a" + integrity sha512-Yxe4mTyDzTd59PZJY4ojZR8F+E5e97iq2ZOHPz3HDgSvYC5siNad2tLooQ5y5QHyQhc3xVqvyk/eNA3wuoa7Sw== + dependencies: + async "^1.5.2" + debug "^2.2.0" + mkdirp "0.5.x" posix-character-classes@^0.1.0: version "0.1.1" @@ -7001,28 +7099,29 @@ postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0 source-map "^0.5.6" supports-color "^3.2.3" -prebuild-install@^2.4.1: - version "2.5.3" - resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-2.5.3.tgz#9f65f242782d370296353710e9bc843490c19f69" - integrity sha512-/rI36cN2g7vDQnKWN8Uzupi++KjyqS9iS+/fpwG4Ea8d0Pip0PQ5bshUNzVwt+/D2MRfhVAplYMMvWLqWrCF/g== +prebuild-install@5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-5.3.0.tgz#58b4d8344e03590990931ee088dd5401b03004c8" + integrity sha512-aaLVANlj4HgZweKttFNUVNRxDukytuIuxeK2boIMHjagNJCiVKWFsKF4tCE3ql3GbrD2tExPQ7/pwtEJcHNZeg== dependencies: detect-libc "^1.0.3" - expand-template "^1.0.2" + expand-template "^2.0.3" github-from-package "0.0.0" minimist "^1.2.0" mkdirp "^0.5.1" - node-abi "^2.2.0" + napi-build-utils "^1.0.1" + node-abi "^2.7.0" noop-logger "^0.1.1" npmlog "^4.0.1" os-homedir "^1.0.1" pump "^2.0.1" - rc "^1.1.6" + rc "^1.2.7" simple-get "^2.7.0" tar-fs "^1.13.0" tunnel-agent "^0.6.0" which-pm-runs "^1.0.0" -prelude-ls@~1.1.0, prelude-ls@~1.1.1, prelude-ls@~1.1.2: +prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= @@ -7164,6 +7263,14 @@ pump@^2.0.0, pump@^2.0.1: end-of-stream "^1.1.0" once "^1.3.1" +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + pumpify@^1.3.3, pumpify@^1.3.5: version "1.5.1" resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" @@ -7198,6 +7305,11 @@ qs@6.5.1, qs@~6.5.1: resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8" integrity sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A== +qs@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/qs/-/qs-2.3.3.tgz#e9e85adbe75da0bbe4c8e0476a086290f863b404" + integrity sha1-6eha2+ddoLvkyOBHaghikPhjtAQ= + qs@~6.3.0: version "6.3.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.2.tgz#e75bd5f6e268122a2a0e0bda630b2550c166502c" @@ -7295,7 +7407,7 @@ rc@^1.1.2: minimist "^1.2.0" strip-json-comments "~2.0.1" -rc@^1.1.6, rc@^1.2.7: +rc@^1.2.7: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== @@ -7425,15 +7537,6 @@ readdirp@^2.2.1: micromatch "^3.1.10" readable-stream "^2.0.2" -readline2@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" - integrity sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU= - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - mute-stream "0.0.5" - rechoir@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" @@ -7481,22 +7584,16 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" +regexpp@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab" + integrity sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw== + regexpp@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== -remap-istanbul@^0.13.0: - version "0.13.0" - resolved "https://registry.yarnpkg.com/remap-istanbul/-/remap-istanbul-0.13.0.tgz#a529dfd080bb760f5274e3671c9c065f29923ed1" - integrity sha512-rS5ZpVAx3fGtKZkiBe1esXg5mKYbgW9iz8kkADFt3p6lo3NsBBUX1q6SwdhwUtYCGnr7nK6gRlbYK3i8R0jbRA== - dependencies: - istanbul "0.4.5" - minimatch "^3.0.4" - plugin-error "^1.0.1" - source-map "0.6.1" - through2 "3.0.0" - remove-bom-buffer@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz#c2bf1e377520d324f623892e33c10cac2c252b53" @@ -7649,6 +7746,15 @@ request@^2.86.0, request@^2.88.0: tunnel-agent "^0.6.0" uuid "^3.3.2" +requestretry@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/requestretry/-/requestretry-4.0.0.tgz#4e9e7280a7d8561bf33e9925264cf026e2be3e89" + integrity sha512-ST8m0+5FQH2FA+gbzUQyOQjUwHf22kbPQnd6TexveR0p+2UV1YYBg+Roe7BnKQ1Bb/+LtJwwm0QzxK2NA20Cug== + dependencies: + extend "^3.0.2" + lodash "^4.17.10" + when "^3.7.7" + require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -7659,7 +7765,12 @@ require-main-filename@^1.0.1: resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= -require-uncached@^1.0.2: +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + +require-uncached@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" integrity sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM= @@ -7667,6 +7778,11 @@ require-uncached@^1.0.2: caller-path "^0.1.0" resolve-from "^1.0.0" +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= + resolve-cwd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" @@ -7709,11 +7825,6 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@1.1.x: - version "1.1.7" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" - integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= - resolve@^1.1.6, resolve@^1.1.7, resolve@^1.3.2: version "1.5.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" @@ -7728,14 +7839,6 @@ resolve@^1.4.0: dependencies: path-parse "^1.0.6" -restore-cursor@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" - integrity sha1-NGYfRohjJ/7SmRR5FSJS35LapUE= - dependencies: - exit-hook "^1.0.0" - onetime "^1.0.0" - restore-cursor@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" @@ -7749,14 +7852,7 @@ ret@~0.1.10: resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== -right-align@^0.1.1: - version "0.1.3" - resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" - integrity sha1-YTObci/mo1FWiSENJOFMlhSGE+8= - dependencies: - align-text "^0.1.1" - -rimraf@2: +rimraf@2, rimraf@^2.6.3: version "2.6.3" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== @@ -7790,13 +7886,6 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^3.0.0" inherits "^2.0.1" -run-async@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" - integrity sha1-yK1KXhEGYeQCp9IbUw4AnyX444k= - dependencies: - once "^1.3.0" - run-async@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" @@ -7811,10 +7900,17 @@ run-queue@^1.0.0, run-queue@^1.0.3: dependencies: aproba "^1.1.1" -rx-lite@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" - integrity sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI= +rx-lite-aggregates@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" + integrity sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74= + dependencies: + rx-lite "*" + +rx-lite@*, rx-lite@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" + integrity sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ= rxjs@^6.1.0: version "6.2.2" @@ -7892,6 +7988,11 @@ semver-greatest-satisfied-range@^1.1.0: dependencies: sver-compat "^1.5.0" +semver-umd@^5.5.3: + version "5.5.3" + resolved "https://registry.yarnpkg.com/semver-umd/-/semver-umd-5.5.3.tgz#b64d7a2d4f5a717b369d56e31940a38e47e34d1e" + integrity sha512-HOnQrn2iKnVe/xlqCTzMXQdvSz3rPbD0DmQXYuQ+oK1dpptGFfPghonQrx5JHl2O7EJwDqtQnjhE7ME23q6ngw== + "semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.3.0: version "5.4.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" @@ -7912,6 +8013,11 @@ semver@^5.5.1, semver@^5.6.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== +semver@^6.0.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.2.0.tgz#4d813d9590aaf8a9192693d6c85b9344de5901db" + integrity sha512-jdFC1VdUGT/2Scgbimf7FSx9iJLXoqfglSF+gJeuNWVpiE37OIbc1jywR/GJyFdz3mnkz2/id0L0J/cr0izR5A== + send@0.16.1: version "0.16.1" resolved "https://registry.yarnpkg.com/send/-/send-0.16.1.tgz#a70e1ca21d1382c11d0d9f6231deb281080d7ab3" @@ -8011,15 +8117,6 @@ shebang-regex@^1.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= -shelljs@^0.7.5: - version "0.7.8" - resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.8.tgz#decbcf874b0d1e5fb72e14b164a9683048e9acb3" - integrity sha1-3svPh0sNHl+3LhSxZKloMEjprLM= - dependencies: - glob "^7.0.0" - interpret "^1.0.0" - rechoir "^0.6.2" - sigmund@^1.0.1, sigmund@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" @@ -8066,10 +8163,12 @@ slash@^1.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= -slice-ansi@0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" - integrity sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU= +slice-ansi@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" + integrity sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg== + dependencies: + is-fullwidth-code-point "^2.0.0" slice-ansi@^2.0.0: version "2.1.0" @@ -8173,43 +8272,36 @@ source-map-url@^0.4.0: resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= -source-map@0.4.x, source-map@^0.4.4: +source-map@^0.4.4: version "0.4.4" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" integrity sha1-66T12pwNyZneaAMti092FzZSA2s= dependencies: amdefine ">=0.0.4" -source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -source-map@^0.5.1, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1: +source-map@^0.5.0, source-map@^0.5.1, source-map@^0.5.3, source-map@^0.5.6: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= -source-map@~0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d" - integrity sha1-2rc/vPwrqBm03gO9b26qSBZLP50= - dependencies: - amdefine ">=0.0.4" +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== sparkles@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.0.tgz#1acbbfb592436d10bbe8f785b7cc6f82815012c3" integrity sha1-Gsu/tZJDbRC76PeFt8xvgoFQEsM= -spdlog@0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/spdlog/-/spdlog-0.8.1.tgz#dfb3f3422ab3efe32be79e4769b95440ed72699f" - integrity sha512-W0s8IOXpn86md+8PJ4mJeB/22thykzH5YaNc3Rgnql4x4/zFIhvNiEx6/a1arnqvmJF0HtRO0Ehlswg0WcwTLQ== +spdlog@^0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/spdlog/-/spdlog-0.9.0.tgz#c85dd9d0b9cd385f6f3f5b92dc9d2e1691092b5c" + integrity sha512-AeLWPCYjGi4w5DfpXFKb9pCdgMe4gFBMroGfgwXiNfzwmcNYGoFQkIuD1MChZBR1Iwrx0nGhsTSHFslt/qfTAQ== dependencies: - bindings "^1.3.0" + bindings "^1.5.0" mkdirp "^0.5.1" - nan "^2.8.0" + nan "^2.14.0" spdx-correct@~1.0.0: version "1.0.2" @@ -8390,6 +8482,15 @@ string-width@^1.0.1, string-width@^1.0.2: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" +string-width@^3.0.0, string-width@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + string_decoder@^1.0.0, string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" @@ -8442,6 +8543,13 @@ strip-ansi@^5.0.0: dependencies: ansi-regex "^4.0.0" +strip-ansi@^5.1.0, strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + strip-bom-stream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-bom-stream/-/strip-bom-stream-1.0.0.tgz#e7144398577d51a6bed0fa1994fa05f43fd988ee" @@ -8457,11 +8565,6 @@ strip-bom@^2.0.0: dependencies: is-utf8 "^0.2.0" -strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= - strip-eof@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" @@ -8479,10 +8582,10 @@ strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= -sudo-prompt@8.2.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/sudo-prompt/-/sudo-prompt-8.2.0.tgz#bcd4aaacdb367b77b4bffcce1c658c2b1dd327f3" - integrity sha512-n5Nv2lIZaWfVBg10EWC8yaJCB6xV7sEsuaISAVFIS9F4fTRjy/O35A82lkweKuSqQItDlKOGQpTHK9/udQhRRw== +sudo-prompt@9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/sudo-prompt/-/sudo-prompt-9.0.0.tgz#eebedeee9fcd6f661324e6bb46335e3288e8dc8a" + integrity sha512-kUn5fiOk0nhY2oKD9onIkcNCE4Zt85WTsvOfSmqCplmlEvXCcPOmp1npH5YWuf8Bmyy9wLWkIxx+D+8cThBORQ== sumchecker@^2.0.1: version "2.0.2" @@ -8501,7 +8604,7 @@ supports-color@^2.0.0: resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= -supports-color@^3.1.0, supports-color@^3.2.3: +supports-color@^3.2.3: version "3.2.3" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" integrity sha1-ZawFBLOVQXHYpklGsq48u4pfVPY= @@ -8529,6 +8632,13 @@ supports-color@^5.3.0, supports-color@^5.4.0: dependencies: has-flag "^3.0.0" +supports-color@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== + dependencies: + has-flag "^3.0.0" + sver-compat@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/sver-compat/-/sver-compat-1.5.0.tgz#3cf87dfeb4d07b4a3f14827bc186b3fd0c645cd8" @@ -8550,17 +8660,17 @@ svgo@^0.7.0: sax "~1.2.1" whet.extend "~0.9.9" -table@^3.7.8: - version "3.8.3" - resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" - integrity sha1-K7xULw/amGGnVdOUf+/Ys/UThV8= +table@4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36" + integrity sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA== dependencies: - ajv "^4.7.0" - ajv-keywords "^1.0.0" - chalk "^1.1.1" - lodash "^4.0.0" - slice-ansi "0.0.4" - string-width "^2.0.0" + ajv "^5.2.3" + ajv-keywords "^2.1.0" + chalk "^2.1.0" + lodash "^4.17.4" + slice-ansi "1.0.0" + string-width "^2.1.1" table@^5.0.2: version "5.2.2" @@ -8661,14 +8771,6 @@ through2@2.0.3, through2@^2.0.0, through2@^2.0.1, through2@^2.0.3, through2@~2.0 readable-stream "^2.1.5" xtend "~4.0.1" -through2@3.0.0, through2@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.0.tgz#468b461df9cd9fcc170f22ebf6852e467e578ff2" - integrity sha512-8B+sevlqP4OiCjonI1Zw03Sf8PuV1eRsYQgLad5eonILOdyeRsY27A/2Ze8IlvlMvq31OH+3fz/styI7Ya62yQ== - dependencies: - readable-stream "2 || 3" - xtend "~4.0.1" - through2@^0.6.0: version "0.6.5" resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48" @@ -8677,6 +8779,14 @@ through2@^0.6.0: readable-stream ">=1.0.33-1 <1.1.0-0" xtend ">=4.0.0 <4.1.0-0" +through2@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.0.tgz#468b461df9cd9fcc170f22ebf6852e467e578ff2" + integrity sha512-8B+sevlqP4OiCjonI1Zw03Sf8PuV1eRsYQgLad5eonILOdyeRsY27A/2Ze8IlvlMvq31OH+3fz/styI7Ya62yQ== + dependencies: + readable-stream "2 || 3" + xtend "~4.0.1" + through2@~0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/through2/-/through2-0.2.3.tgz#eb3284da4ea311b6cc8ace3653748a52abf25a3f" @@ -8756,6 +8866,11 @@ to-buffer@^1.1.0: resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + to-iso-string@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/to-iso-string/-/to-iso-string-0.0.2.tgz#4dc19e664dfccbe25bd8db508b00c6da158255d1" @@ -8825,6 +8940,11 @@ trim-newlines@^1.0.0: resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" integrity sha1-WIeWa7WCpFA6QetST301ARgVphM= +trim-right@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= + tryit@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" @@ -8851,25 +8971,26 @@ tslib@^1.8.1, tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== -tslint@^5.11.0: - version "5.11.0" - resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.11.0.tgz#98f30c02eae3cde7006201e4c33cb08b48581eed" - integrity sha1-mPMMAurjzecAYgHkwzywi0hYHu0= +tslint@^5.16.0: + version "5.16.0" + resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.16.0.tgz#ae61f9c5a98d295b9a4f4553b1b1e831c1984d67" + integrity sha512-UxG2yNxJ5pgGwmMzPMYh/CCnCnh0HfPgtlVRDs1ykZklufFBL1ZoTlWFRz2NQjcoEiDoRp+JyT0lhBbbH/obyA== dependencies: - babel-code-frame "^6.22.0" + "@babel/code-frame" "^7.0.0" builtin-modules "^1.1.1" chalk "^2.3.0" commander "^2.12.1" diff "^3.2.0" glob "^7.1.1" - js-yaml "^3.7.0" + js-yaml "^3.13.0" minimatch "^3.0.4" + mkdirp "^0.5.1" resolve "^1.3.2" semver "^5.3.0" tslib "^1.8.0" - tsutils "^2.27.2" + tsutils "^2.29.0" -tsutils@^2.27.2: +tsutils@^2.29.0: version "2.29.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99" integrity sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA== @@ -8903,7 +9024,7 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= -type-check@~0.3.1, type-check@~0.3.2: +type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= @@ -8918,13 +9039,6 @@ type-is@~1.6.15: media-typer "0.3.0" mime-types "~2.1.15" -typechecker@^4.3.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/typechecker/-/typechecker-4.5.0.tgz#c382920097812364bbaf4595b0ab6588244117a6" - integrity sha512-bqPE/ck3bVIaXP7gMKTKSHrypT32lpYTpiqzPYeYzdSQnmaGvaGhy7TnN/M/+5R+2rs/kKcp9ZLPRp/Q9Yj+4w== - dependencies: - editions "^1.3.4" - typed-rest-client@^0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/typed-rest-client/-/typed-rest-client-0.9.0.tgz#f768cc0dc3f4e950f06e04825c36b3e7834aa1f2" @@ -8946,18 +9060,10 @@ typescript-formatter@7.1.0: commandpost "^1.0.0" editorconfig "^0.15.0" -typescript-tslint-plugin@^0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/typescript-tslint-plugin/-/typescript-tslint-plugin-0.0.7.tgz#675c26a54b0156aec404abc264d0a87642151d5a" - integrity sha512-WH06dLcOjhc6fPwCUwPZKV4Dke7KvsHClZhOfa9WDnWqt08mOXx5h6o6901vakul9r82JFHWz5LSZIijXQZWLQ== - dependencies: - minimatch "^3.0.4" - vscode-languageserver "^5.1.0" - -typescript@3.4.5: - version "3.4.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.5.tgz#2d2618d10bb566572b8d7aad5180d84257d70a99" - integrity sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw== +typescript@3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.2.tgz#a09e1dc69bc9551cadf17dba10ee42cf55e5d56c" + integrity sha512-7KxJovlYhTX5RaRbUdkAXN1KUZ8PwWlTzQdHV6xNqvuFOs7+WBo10TQUqT19Q/Jz2hk5v9TQDIhyLhhJY4p5AA== typescript@^2.6.2: version "2.6.2" @@ -8985,16 +9091,6 @@ uglify-es@^3.3.4: commander "~2.13.0" source-map "~0.6.1" -uglify-js@^2.6: - version "2.8.29" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" - integrity sha1-KcVzMUgFe7Th913zW3qcty5qWd0= - dependencies: - source-map "~0.5.1" - yargs "~3.10.0" - optionalDependencies: - uglify-to-browserify "~1.0.0" - uglify-js@^3.0.5: version "3.1.9" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.1.9.tgz#dffca799308cf327ec3ac77eeacb8e196ce3b452" @@ -9003,10 +9099,13 @@ uglify-js@^3.0.5: commander "~2.11.0" source-map "~0.6.1" -uglify-to-browserify@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" - integrity sha1-bgkk1r2mta/jSeOabWMoUKD4grc= +uglify-js@^3.1.4: + version "3.6.0" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.6.0.tgz#704681345c53a8b2079fb6cec294b05ead242ff5" + integrity sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg== + dependencies: + commander "~2.20.0" + source-map "~0.6.1" uglifyjs-webpack-plugin@^1.2.4: version "1.2.7" @@ -9067,6 +9166,13 @@ union-value@^1.0.0: is-extendable "^0.1.1" set-value "^0.4.3" +union@~0.4.3: + version "0.4.6" + resolved "https://registry.yarnpkg.com/union/-/union-0.4.6.tgz#198fbdaeba254e788b0efcb630bc11f24a2959e0" + integrity sha1-GY+9rrolTniLDvy2MLwR8kopWeA= + dependencies: + qs "~2.3.3" + uniq@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" @@ -9129,6 +9235,11 @@ upath@^1.0.5, upath@^1.1.0: resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd" integrity sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw== +upath@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.2.tgz#3db658600edaeeccbe6db5e684d67ee8c2acd068" + integrity sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q== + uri-js@^4.2.1, uri-js@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" @@ -9146,6 +9257,11 @@ url-join@^1.1.0: resolved "https://registry.yarnpkg.com/url-join/-/url-join-1.1.0.tgz#741c6c2f4596c4830d6718460920d0c92202dc78" integrity sha1-dBxsL0WWxIMNZxhGCSDQySIC3Hg= +url-join@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/url-join/-/url-join-2.0.5.tgz#5af22f18c052a000a48d7b82c5e9c2e2feeda728" + integrity sha1-WvIvGMBSoACkjXuCxenC4v7tpyg= + url@^0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" @@ -9159,13 +9275,6 @@ use@^3.1.0: resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== -user-home@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" - integrity sha1-nHC/2Babwdy/SGBODwS4tJzenp8= - dependencies: - os-homedir "^1.0.0" - util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -9403,72 +9512,49 @@ vsce@1.48.0: yauzl "^2.3.1" yazl "^2.2.2" -vscode-anymatch@1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/vscode-anymatch/-/vscode-anymatch-1.3.3.tgz#0613d31a949c8025473bbdad848d219f47a44f86" - integrity sha512-LQ4vF4BWb9gwAvbMtN+3HC4HKDxLd+ZyWmAjACOdD05O/ZMcgvvnjO24GseEIQ6cWn8gW+Ft08gHFihnQy1eSw== +vscode-anymatch@3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/vscode-anymatch/-/vscode-anymatch-3.0.3.tgz#5a79101e6df7e659a1f070367bc42f190eb4ae76" + integrity sha512-qQgfbzJJ5nNShh4jjC3BBekY4d8emcxHFgnqcXwsB/PUKvJPCg7AZYXM7hqS7EDnKrX9tsIFwFMihZ7yut92Qg== dependencies: - micromatch "^2.1.5" - normalize-path "^2.0.0" + normalize-path "^3.0.0" + picomatch "^2.0.4" -vscode-chokidar@1.6.5: - version "1.6.5" - resolved "https://registry.yarnpkg.com/vscode-chokidar/-/vscode-chokidar-1.6.5.tgz#f38a1f909fa364a5429a4d4d70ecb40a15b54d0b" - integrity sha512-bc5dNF8tW2R+oesYT/Au//qumyd/0HTwSRqVXcg8ADQW1MsWKFwv+IxfSIuCHckaEy4I81GpSDaRWVGQqtsELw== +vscode-chokidar@2.1.7: + version "2.1.7" + resolved "https://registry.yarnpkg.com/vscode-chokidar/-/vscode-chokidar-2.1.7.tgz#c5b31eb87402f4779bb4170915245bdcb6f7854b" + integrity sha512-uSNEQetPjAlgIAHmcF9E6M+KCw0f842rsEnJ64aamUAV6TO7gkXNCvLSzb4MuLsPU7ZQyCa++DrLQFjvciK5dg== dependencies: - async-each "^1.0.0" - glob-parent "^2.0.0" - inherits "^2.0.1" + async-each "^1.0.1" + braces "^2.3.2" + glob-parent "^3.1.0" + inherits "^2.0.3" is-binary-path "^1.0.0" - is-glob "^2.0.0" + is-glob "^4.0.0" + normalize-path "^3.0.0" path-is-absolute "^1.0.0" - readdirp "^2.0.0" - vscode-anymatch "1.3.3" + readdirp "^2.2.1" + upath "^1.1.1" + vscode-anymatch "3.0.3" optionalDependencies: - vscode-fsevents "0.3.10" - -vscode-debugprotocol@1.34.0: - version "1.34.0" - resolved "https://registry.yarnpkg.com/vscode-debugprotocol/-/vscode-debugprotocol-1.34.0.tgz#aef63274166ccbc6d1d68e68c7d7f6d013802f08" - integrity sha512-tcMThtgk9TUtE8zzAIwPvHZfgnEYnVa7cI3YaQk/o54Q9cme+TLd/ao60a6ycj5rCrI/B5r/mAfeK5EKSItm7g== - -vscode-fsevents@0.3.10: - version "0.3.10" - resolved "https://registry.yarnpkg.com/vscode-fsevents/-/vscode-fsevents-0.3.10.tgz#65a586c3c6df3080bea20482146963a0f3a2c58d" - integrity sha512-iNlCKNgEB9A2JZkLf4h4sJlOS1u0lbe4QjM0Dr0PHaTmsttkJEfOaQeci2Ja1wUA7hUUAF6sNbei/Qp2DacFLw== - dependencies: - nan "^2.10.0" - -vscode-jsonrpc@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-4.0.0.tgz#a7bf74ef3254d0a0c272fab15c82128e378b3be9" - integrity sha512-perEnXQdQOJMTDFNv+UF3h1Y0z4iSiaN9jIlb0OqIYgosPCZGYh/MCUlkFtV2668PL69lRDO32hmvL2yiidUYg== - -vscode-languageserver-protocol@3.13.0: - version "3.13.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.13.0.tgz#710d8e42119bb3affb1416e1e104bd6b4d503595" - integrity sha512-2ZGKwI+P2ovQll2PGAp+2UfJH+FK9eait86VBUdkPd9HRlm8e58aYT9pV/NYanHOcp3pL6x2yTLVCFMcTer0mg== - dependencies: - vscode-jsonrpc "^4.0.0" - vscode-languageserver-types "3.13.0" + vscode-fsevents "1.2.12" -vscode-languageserver-types@3.13.0: - version "3.13.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.13.0.tgz#b704b024cef059f7b326611c99b9c8753c0a18b4" - integrity sha512-BnJIxS+5+8UWiNKCP7W3g9FlE7fErFw0ofP5BXJe7c2tl0VeWh+nNHFbwAS2vmVC4a5kYxHBjRy0UeOtziemVA== +vscode-debugprotocol@1.35.0: + version "1.35.0" + resolved "https://registry.yarnpkg.com/vscode-debugprotocol/-/vscode-debugprotocol-1.35.0.tgz#565140cd42945e30c6c85cafb38c631457d4a46c" + integrity sha512-+OMm11R1bGYbpIJ5eQIkwoDGFF4GvBz3Ztl6/VM+/RNNb2Gjk2c0Ku+oMmfhlTmTlPCpgHBsH4JqVCbUYhu5bA== -vscode-languageserver@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver/-/vscode-languageserver-5.1.0.tgz#012a28f154cc7a848c443d217894942e4c3eeb39" - integrity sha512-CIsrgx2Y5VHS317g/HwkSTWYBIQmy0DwEyZPmB2pEpVOhYFwVsYpbiJwHIIyLQsQtmRaO4eA2xM8KPjNSdXpBw== +vscode-fsevents@1.2.12: + version "1.2.12" + resolved "https://registry.yarnpkg.com/vscode-fsevents/-/vscode-fsevents-1.2.12.tgz#01a71a01f90ee95ca822c34427aba437a17c03a7" + integrity sha512-bH/jRdDpSesGpqiVLjp6gHLSKUOh7oNvppzZ17JIrdbRYCcDmV7dIWR5gQc27DFy0RD9JDT+t+ixMid94MkM1A== dependencies: - vscode-languageserver-protocol "3.13.0" - vscode-uri "^1.0.6" + nan "^2.14.0" -vscode-nls-dev@3.2.5: - version "3.2.5" - resolved "https://registry.yarnpkg.com/vscode-nls-dev/-/vscode-nls-dev-3.2.5.tgz#bea2b6e0cae709c48144180585e1a511edc9fb8d" - integrity sha512-eiNkwDHgTjP1h23BCOmAlXbFVembGokALYIvID5LMBzYppOiJzN/rGatHBlThQl6lnHWv599UEre6/AbjioYYw== +vscode-nls-dev@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/vscode-nls-dev/-/vscode-nls-dev-3.3.1.tgz#15fc03e0c9ca5a150abb838690d9554ac06f77e4" + integrity sha512-fug18D7CXb8pv8JoQ0D0JmZaIYDQoKLiyZxkAy5P8Cln/FwlNsdzwQILDph62EdGY5pvsJ2Jd1T5qgHAExe/tg== dependencies: ansi-colors "^3.2.3" clone "^2.1.1" @@ -9481,17 +9567,7 @@ vscode-nls-dev@3.2.5: typescript "^2.6.2" vinyl "^2.1.0" xml2js "^0.4.19" - yargs "^10.1.1" - -vscode-nsfw@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/vscode-nsfw/-/vscode-nsfw-1.1.1.tgz#7c3febe153677c5850b197a0b64a197cd11e95c7" - integrity sha512-Wg3vzN1U3T6P1uE13LdVVRIhdy7XWnWkwmAXhkLsIkH2QY0E/pvNDRLrwAMMW6GC1Fvvbxm3hzdIrCmr7Hq3FA== - dependencies: - fs-extra "^7.0.0" - lodash.isinteger "^4.0.4" - lodash.isundefined "^3.0.1" - nan "^2.10.0" + yargs "^13.2.4" vscode-proxy-agent@0.4.0: version "0.4.0" @@ -9503,29 +9579,24 @@ vscode-proxy-agent@0.4.0: https-proxy-agent "2.2.1" socks-proxy-agent "4.0.1" -vscode-ripgrep@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.2.5.tgz#2093c8f36d52bd2dab9eb45b003dd02533c5499c" - integrity sha512-n5XBm9od5hahpljw9T8wbkuMnAY7LlAG1OyEEtcCZEX9aCHFuBKSP0IcvciGRTbtWRovNuT83A2iRjt6PL3bLg== +vscode-ripgrep@^1.5.5: + version "1.5.5" + resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.5.tgz#24c0e9cb356cf889c98e15ecb58f9cf654a1d961" + integrity sha512-OrPrAmcun4+uZAuNcQvE6CCPskh+5AsjANod/Q3zRcJcGNxgoOSGlQN9RPtatkUNmkN8Nn8mZBnS1jMylu/dKg== -vscode-sqlite3@4.0.7: - version "4.0.7" - resolved "https://registry.yarnpkg.com/vscode-sqlite3/-/vscode-sqlite3-4.0.7.tgz#7adbf0fe411c87716ca3c4e467f04de3a7353125" - integrity sha512-1BqWdf6Nzs+q7JC+JFXDLX2Z8ZID7lZH69AoLh9FXos7XgLbF4dsmUZO5a6d9X3Jccu/m0PfKK1K4E6dk/xiRg== +vscode-sqlite3@4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/vscode-sqlite3/-/vscode-sqlite3-4.0.8.tgz#1eba415b996d2661628d80d4a191a20767713829" + integrity sha512-FsFtYSHmy0mYjtt9ibFKsJqbRzqaltDKZ5SLdpykjvORugFMr0HfGunkh+qGaz9CvAiqjM2KVO91NE9KdyTWKQ== dependencies: - nan "~2.10.0" + nan "^2.14.0" -vscode-textmate@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-4.0.1.tgz#6c36f28e9059ce12bc34907f7a33ea43166b26a8" - integrity sha512-gHTXTj04TUgbjB8y7pkVwxOiuCuD6aU5gnFzIByQuqdgFpe/bJaaEIS4geGjbjWbd1XJh6zG1EthLfpNaXEqUw== +vscode-textmate@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-4.2.2.tgz#0b4dabc69a6fba79a065cb6b615f66eac07c8f4c" + integrity sha512-1U4ih0E/KP1zNK/EbpUqyYtI7PY+Ccd2nDGTtiMR/UalLFnmaYkwoWhN1oI7B91ptBN8NdVwWuvyUnvJAulCUw== dependencies: - oniguruma "^7.0.0" - -vscode-uri@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-1.0.6.tgz#6b8f141b0bbc44ad7b07e94f82f168ac7608ad4d" - integrity sha512-sLI2L0uGov3wKVb9EB+vIQBl9tVP90nqRvxSoJ35vI3NjxE8jfsE5DSOhWgSunHSZmKS4OCi2jrtfxK7uyp2ww== + oniguruma "^7.2.0" vscode-windows-ca-certs@0.1.0: version "0.1.0" @@ -9541,11 +9612,6 @@ vscode-windows-registry@1.0.1: dependencies: nan "^2.12.1" -vscode-xterm@3.13.0-beta3: - version "3.13.0-beta3" - resolved "https://registry.yarnpkg.com/vscode-xterm/-/vscode-xterm-3.13.0-beta3.tgz#ab642ed77df07c2adfca7b15ae39c18328db3fc6" - integrity sha512-XvgD/P6CCV0+79UYM7CEL6Ziv2RiDopI3Wa1hIm3Dm8InWxkl3QwykINlempMNub+r0gwVwLKSQYr+Q/jg1IAw== - vso-node-api@6.1.2-preview: version "6.1.2-preview" resolved "https://registry.yarnpkg.com/vso-node-api/-/vso-node-api-6.1.2-preview.tgz#aab3546df2451ecd894e071bb99b5df19c5fa78f" @@ -9636,6 +9702,11 @@ webpack@^4.16.5, webpack@^4.7.0: watchpack "^1.5.0" webpack-sources "^1.0.1" +when@^3.7.7: + version "3.7.8" + resolved "https://registry.yarnpkg.com/when/-/when-3.7.8.tgz#c7130b6a7ea04693e842cdc9e7a1f2aa39a39f82" + integrity sha1-xxMLan6gRpPoQs3J56Hyqjmjn4I= + whet.extend@~0.9.9: version "0.9.9" resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1" @@ -9656,13 +9727,6 @@ which-pm-runs@^1.0.0: resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs= -which@^1.1.1, which@^1.2.9: - version "1.3.0" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" - integrity sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg== - dependencies: - isexe "^2.0.0" - which@^1.2.14: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" @@ -9670,6 +9734,13 @@ which@^1.2.14: dependencies: isexe "^2.0.0" +which@^1.2.9: + version "1.3.0" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" + integrity sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg== + dependencies: + isexe "^2.0.0" + wide-align@^1.1.0: version "1.1.3" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" @@ -9677,46 +9748,36 @@ wide-align@^1.1.0: dependencies: string-width "^1.0.2 || 2" -window-size@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" - integrity sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0= - -windows-foreground-love@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/windows-foreground-love/-/windows-foreground-love-0.1.0.tgz#948e4beac0733cd58624710cc09432b7e8bf3521" - integrity sha1-lI5L6sBzPNWGJHEMwJQyt+i/NSE= +windows-foreground-love@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/windows-foreground-love/-/windows-foreground-love-0.2.0.tgz#b291832d8a02a966bc046ba0e498cc789809076b" + integrity sha512-72ZDshnt8Q3/ImLMt4wxsY8eVnUd1KDb5QfvZX09AxJJJa0hGdyzPfd/ms0pKSYYwKlEhB1ri+WDKNvdIpJknQ== -windows-mutex@0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/windows-mutex/-/windows-mutex-0.2.1.tgz#05a8da8018f22874d7fbbd775c0141876d1c28fc" - integrity sha512-TaLGQa+qBcPZ2EH94BD/3Hy8fycrZjzqxI/lOMdXPyvffNnIJOvKwEyvNRC25bVFQ2mliJBziKhCMEhk9Dhhhg== +windows-mutex@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/windows-mutex/-/windows-mutex-0.3.0.tgz#2f51a0c97b3979c98952b23c086035f1f3715fab" + integrity sha512-IDWzyHOEpQr7m590pT90jMbCYNe525d7BgP6F80TjispEu2gWMvTIoSuO6Sy4atIEhvs3ys7DVlKdLzIAyRviQ== dependencies: bindings "^1.2.1" - nan "^2.10.0" + nan "^2.14.0" -windows-process-tree@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/windows-process-tree/-/windows-process-tree-0.2.3.tgz#6b781f0a320e8a0d6434c9399add4389c709cf6e" - integrity sha512-SzPJSubVVsToz1g5lr2P+4mQT70gvJ9u/nlnpfkOeQcAhOuhKz5DiO1TARgR0OnVsv21LPzxbA2m/4JQkGh1wA== +windows-process-tree@0.2.4: + version "0.2.4" + resolved "https://registry.yarnpkg.com/windows-process-tree/-/windows-process-tree-0.2.4.tgz#747af587b54cc6c996f2be0836cc8a8fd0dc038f" + integrity sha512-9gag9AHm3Iin/4YC1EwoIfZlqW/rG2eV7rJZ4Fy5NnAMGdewmnwsie5Rz+CJo2vSolqzzfw7hPeu3oOdniNejg== dependencies: - nan "^2.10.0" - -wordwrap@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" - integrity sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8= - -wordwrap@^1.0.0, wordwrap@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= + nan "^2.13.2" wordwrap@~0.0.2: version "0.0.3" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= +wordwrap@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= + worker-farm@^1.5.2: version "1.6.0" resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.6.0.tgz#aecc405976fab5a95526180846f0dba288f3a4a0" @@ -9732,6 +9793,15 @@ wrap-ansi@^2.0.0: string-width "^1.0.1" strip-ansi "^3.0.1" +wrap-ansi@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" + integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== + dependencies: + ansi-styles "^3.2.0" + string-width "^3.0.0" + strip-ansi "^5.0.0" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -9815,6 +9885,21 @@ xtend@~2.1.1: dependencies: object-keys "~0.4.0" +xterm-addon-search@0.2.0-beta3: + version "0.2.0-beta3" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.2.0-beta3.tgz#710ce14658e269c5a4791f5a9e2f520883a2e62b" + integrity sha512-KzVdkEtGbKJe9ER2TmrI7XjF/wUq1lir9U63vPJi0t2ymQvIECl1V63f9QtOp1vvpdhbZiXBxO+vGTj+y0tRow== + +xterm-addon-web-links@0.1.0-beta10: + version "0.1.0-beta10" + resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.1.0-beta10.tgz#610fa9773a2a5ccd41c1c83ba0e2dd2c9eb66a23" + integrity sha512-xfpjy0V6bB4BR44qIgZQPoCMVakxb65gMscPkHpO//QxvUxKzabV3dxOsIbeZRFkUGsWTFlvz2OoaBLoNtv5gg== + +xterm@3.15.0-beta89: + version "3.15.0-beta89" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta89.tgz#255962e2595deefb42b8c0043001256526163a3f" + integrity sha512-rNaoUamacPRg+ejbKDGRDNqR3SZ3Uf/pUW0mO+FF25/lIgdLq8x7RgZVBgFweCZ/dijPjxoyMcgfNDTH9h8LOg== + y18n@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" @@ -9842,6 +9927,14 @@ yargs-parser@^10.1.0: dependencies: camelcase "^4.1.0" +yargs-parser@^13.1.0: + version "13.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0" + integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + yargs-parser@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a" @@ -9849,31 +9942,6 @@ yargs-parser@^5.0.0: dependencies: camelcase "^3.0.0" -yargs-parser@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-8.1.0.tgz#f1376a33b6629a5d063782944da732631e966950" - integrity sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ== - dependencies: - camelcase "^4.1.0" - -yargs@^10.1.1: - version "10.1.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-10.1.2.tgz#454d074c2b16a51a43e2fb7807e4f9de69ccb5c5" - integrity sha512-ivSoxqBGYOqQVruxD35+EyCFDYNEFL/Uo6FcOnz+9xZdZzK0Zzw4r4KhbrME1Oo2gOggwJod2MnsdamSG7H9ig== - dependencies: - cliui "^4.0.0" - decamelize "^1.1.1" - find-up "^2.1.0" - get-caller-file "^1.0.1" - os-locale "^2.0.0" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^2.0.0" - which-module "^2.0.0" - y18n "^3.2.1" - yargs-parser "^8.1.0" - yargs@^12.0.1: version "12.0.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.1.tgz#6432e56123bb4e7c3562115401e98374060261c2" @@ -9892,6 +9960,23 @@ yargs@^12.0.1: y18n "^3.2.1 || ^4.0.0" yargs-parser "^10.1.0" +yargs@^13.2.4: + version "13.2.4" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.2.4.tgz#0b562b794016eb9651b98bd37acf364aa5d6dc83" + integrity sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg== + dependencies: + cliui "^5.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + os-locale "^3.1.0" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^13.1.0" + yargs@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8" @@ -9911,16 +9996,6 @@ yargs@^7.1.0: y18n "^3.2.1" yargs-parser "^5.0.0" -yargs@~3.10.0: - version "3.10.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" - integrity sha1-9+572FfdfB0tOMDnTvvWgdFDH9E= - dependencies: - camelcase "^1.0.2" - cliui "^2.1.0" - decamelize "^1.0.0" - window-size "0.1.0" - yauzl@2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" @@ -9928,7 +10003,7 @@ yauzl@2.4.1: dependencies: fd-slicer "~1.0.1" -yauzl@^2.2.1, yauzl@^2.3.1, yauzl@^2.9.1: +yauzl@^2.2.1, yauzl@^2.3.1: version "2.9.1" resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.9.1.tgz#a81981ea70a57946133883f029c5821a89359a7f" integrity sha1-qBmB6nCleUYTOIPwKcWCGok1mn8= @@ -9936,6 +10011,14 @@ yauzl@^2.2.1, yauzl@^2.3.1, yauzl@^2.9.1: buffer-crc32 "~0.2.3" fd-slicer "~1.0.1" +yauzl@^2.9.2: + version "2.10.0" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" + integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk= + dependencies: + buffer-crc32 "~0.2.3" + fd-slicer "~1.1.0" + yazl@^2.2.1, yazl@^2.2.2, yazl@^2.4.3: version "2.4.3" resolved "https://registry.yarnpkg.com/yazl/-/yazl-2.4.3.tgz#ec26e5cc87d5601b9df8432dbdd3cd2e5173a071"